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.