mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-15 05:29:10 +08:00
118 lines
4.3 KiB
C
118 lines
4.3 KiB
C
/*************************************************************************\
|
|
* Copyright (C) Michael Kerrisk, 2018. *
|
|
* *
|
|
* This program is free software. You may use, modify, and redistribute it *
|
|
* under the terms of the GNU Lesser General Public License as published *
|
|
* by the Free Software Foundation, either version 3 or (at your option) *
|
|
* any later version. This program is distributed without any warranty. *
|
|
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
|
\*************************************************************************/
|
|
|
|
/* Listing 64-2 */
|
|
|
|
/* pty_fork.c
|
|
|
|
Implements ptyFork(), a function that creates a child process connected to
|
|
the parent (i.e., the calling process) via a pseudoterminal (pty). The child
|
|
is placed in a new session, with the pty slave as its controlling terminal,
|
|
and its standard input, output, and error connected to the pty slave.
|
|
|
|
In the parent, 'masterFd' is used to return the file descriptor for the
|
|
pty master.
|
|
|
|
If 'slaveName' is non-NULL, then it is used to return the name of the pty
|
|
slave. If 'slaveName' is not NULL, then 'snLen' should be set to indicate
|
|
the size of the buffer pointed to by 'slaveName'.
|
|
|
|
If 'slaveTermios' and 'slaveWS' are non-NULL, then they are used respectively
|
|
to set the terminal attributes and window size of the pty slave.
|
|
|
|
Returns:
|
|
in child: 0
|
|
in parent: PID of child or -1 on error
|
|
*/
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
#include <sys/ioctl.h>
|
|
#include "pty_master_open.h"
|
|
#include "pty_fork.h" /* Declares ptyFork() */
|
|
#include "af_unix_hdr.h"
|
|
|
|
#define MAX_SNAME 1000 /* Maximum size for pty slave name */
|
|
|
|
pid_t
|
|
ptyFork(int *masterFd, char *slaveName, size_t snLen,
|
|
const struct termios *slaveTermios, const struct winsize *slaveWS)
|
|
{
|
|
int mfd, slaveFd, savedErrno;
|
|
pid_t childPid;
|
|
char slname[MAX_SNAME];
|
|
|
|
mfd = ptyMasterOpen(slname, MAX_SNAME);
|
|
if (mfd == -1)
|
|
return -1;
|
|
|
|
if (slaveName != NULL) { /* Return slave name to caller */
|
|
if (strlen(slname) < snLen) {
|
|
strncpy(slaveName, slname, snLen);
|
|
|
|
} else { /* 'slaveName' was too small */
|
|
close(mfd);
|
|
errno = EOVERFLOW;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
childPid = fork();
|
|
|
|
if (childPid == -1) { /* fork() failed */
|
|
savedErrno = errno; /* close() might change 'errno' */
|
|
close(mfd); /* Don't leak file descriptors */
|
|
errno = savedErrno;
|
|
return -1;
|
|
}
|
|
|
|
if (childPid != 0) { /* Parent */
|
|
*masterFd = mfd; /* Only parent gets master fd */
|
|
return childPid; /* Like parent of fork() */
|
|
}
|
|
|
|
/* Child falls through to here */
|
|
|
|
if (setsid() == -1) /* Start a new session */
|
|
err_exit("ptyFork:setsid");
|
|
|
|
close(mfd); /* Not needed in child */
|
|
|
|
slaveFd = open(slname, O_RDWR); /* Becomes controlling tty */
|
|
if (slaveFd == -1)
|
|
err_exit("ptyFork:open-slave");
|
|
|
|
/* #ifdef TIOCSCTTY /\* Acquire controlling tty on BSD *\/ */
|
|
/* if (ioctl(slaveFd, TIOCSCTTY, 0) == -1) */
|
|
/* err_exit("ptyFork:ioctl-TIOCSCTTY"); */
|
|
/* #endif */
|
|
|
|
if (slaveTermios != NULL) /* Set slave tty attributes */
|
|
if (tcsetattr(slaveFd, TCSANOW, slaveTermios) == -1)
|
|
err_exit("ptyFork:tcsetattr");
|
|
|
|
if (slaveWS != NULL) /* Set slave tty window size */
|
|
if (ioctl(slaveFd, TIOCSWINSZ, slaveWS) == -1)
|
|
err_exit("ptyFork:ioctl-TIOCSWINSZ");
|
|
|
|
/* Duplicate pty slave to be child's stdin, stdout, and stderr */
|
|
|
|
if (dup2(slaveFd, STDIN_FILENO) != STDIN_FILENO)
|
|
err_exit("ptyFork:dup2-STDIN_FILENO");
|
|
if (dup2(slaveFd, STDOUT_FILENO) != STDOUT_FILENO)
|
|
err_exit("ptyFork:dup2-STDOUT_FILENO");
|
|
if (dup2(slaveFd, STDERR_FILENO) != STDERR_FILENO)
|
|
err_exit("ptyFork:dup2-STDERR_FILENO");
|
|
|
|
if (slaveFd > STDERR_FILENO) /* Safety check */
|
|
close(slaveFd); /* No longer need this fd */
|
|
|
|
return 0; /* Like child of fork() */
|
|
}
|