2 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 RCSID("$Id: forkpty.c,v 1.57 1999/12/02 16:58:28 joda Exp $");
40 /* Only CRAY is known to have problems with forkpty(). */
42 static int forkpty_ok = 0;
44 static int forkpty_ok = 1;
48 static char *ptsname(int fd)
59 #define grantpt(fdm) (0)
63 #define unlockpt(fdm) (0)
78 if ( (slave = open(line, O_RDWR)) < 0)
81 ofun = signal(SIGHUP, SIG_IGN);
85 * Some systems (atleast SunOS4) want to have the slave end open
86 * at all times to prevent a race in the child. Login will close
87 * it so it should really not be a problem. However for the
88 * paranoid we use the close on exec flag so it will only be open
89 * in the parent. Additionally since this will be the controlling
90 * tty of rlogind the final vhangup() in rlogind should hangup all
91 * processes. A working revoke would of course have been prefered
94 fcntl(slave, F_SETFD, 1);
100 static int pty_major, pty_minor;
109 static char *bsd_1 = "0123456789abcdefghijklmnopqrstuv";
110 /* there are many more */
111 static char *bsd_2 = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
114 pty_scan_next(char *buf, size_t sz)
117 if(++pty_major >= sysconf(_SC_CRAY_NPTY))
119 snprintf(buf, sz, "/dev/pty/%03d", pty_major);
121 if(++pty_major == strlen(bsd_1)){
123 if(++pty_minor == strlen(bsd_2))
127 snprintf(buf, sz, "/dev/ptym/pty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
129 snprintf(buf, sz, "/dev/pty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
136 pty_scan_tty(char *buf, size_t sz)
139 snprintf(buf, sz, "/dev/ttyp%03d", pty_major);
140 #elif defined(__hpux)
141 snprintf(buf, sz, "/dev/pty/tty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
143 snprintf(buf, sz, "/dev/tty%c%c", bsd_2[pty_major], bsd_1[pty_minor]);
148 ptym_open_streams_flavor(char *pts_name,
152 /* Try clone device master ptys */
153 const char *const clone[] = { "/dev/ptc", "/dev/ptmx",
154 "/dev/ptm", "/dev/ptym/clone", 0 };
156 const char *const *q;
158 for (q = clone; *q; q++) {
159 fdm = open(*q, O_RDWR);
165 if ((ptr1 = ptsname(fdm)) != NULL) /* Get slave's name */
166 /* Return name of slave */
167 strlcpy(pts_name, ptr1, pts_name_sz);
172 if (grantpt(fdm) < 0) { /* Grant access to slave */
176 if (unlockpt(fdm) < 0) { /* Clear slave's lock flag */
180 return(fdm); /* return fd of master */
186 ptym_open_bsd_flavor(char *pts_name, size_t pts_name_sz, int *streams_pty)
189 char ptm[MaxPathLen];
193 while (pty_scan_next(ptm, sizeof(ptm)) != -1) {
194 fdm = open(ptm, O_RDWR);
198 /* Avoid a bug in SunOS4 ttydriver */
201 if ((ioctl(fdm, TIOCGPGRP, &pgrp) == -1)
210 pty_scan_tty(pts_name, sizeof(ptm));
212 /* this is some magic from the telnet code */
215 if(stat(pts_name, &sb) < 0) {
219 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
220 chown(pts_name, 0, 0);
221 chmod(pts_name, 0600);
229 * Now it should be safe...check for accessability.
231 if (access(pts_name, 6) != 0){
232 /* no tty side to pty so skip it */
237 return fdm; /* All done! */
240 /* We failed to find BSD style pty */
247 * Open a master pty either using the STREAM flavor or the BSD flavor.
248 * Depending on if there are any free ptys in the different classes we
249 * need to try both. Normally try STREAMS first and then BSD.
251 * Kludge alert: Under HP-UX 10 and perhaps other systems STREAM ptys
252 * doesn't get initialized properly so we try them in different order
253 * until the problem has been resolved.
257 ptym_open(char *pts_name, size_t pts_name_sz, int *streams_pty)
263 char *p = _getpty(&fdm, O_RDWR, 0600, 1);
266 strlcpy (pts_name, p, pts_name_sz);
273 fdm = ptym_open_streams_flavor(pts_name, pts_name_sz, streams_pty);
281 fdm = ptym_open_bsd_flavor(pts_name, pts_name_sz, streams_pty);
289 fdm = ptym_open_streams_flavor(pts_name, pts_name_sz, streams_pty);
301 maybe_push_modules(int fd, char **modules)
307 for(p=modules; *p; p++){
308 err=ioctl(fd, I_FIND, *p);
311 if(err < 0 && errno != EINVAL)
313 /* module not pushed or does not exist */
315 /* p points to null or to an already pushed module, now push all
316 modules before this one */
318 for(p--; p >= modules; p--){
319 err = ioctl(fd, I_PUSH, *p);
320 if(err < 0 && errno != EINVAL)
328 ptys_open(int fdm, char *pts_name, int streams_pty)
333 /* Streams style slave ptys */
334 if ( (fds = open(pts_name, O_RDWR)) < 0) {
340 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
341 char *ptymodules[] = { "pckt", NULL };
343 if(maybe_push_modules(fds, ttymodules)<0){
348 if(maybe_push_modules(fdm, ptymodules)<0){
355 /* BSD style slave ptys */
358 if ( (grptr = getgrnam("tty")) != NULL)
361 gid = -1; /* group tty is not in the group file */
363 /* Grant access to slave */
364 if (chown(pts_name, getuid(), gid) < 0)
365 fatal(0, "chown slave tty failed", 1);
366 if (chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP) < 0)
367 fatal(0, "chmod slave tty failed", 1);
369 if ( (fds = open(pts_name, O_RDWR)) < 0) {
378 forkpty_truncate(int *ptrfdm,
380 size_t slave_name_sz,
381 struct termios *slave_termios,
382 struct winsize *slave_winsize)
384 int fdm, fds, streams_pty;
389 fatal(0, "Protocol not yet supported, use telnet", 0);
391 if ( (fdm = ptym_open(pts_name, sizeof(pts_name), &streams_pty)) < 0)
394 if (slave_name != NULL)
395 /* Return name of slave */
396 strlcpy(slave_name, pts_name, slave_name_sz);
401 else if (pid == 0) { /* Child */
403 fatal(0, "setsid() failure", errno);
407 #if defined(NeXT) || defined(ultrix)
408 /* The NeXT is severely broken, this makes things slightly
409 * better but we still doesn't get a working pty. If there
410 * where a TIOCSCTTY we could perhaps fix things but... The
411 * same problem also exists in xterm! */
412 if (setpgrp(0, 0) < 0)
413 fatal(0, "NeXT kludge failed setpgrp", errno);
416 /* SVR4 acquires controlling terminal on open() */
417 if ( (fds = ptys_open(fdm, pts_name, streams_pty)) < 0)
419 close(fdm); /* All done with master in child */
421 #if defined(TIOCSCTTY) && !defined(CIBAUD) && !defined(__hpux)
422 /* 44BSD way to acquire controlling terminal */
423 /* !CIBAUD to avoid doing this under SunOS */
424 if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
429 int t = open("/dev/tty", O_RDWR);
431 fatal(0, "Failed to open /dev/tty", errno);
436 /* Set slave's termios and window size */
437 if (slave_termios != NULL) {
438 if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
442 if (slave_winsize != NULL) {
443 if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
447 /* slave becomes stdin/stdout/stderr of child */
448 if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
450 if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
452 if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
454 if (fds > STDERR_FILENO)
456 return(0); /* child returns 0 just like fork() */
459 *ptrfdm = fdm; /* Return fd of master */
460 return(pid); /* Parent returns pid of child */
467 struct termios *slave_termios,
468 struct winsize *slave_winsize)
470 return forkpty_truncate (ptrfdm,
477 #endif /* HAVE_FORKPTY */