| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #include "config.h"
- #if !defined(HAVE_PTY_H) && defined(HAVE__DEV_PTMX) && !defined(HAVE_FORKPTY)
- /*
- * Substitute for the nonstandard BSD/GNU extension 'forkpty' using
- * SysV STREAMS (the /dev/ptmx pseudoterminal multiplexer).
- *
- * dgc@uchicago.edu
- */
- #ifdef HAVE_SYS_IOCTL_H
- #include <sys/ioctl.h>
- #endif
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <limits.h> /* PATH_MAX */
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/termios.h>
- #include <stropts.h>
- #define DEV_PTMX "/dev/ptmx"
- enum
- {
- EPTMX_OK = 0,
- EPTMX_OPEN,
- EPTMX_GRANT,
- EPTMX_UNLOCK,
- EPTMX_NAME,
- EPTMX_FIND,
- EPTMX_PUSH_PTEM,
- EPTMX_PUSH_LDTERM,
- EPTMX_PUSH_TTCOMPAT,
- EPTMX_END
- } ptmx_errs;
- int open_master(char *name, int sz)
- {
- char *sname;
- int fd;
- strncpy(name, DEV_PTMX, sz);
- name[sz-1] = '\0';
- fd = open(name, O_RDWR);
- if (fd < 0)
- return EPTMX_OPEN;
- if (grantpt(fd) < 0)
- {
- close(fd);
- return EPTMX_GRANT;
- }
- if (unlockpt(fd) < 0)
- {
- close(fd);
- return EPTMX_UNLOCK;
- }
- sname = ptsname(fd);
- if (sname == NULL)
- {
- close(fd);
- return EPTMX_NAME;
- }
- strncpy(name, sname, sz);
- name[sz-1] = '\0';
- return fd;
- }
- int open_slave(char *name)
- {
- int fd;
- int status;
- fd = open(name, O_RDWR);
- if (fd < 0)
- return EPTMX_OPEN;
- status = ioctl(fd, I_FIND, "ldterm");
- if (status < 0)
- {
- close(fd);
- return EPTMX_FIND;
- }
- if (status > 0)
- return fd;
- if (ioctl(fd, I_PUSH, "ptem") < 0)
- {
- close(fd);
- return EPTMX_PUSH_PTEM;
- }
- if (ioctl(fd, I_PUSH, "ldterm") < 0)
- {
- close(fd);
- return EPTMX_PUSH_LDTERM;
- }
- if (ioctl(fd, I_PUSH, "ttcompat") < 0)
- {
- close(fd);
- return EPTMX_PUSH_TTCOMPAT;
- }
- return fd;
- }
- int login_tty(int fd)
- {
- setsid();
- if (ioctl(fd, TIOCSCTTY, NULL) == -1)
- return -1;
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- if (fd > 2)
- close(fd);
- return 0;
- }
- pid_t forkpty(int *masterp, char *name, struct termios *termp, struct winsize *winp)
- {
- int master, slave;
- char ptname[PATH_MAX];
- pid_t pid;
- master = open_master(ptname, sizeof(ptname));
- if (master < 0)
- {
- return -1;
- }
- slave = open_slave(ptname);
- if (slave < 0)
- {
- close(master);
- return -1;
- }
- if (name)
- strcpy(name, ptname);
- if (termp)
- tcsetattr(slave, TCSAFLUSH, termp);
- if (winp)
- ioctl(slave, TIOCSWINSZ, winp);
- pid = fork();
- if (pid < 0)
- {
- close(slave);
- close(master);
- return -1;
- }
- else if (pid == 0)
- {
- /* child/slave */
- close(master);
- login_tty(slave);
- return 0;
- }
- /* parent/master */
- *masterp = master;
- close(slave);
- return pid;
- }
- #endif
|