2 * pty.c - pseudo-terminal handling
16 #include <sys/ioctl.h>
17 #include <sys/types.h>
23 static char ptyname[FILENAME_MAX];
26 void pty_preinit(void)
31 master = open("/dev/ptmx", O_RDWR);
33 perror("/dev/ptmx: open");
37 if (grantpt(master) < 0) {
42 if (unlockpt(master) < 0) {
48 void pty_resize(int w, int h)
56 sz.ws_xpixel = sz.ws_ypixel = 0;
57 ioctl(master, TIOCSWINSZ, &sz);
60 int run_program_in_pty(const struct shell_data *shdata,
61 char *directory, char **program_args)
64 char *fallback_args[2];
68 ptyname[FILENAME_MAX-1] = '\0';
69 strncpy(ptyname, ptsname(master), FILENAME_MAX-1);
77 * FIXME: think up some good defaults here
80 if (!ioctl(0, TIOCGWINSZ, &ws))
81 ioctl(master, TIOCSWINSZ, &ws);
82 if (!tcgetattr(0, &ts))
83 tcsetattr(master, TCSANOW, &ts);
87 slave = open(ptyname, O_RDWR | O_NOCTTY);
89 perror("slave pty: open");
94 * Fork and execute the command.
110 fcntl(slave, F_SETFD, 0); /* don't close on exec */
113 if (slave != 0 && slave != 1)
120 if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
121 ioctl(fd, TIOCNOTTY, &i);
126 * Make the new pty our controlling terminal. On some OSes
127 * this is done with TIOCSCTTY; Cygwin doesn't have that, so
128 * instead it's done by simply opening the pty without
129 * O_NOCTTY. This code is primarily intended for Cygwin, but
130 * it's useful to have it work in other contexts for testing
131 * purposes, so I leave the TIOCSCTTY here anyway.
133 if ((fd = open(ptyname, O_RDWR)) >= 0) {
135 ioctl(fd, TIOCSCTTY, &i);
139 perror("slave pty: open");
142 tcsetpgrp(0, getpgrp());
144 for (i = 0; i < shdata->nenvvars; i++)
145 putenv(shdata->envvars[i]);
146 if (shdata->termtype)
147 putenv(shdata->termtype);
153 * Use the provided shell program name, if the user gave
154 * one. Failing that, use $SHELL; failing that, look up
155 * the user's default shell in the password file; failing
156 * _that_, revert to the bog-standard /bin/sh.
161 shell = getenv("SHELL");
168 * For maximum generality in the face of multiple
169 * /etc/passwd entries with different login names and
170 * shells but a shared uid, we start by using
171 * getpwnam(getlogin()) if it's available - but we
172 * insist that its uid must match our real one, or we
173 * give up and fall back to getpwuid(getuid()).
177 if (login && (pwd = getpwnam(login)) && pwd->pw_uid == uid)
178 shell = pwd->pw_shell;
179 else if ((pwd = getpwuid(uid)))
180 shell = pwd->pw_shell;
185 fallback_args[0] = shell;
186 fallback_args[1] = NULL;
187 program_args = fallback_args;
190 execv(program_args[0], program_args);
193 * If we're here, exec has gone badly foom.