#include #include #include #include #include #include #include /* Open a pseudo-terminal. */ static int openpty (int *amaster, int *aslave, char *name, struct termios const *termp, struct winsize const *winp) { int master; char *slave_name; int slave; master = open ("/dev/ptc", O_RDWR | O_NOCTTY); if (master < 0) return -1; if (grantpt (master)) goto fail; if (unlockpt (master)) goto fail; slave_name = ptsname (master); if (slave_name == NULL) goto fail; slave = open (slave_name, O_RDWR | O_NOCTTY); if (slave == -1) goto fail; /* XXX Should we ignore errors here? */ if (termp) tcsetattr (slave, TCSAFLUSH, termp); if (winp) ioctl (slave, TIOCSWINSZ, winp); *amaster = master; *aslave = slave; if (name != NULL) strcpy (name, slave_name); return 0; fail: close (master); return -1; } /* Assign a given terminal as controlling terminal and as standard input, standard output, standard error of the current process. */ static int login_tty (int slave_fd) { int i; /* Create a new session. */ setsid (); /* Make fd the controlling terminal for the current process. On Solaris: A terminal becomes the controlling terminal of a session if it is being open()ed, at a moment when 1. it is not already the controlling terminal of some session, and 2. the process that open()s it is a session leader that does not have a controlling terminal. We assume condition 1, try to ensure condition 2, and then open() it. */ for (i = 0; i < 3; i++) if (i != slave_fd) close (i); char *slave_name; int dummy_fd; slave_name = ttyname (slave_fd); if (slave_name == NULL) return -1; dummy_fd = open (slave_name, O_RDWR); if (dummy_fd < 0) return -1; close (dummy_fd); /* Assign fd to the standard input, standard output, and standard error of the current process. */ for (i = 0; i < 3; i++) if (slave_fd != i) while (dup2 (slave_fd, i) == -1 && errno == EBUSY); // if (dup2 (slave_fd, i) < 0) // return -1; if (slave_fd >= 3) close (slave_fd); return 0; } /* Fork a child process attached to the slave of a pseudo-terminal. */ int forkpty (int *amaster, char *name, const struct termios *termp, const struct winsize *winp) { int master, slave, pid; if (openpty (&master, &slave, name, termp, winp) == -1) return -1; switch (pid = fork ()) { case -1: close (master); close (slave); return -1; case 0: /* Child. */ close (master); if (login_tty (slave)) _exit (1); return 0; default: /* Parent. */ *amaster = master; close (slave); // sleep(1); return pid; } }