1 char *ckptyv = "Pseudoterminal support, 9.0.101, 13 Jun 2011";
3 /* C K U P T Y -- C-Kermit pseudoterminal control functions for UNIX */
5 /* Last update: Mon Jun 13 11:32:52 2011 */
8 Copyright 1995 by the Massachusetts Institute of Technology.
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted, provided
12 that the above copyright notice appear in all copies and that both that
13 copyright notice and this permission notice appear in supporting
14 documentation, and that the name of M.I.T. not be used in advertising or
15 publicity pertaining to distribution of the software without specific,
16 written prior permission. Furthermore if you modify this software you must
17 label your software as modified software and not distribute it in such a
18 fashion that it might be confused with the original M.I.T. software.
19 M.I.T. makes no representations about the suitability of this software for
20 any purpose. It is provided "as is" without express or implied warranty.
22 Modified for use in C-Kermit, and new material added, by:
24 Jeffrey Altman <jaltman@secure-endpoints.com>
25 Secure Endpoints Inc., New York City
28 Parameterized for pty file descriptor and function code,
29 Frank da Cruz, Columbia University, New York City
34 Built and tested successully on:
35 . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
38 . Digital UNIX 3.2 and 4.0
39 . HP-UX 9.00 and later
45 . QNX 4.25 (except PTY process termination not detected)
53 . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
54 . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
60 #include "ckcdeb.h" /* To pick up NETPTY definition */
62 #ifndef NETPTY /* Selector for PTY support */
64 char * ptyver = "No PTY support";
66 #else /* (rest of this module...) */
68 char * ptyver = "PTY support 8.0.016, 22 Aug 2007";
70 /* These will no doubt need adjustment... */
106 #endif /* BSD44ORPOSIX */
111 #endif /* USE_TERMIO */
118 #define POSIX_TERMIOS /* Seems to be a misnomer */
119 #endif /* USE_TERMIO */
122 #ifndef GETPGRP_ONEARG
123 #define GETPGRP_ONEARG
124 #endif /* GETPGRP_ONEARG */
127 #ifdef WANT_UTMP /* See ckupty.h */
129 WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
130 nonportable part of this module, and (b) we're not logging anybody
131 in, we're just running a process, and don't need to write utmp/wtmp records.
133 #ifndef HAVE_SETUTXENT /* Who has <utmpx.h> */
135 #define HAVE_SETUTXENT
138 #define HAVE_SETUTXENT
141 #define HAVE_SETUTXENT
144 #define HAVE_SETUTXENT
147 #define HAVE_SETUTXENT
150 #define HAVE_SETUTXENT
152 #endif /* UNIXWARE */
154 #endif /* CK_SCOV5 */
157 #endif /* HAVE_SETUTXENT */
159 #ifndef HAVE_UTHOST /* Does utmp include ut_host[]? */
160 #ifdef HAVE_SETUTXENT /* utmpx always does */
163 #ifdef LINUX /* Linux does */
166 #ifdef SUNOS4 /* SunOS does */
169 #ifdef AIX41 /* AIX 4.1 and later do */
174 #endif /* HAVE_SETUTXENT */
175 #endif /* HAVE_UTHOST */
180 #endif /* NO_UT_HOST */
181 #endif /* HAVE_UT_HOST */
183 #endif /* WANT_UTMP */
187 #define HAVE_SYS_SELECT_H
188 #define HAVE_GETUTENT
189 #define HAVE_SETUTENT
199 #endif /* HAVE_PTYTRAP */
207 #endif /* HAVE_PTYTRAP */
228 #define PUSH_TTCOMPAT
245 #endif /* HAVE_PTMX */
249 #endif /* HAVE_STREAMS */
257 #define O_NDELAY O_NONBLOCK
258 #endif /* O_NONBLOCK */
259 #endif /* O_NDELAY */
260 #else /* PTYNOBLOCK */
263 #endif /* O_NDELAY */
265 #endif /* PTYNOBLOCK */
272 #include <sys/wait.h>
273 #endif /* CK_WAIT_H */
278 #endif /* INIT_SPTY */
280 #include <sys/stream.h>
284 /* Make sure we don't get the BSD version */
286 #ifdef HAVE_SYS_TTY_H
287 #include "/usr/include/sys/tty.h"
288 #endif /* HAVE_SYS_TTY_H */
290 #ifdef HAS_PTYVAR /* Where is this set? */
292 #include <sys/ptyvar.h>
294 #else /* HAS_PTYVAR */
296 #ifndef TIOCPKT_FLUSHWRITE
297 #define TIOCPKT_FLUSHWRITE 0x02
298 #define TIOCPKT_NOSTOP 0x10
299 #define TIOCPKT_DOSTOP 0x20
300 #define TIOCPKT_IOCTL 0x40
301 #endif /* TIOCPKT_FLUSHWRITE */
303 #endif /* HAS_PTYVAR */
307 #endif /* HAVE_TTY_H */
310 Because of the way ptyibuf is used with streams messages, we need
311 ptyibuf+1 to be on a full-word boundary. The following weirdness
312 is simply to make that happen.
314 long ptyibufbuf[BUFSIZ/sizeof(long)+1];
315 char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
316 char *ptyip = ((char *)&ptyibufbuf[1])-1;
317 char ptyibuf2[BUFSIZ];
318 unsigned char ctlbuf[BUFSIZ];
319 struct strbuf strbufc, strbufd;
323 #else /* ! STREAMSPTY */
325 /* I/O data buffers, pointers, and counters. */
327 char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
328 char ptyibuf2[BUFSIZ];
330 #endif /* ! STREAMSPTY */
341 #define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
342 #define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
343 #define cfgetospeed(tp) (tp)->sg.sg_ospeed
344 #define cfgetispeed(tp) (tp)->sg.sg_ispeed
346 #else /* USE_TERMIO */
349 #define termios termio
350 #endif /* SYSV_TERMIO */
356 #define TCSANOW TCSETS
357 #define TCSADRAIN TCSETSW
358 #define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
363 #define TCSANOW TCSETA
364 #define TCSADRAIN TCSETAW
365 #define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
367 #define TCSANOW TIOCSETA
368 #define TCSADRAIN TIOCSETAW
369 #define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
374 #define tcsetattr(f,a,t) ioctl(f,a,t)
375 #define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
376 #define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
379 #define cfsetispeed(tp,val) \
380 (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
381 #define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
383 #define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
384 #define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
389 struct termios termbuf, termbuf2; /* pty control structure */
392 static int spty = -1;
393 #endif /* INIT_SPTY */
395 #endif /* USE_TERMIO */
405 /* Variables available to other modules */
407 int pty_fork_active = 0; /* pty fork is active */
408 PID_T pty_fork_pid = -1; /* pty fork pid */
409 int pty_slave_fd = -1; /* pty slave file descriptor */
410 int pty_master_fd = -1; /* pty master file descriptor */
412 /* termbuf routines (begin) */
418 These three routines are used to get and set the "termbuf" structure
419 to and from the kernel. init_termbuf() gets the current settings.
420 copy_termbuf() hands in a new "termbuf" to write to the kernel, and
421 set_termbuf() writes the structure into the kernel.
424 init_termbuf(fd) int fd; {
431 debug(F100,"init_termbuf HAVE_STREAMS","",0);
433 debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0);
434 #endif /* HAVE_STREAMS */
436 debug(F100,"init_termbuf STREAMSPTY","",0);
438 debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0);
439 #endif /* STREAMSPTY */
441 debug(F100,"init_termbuf INIT_SPTY","",0);
443 debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0);
444 #endif /* INIT_SPTY */
446 debug(F101,"init_termbuf ttyfd","",ttyfd);
448 debug(F101,"init_termbuf spty","",spty);
449 #endif /* INIT_SPTY */
451 memset(&termbuf,0,sizeof(termbuf));
452 memset(&termbuf2,0,sizeof(termbuf2));
454 rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
455 rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
456 rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
458 rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
459 #endif /* TIOCGSTATE */
460 #else /* USE_TERMIO */
463 rc = tcgetattr(spty, &termbuf);
464 debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
466 rc = tcgetattr(ttyfd, &termbuf);
467 debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
468 #endif /* INIT_SPTY */
469 #endif /* USE_TERMIO */
476 copy_termbuf(cp, len) char *cp; int len; {
477 if (len > sizeof(termbuf))
478 len = sizeof(termbuf);
479 memcpy((char *)&termbuf, cp, len);
482 #endif /* TIOCPKT_IOCTL */
485 set_termbuf(fd) int fd; { /* Only make the necessary changes. */
490 debug(F101,"set_termbuf ttyfd","",ttyfd);
492 debug(F101,"set_termbuf spty","",spty);
493 #endif /* INIT_SPTY */
496 debug(F100,"set_termbuf USE_TERMIO","",0);
497 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
498 ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
499 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
500 ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
501 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
502 sizeof(termbuf.ltc)))
503 ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
504 if (termbuf.lflags != termbuf2.lflags)
505 ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
506 #else /* USE_TERMIO */
507 x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf));
508 debug(F101,"set_termbuf !USE_TERMIO memcmp","",x);
509 x = 1; /* Force this */
514 debug(F100,"set_termbuf INIT_SPTY","",0);
515 x = tcsetattr(spty, TCSANOW, &termbuf);
516 debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
518 debug(F100,"set_termbuf !INIT_SPTY","",0);
519 x = tcsetattr(ttyfd, TCSANOW, &termbuf);
520 debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
521 #endif /* INIT_SPTY */
523 #endif /* USE_TERMIO */
525 /* termbuf routines (end) */
532 /* Initialize "sa" structure. */
533 sigemptyset(&sa.sa_mask);
535 sa.sa_handler = SIG_IGN;
536 sigaction(SIGHUP, &sa, (struct sigaction *)0);
538 sa.sa_handler = SIG_DFL;
539 sigaction(SIGHUP, &sa, (struct sigaction *)0);
540 #else /* CK_POSIX_SIG */
541 signal(SIGHUP,SIG_IGN);
543 signal(SIGHUP,SIG_DFL);
544 #endif /* CK_POSIX_SIG */
545 #endif /* CK_VHANGUP */
549 This routine is called twice. It's not particularly important that the
550 setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
551 rather that we have a controlling terminal at the end. It is assumed that
552 vhangup doesn't exist and confuse the process's notion of controlling
553 terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
554 the controlling terminal in tact, breaks the association completely, or the
555 system provides TIOCNOTTY to get things back into a reasonable state. In
556 practice, vhangup() either breaks the association completely or doesn't
557 effect controlling terminals, so this condition is met.
560 ptyint_void_association() {
564 "ptyint_void_association()",
569 #endif /* HAVE_SETSID */
572 /* Void tty association first */
574 con_fd = open("/dev/tty", O_RDWR);
576 "ptyint_void_association() open(/dev/tty,O_RDWR)",
580 ioctl(con_fd, TIOCNOTTY, 0);
584 else debug(F101, "ptyint_void_association() open() errno","",errno);
586 #endif /* TIOCNOTTY */
587 #endif /* NO_DEVTTY */
591 /* PID may be zero for unknown.*/
594 pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
597 #endif /* VHANG_LAST */
599 debug(F111,"pty_cleanup()",slave,pid);
602 pty_update_utmp(PTY_DEAD_PROCESS,
607 PTY_UTMP_USERNAME_VALID
609 #endif /* WANT_UTMP */
619 Revoke isn't guaranteed to send a SIGHUP to the processes it
620 dissociates from the terminal. The best solution without a Posix
621 mechanism for forcing a hangup is to killpg() the process group of the
622 pty. This will at least kill the shell and hopefully, the child
623 processes. This is not always the case, however. If the shell puts
624 each job in a process group and doesn't pass along SIGHUP, all
625 processes may not die.
631 kill(-(pid), SIGHUP);
632 #endif /*HAVE_KILLPG*/
634 #else /* HAVE_REVOKE*/
641 sigaddset(&new, SIGCHLD);
642 sigprocmask(SIG_BLOCK, &new, &old);
643 #else /*CK_POSIX_SIG*/
644 int mask = sigblock(sigmask(SIGCHLD));
645 #endif /*CK_POSIX_SIG*/
646 switch (retval = fork()) {
649 sigprocmask(SIG_SETMASK, &old, 0);
650 #else /*CK_POSIX_SIG*/
652 #endif /*CK_POSIX_SIG*/
655 ptyint_void_association();
656 if (retval = (pty_open_ctty(slave, &fd, -1)))
663 waitpid(retval, &status, 0);
664 #else /*HAVE_WAITPID*/
666 #endif /* HAVE_WAITPID */
668 sigprocmask(SIG_SETMASK, &old, 0);
669 #else /*CK_POSIX_SIG*/
671 #endif /*CK_POSIX_SIG*/
675 #endif /*VHANG_LAST*/
676 #endif /* HAVE_REVOKE*/
678 slave[strlen("/dev/")] = 'p';
683 #endif /* HAVE_STREAMS */
688 pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
696 #endif /* HAVE__GETPTY */
697 #endif /* HAVE_OPENPTY */
699 char *slaveret; /* Temp to hold pointer to slave */
700 #endif /*HAVE__GETPTY*/
706 debug(F100,"HAVE_OPENPTY","",0);
720 #else /* HAVE_OPENPTY */
724 This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
725 it fails to work properly; even after calling unlockpt, root gets permission
726 denied opening the pty. The code to support _getpty should be removed if
727 Irix gets working streams ptys in favor of maintaining the least needed code
730 debug(F100,"HAVE__GETPTY","",0);
731 if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
733 return(PTY_GETPTY_NOPTY);
735 if (strlen(slaveret) > slavelength - 1) {
738 return(PTY_GETPTY_SLAVE_TOOLONG);
740 ckstrncpy(slave, slaveret, slavelength);
744 #else /* HAVE__GETPTY */
746 *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
748 debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
753 debug(F100,"HAVE_PTMX","",0);
754 *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
756 debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
759 #endif /* HAVE_PTMX */
761 *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
763 debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
766 *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
768 debug(F110,"pty_getpty()","open(/dev/pty) success",0);
771 /* This would be the pty master */
772 debug(F101,"pty_getpty fd(A)","",*fd);
778 debug(F100,"HAVE_GRANTPT","",0);
779 if (grantpt(*fd) || unlockpt(*fd))
780 return(PTY_GETPTY_STREAMS);
781 #endif /* HAVE_PTMX */
782 #endif /* HAVE_GRANTPT */
785 debug(F100,"HAVE_PTSNAME","",0);
786 p = (char *)ptsname(*fd);
787 debug(F110,"pty_getpty() ptsname()",p,0);
790 debug(F100,"HAVE_TTYNAME","",0);
792 debug(F110,"pty_getpty() ttyname()",p,0);
794 /* If we don't have either what do we do? */
795 return(PTY_GETPTY_NOPTY); /* punt */
796 #endif /* HAVE_TTYNAME */
797 #endif /* HAVE_PTSNAME */
799 if (strlen(p) > slavelength - 1) {
802 return(PTY_GETPTY_SLAVE_TOOLONG);
804 ckstrncpy(slave, p, slavelength);
807 if (fstat(*fd, &stb) < 0) {
809 return(PTY_GETPTY_FSTAT);
811 ptynum = (int)(stb.st_rdev&0xFF);
812 sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
813 if (strlen(slavebuf) > slavelength - 1) {
816 return(PTY_GETPTY_SLAVE_TOOLONG);
818 debug(F110,"pty_getpty() slavebuf",slavebuf,0);
819 ckstrncpy(slave, slavebuf, slavelength);
822 for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
823 sprintf(slavebuf,"/dev/ptyXX"); /* safe */
824 slavebuf[sizeof("/dev/pty") - 1] = *cp;
825 slavebuf[sizeof("/dev/ptyp") - 1] = '0';
826 if (stat(slavebuf, &stb) < 0)
828 for (i = 0; i < 16; i++) {
829 slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
831 *fd = open(slavebuf, O_RDWR|O_NDELAY);
833 debug(F111,"pty_getpty() pty master open error",
837 debug(F111,"pty_getpty() found pty master",slavebuf,*fd);
838 slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
839 if (strlen(slavebuf) > slavelength -1) {
842 return(PTY_GETPTY_SLAVE_TOOLONG);
844 ckstrncpy(slave, slavebuf, slavelength);
845 debug(F110,"pty_getpty slave name",slave,0);
850 return(PTY_GETPTY_NOPTY);
852 #endif /*HAVE__GETPTY*/
853 #endif /* HAVE_OPENPTY */
860 debug(F100,"HAVE_PTYM","",0);
861 tty_bank = &master_name[strlen("/dev/ptym/pty")];
862 tty_num = &master_name[strlen("/dev/ptym/ptyX")];
863 slave_bank = &slave_name[strlen("/dev/pty/tty")];
864 slave_num = &slave_name[strlen("/dev/pty/ttyX")];
870 The following is an array of modules that should be pushed on the stream.
871 See configure.in for caviats and notes about when this array is used and not
875 #ifndef HAVE_LINE_PUSH
876 static char *push_list[] = {
888 #endif /* HAVE_LINE_PUSH */
889 #endif /* HAVE_STREAMS */
892 pty_initialize_slave (fd) int fd; {
895 struct termios new_termio;
901 #endif /* POSIX_TERMIOS */
907 #endif /* POSIX_TERMIOS */
909 debug(F111,"pty_initialize_slave()","fd",fd);
912 #ifdef HAVE_LINE_PUSH
913 while (ioctl(fd,I_POP,0) == 0) ; /* Clear out any old lined's */
915 if (line_push(fd) < 0) {
916 debug(F110,"pty_initialize_slave()","line_push() failed",0);
919 return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
921 #else /*No line_push */
923 char **module = &push_list[0];
925 if (ioctl(fd, I_PUSH, *(module++)) < 0) {
926 debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
927 return(PTY_OPEN_SLAVE_PUSH_FAIL);
932 #endif /*HAVE_STREAMS*/
934 Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
935 explicitly. Why rlogind works at all without this on 4.3BSD is a mystery.
937 #ifdef GETPGRP_ONEARG
938 pid = getpgrp(getpid());
941 #endif /* GETPGRP_ONEARG */
943 debug(F111,"pty_initialize_slave()","pid",pid);
946 ioctl(fd, TIOCSPGRP, &pid);
947 #endif /* TIOCSPGRP */
953 rc = tcgetattr(fd,&new_termio);
954 debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
956 new_termio.c_cc[VMIN] = 1;
957 new_termio.c_cc[VTIME] = 0;
958 rc = tcsetattr(fd,TCSANOW,&new_termio);
959 debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
962 #endif /* POSIX_TERMIOS */
968 pty_logwtmp (tty, user, host) char *user, *tty, *host; {
970 logwtmp(tty,user,host);
976 int loggingin = user[0]; /* Will be empty for logout */
979 strncpy(ut.ut_host, host, sizeof(ut.ut_host));
980 #endif /* NO_UT_HOST */
982 strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
983 ut.ut_time = time(0);
986 ut.ut_pid = getpid();
987 strncpy(ut.ut_user, user, sizeof(ut.ut_user));
989 tmpx = tty + strlen(tty) - 2;
990 ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
991 strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
992 ut.ut_pid = (loggingin ? getpid() : 0);
993 ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
995 strncpy(ut.ut_name, user, sizeof(ut.ut_name));
996 #endif /* NO_UT_PID */
998 return(ptyint_update_wtmp(&ut, host, user));
1000 #endif /* HAVE_LOGWTMP */
1002 #endif /* WANT_UTMP */
1005 This routine is called twice. It's not particularly important that the
1006 setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
1007 rather that we have a controlling terminal at the end. It is assumed that
1008 vhangup doesn't exist and confuse the process's notion of controlling
1009 terminal on any system without TIOCNOTTY. That is, either vhangup() leaves
1010 the controlling terminal in tact, breaks the association completely, or the
1011 system provides TIOCNOTTY to get things back into a reasonable state. In
1012 practice, vhangup() either breaks the association completely or doesn't
1013 effect controlling terminals, so this condition is met.
1016 pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; {
1019 debug(F110,"pty_open_ctty() slave",slave,0);
1021 /* First, dissociate from previous terminal */
1023 if ((retval = ptyint_void_association()) != 0) {
1026 "ptyint_void_association() failed",
1033 The Ultrix (and other BSD tty drivers) require the process group
1034 to be zero in order to acquire the new tty as a controlling tty.
1037 debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno);
1038 #endif /* MUST_SETPGRP */
1041 *fd = open(slave, O_RDWR);
1042 debug(F111,"pty_open_ctty open(slave) fd",slave,*fd);
1044 debug(F111,"pty_open_ctty() open failure", slave, errno);
1045 return(PTY_OPEN_SLAVE_OPENFAIL);
1048 /* This forces the job to have a controlling terminal. */
1050 *fd = open(slave, O_RDWR);
1051 debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd);
1053 /* This shows that /dev/tty exists */
1056 x = open("/dev/tty", O_RDWR);
1057 debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x);
1058 if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno);
1059 debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0);
1060 if (x > -1) close(x);
1063 #endif /* SOLARIS */
1066 setpgrp(0, getpid());
1067 #endif /* MUST_SETPGRP */
1075 #endif /* COMMENT */
1077 /* TIOCSCTTY = Make this the job's controlling terminal */
1079 retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
1080 debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
1082 #endif /* TIOCSCTTY */
1087 pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; {
1091 struct sigaction sa;
1093 sigemptyset(&sa.sa_mask); /* Initialize "sa" structure. */
1095 #endif /* CK_POSIX_SIG */
1098 First, chmod and chown the slave. If we have vhangup then we really need
1099 pty_open_ctty to make sure our controlling terminal is the pty we're
1100 opening. However, if we are using revoke or nothing then we just need a
1101 file descriiptor for the pty. Considering some OSes in this category break
1102 on the second call to open_ctty (currently OSF but others may), we simply
1103 use a descriptor if we can.
1106 if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) {
1108 "pty_open_slave() VHANG_FIRST",
1109 "pty_open_ctty() failed",
1116 "pty_open_slave() VHANG_FIRST",
1117 "PTY_OPEN_SLAVE_OPENFAIL",
1120 return(PTY_OPEN_SLAVE_OPENFAIL);
1122 #endif /* VHANG_FIRST */
1124 if (slave == NULL || *slave == '\0') {
1125 debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
1126 return(PTY_OPEN_SLAVE_TOOSHORT);
1130 if (chmod(slave, 0)) {
1131 debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
1132 return(PTY_OPEN_SLAVE_CHMODFAIL);
1134 if (chown(slave, 0, 0 ) == -1 ) {
1135 debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
1136 return(PTY_OPEN_SLAVE_CHOWNFAIL);
1142 #endif /* VHANG_FIRST */
1144 if ((retval = ptyint_void_association()) != 0) {
1147 "ptyint_void_association() failed",
1154 if (revoke (slave) < 0 ) {
1155 debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
1156 return(PTY_OPEN_SLAVE_REVOKEFAIL);
1158 #endif /* HAVE_REVOKE */
1160 /* Open the pty for real. */
1162 retval = pty_open_ctty(slave, fd, fc);
1163 debug(F111,"pty_open_slave retval",slave,retval);
1164 debug(F111,"pty_open_slave fd",slave,*fd);
1166 debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
1167 return(PTY_OPEN_SLAVE_OPENFAIL);
1169 pty_slave_fd = *fd; /* This is not visible to the upper fork */
1170 debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd);
1171 retval = pty_initialize_slave(*fd);
1172 debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd);
1174 debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
1177 /* (VOID)pty_make_raw(*fd); */
1179 debug(F100,"pty_open_slave OK","",*fd);
1187 #define UTMP_FILE _PATH_UTMP
1188 #endif /* _PATH_UTMP */
1189 #endif /* UTMP_FILE */
1191 /* If it is *still* missing, assume /etc/utmp */
1194 #define UTMP_FILE "/etc/utmp"
1195 #endif /* UTMP_FILE */
1198 #define WTMP_REQUIRES_USERNAME
1199 #endif /* NO_UT_PID */
1202 pty_update_utmp(process_type, pid, username, line, host, flags)
1205 char *username, *line, *host;
1207 /* pty_update_utmp */ {
1208 struct utmp ent, ut;
1209 #ifndef HAVE_SETUTENT
1212 #endif /* HAVE_SETUTENT */
1213 #ifdef HAVE_SETUTXENT
1215 #endif /* HAVE_SETUTXENT */
1219 #endif /* NO_UT_PID */
1223 debug(F100,"pty_update_utmp()","",0);
1224 strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
1225 ent.ut_time = time(0);
1228 if (process_type == PTY_LOGIN_PROCESS)
1230 #else /* NO_UT_PID */
1234 switch (process_type) {
1235 case PTY_LOGIN_PROCESS:
1236 ent.ut_type = LOGIN_PROCESS;
1238 case PTY_USER_PROCESS:
1239 ent.ut_type = USER_PROCESS;
1241 case PTY_DEAD_PROCESS:
1242 ent.ut_type = DEAD_PROCESS;
1245 return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
1247 #endif /*NO_UT_PID*/
1251 strncpy(ent.ut_host, host, sizeof(ent.ut_host));
1253 ent.ut_host[0] = '\0';
1254 #endif /* NO_UT_HOST */
1257 if (!strcmp (line, "/dev/console")) {
1270 strncpy(ent.ut_id, s, 4);
1274 tmpx = line + strlen(line)-1;
1275 if (*(tmpx-1) != '/') tmpx--; /* last 2 chars unless it's a '/' */
1277 ckstrncpy(utmp_id, tmpx, 5);
1279 ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
1281 strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
1283 strncpy(ent.ut_user, username, sizeof(ent.ut_user));
1287 strncpy(ent.ut_name, username, sizeof(ent.ut_name));
1289 #endif /* NO_UT_PID */
1292 strncpy(userbuf, username, sizeof(userbuf));
1296 #ifdef HAVE_SETUTENT
1298 utmpname(UTMP_FILE);
1301 If we need to preserve the user name in the wtmp structure and Our flags
1302 tell us we can obtain it from the utmp and we succeed in obtaining it, we
1303 then save the utmp structure we obtain, write out the utmp structure and
1304 change the username pointer so it is used by update_wtmp.
1307 #ifdef WTMP_REQUIRES_USERNAME
1308 if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
1310 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1311 utptr = getutline(&ut);
1313 strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
1315 #endif /* WTMP_REQUIRES_USERNAME */
1320 #ifdef HAVE_SETUTXENT
1322 #ifdef HAVE_GETUTMPX
1323 getutmpx(&ent, &utx);
1324 #else /* HAVE_GETUTMPX */
1325 /* For platforms like HPUX and Dec Unix which don't have getutmpx */
1326 strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
1327 strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
1328 strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
1329 utx.ut_pid = pid; /* kludge for Irix, etc. to avoid trunc. */
1330 utx.ut_type = ent.ut_type;
1331 #ifdef UT_EXIT_STRUCTURE_DIFFER
1332 utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
1333 #else /* UT_EXIT_STRUCTURE_DIFFER */
1334 /* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
1336 utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
1337 utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
1339 /* XXX do nothing for now; we don't even know the struct member exists */
1341 #endif /* UT_EXIT_STRUCTURE_DIFFER */
1342 utx.ut_tv.tv_sec = ent.ut_time;
1343 utx.ut_tv.tv_usec = 0;
1344 #endif /* HAVE_GETUTMPX */
1346 strncpy(utx.ut_host, host, sizeof(utx.ut_host));
1351 #endif /* HAVE_SETUTXENT */
1353 #else /* HAVE_SETUTENT */
1354 if (flags&PTY_TTYSLOT_USABLE) {
1359 if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
1362 lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
1368 ) != sizeof(struct utmp)
1371 if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
1373 #ifdef WTMP_REQUIRES_USERNAME
1374 if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
1375 strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
1376 #endif /* WTMP_REQUIRES_USERNAME */
1382 if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
1383 lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
1384 write(fd, (char *)&ent, sizeof(struct utmp));
1387 #endif /* HAVE_SETUTENT */
1389 /* Don't record LOGIN_PROCESS entries. */
1390 if (process_type == PTY_LOGIN_PROCESS)
1393 return(ptyint_update_wtmp(&ent, host, userbuf));
1397 #define WTMP_FILE _PATH_WTMP
1398 #endif /* _PATH_WTMP */
1399 #endif /* WTMP_FILE */
1403 #ifdef HAVE_UPDWTMPX
1404 #define WTMPX_FILE _PATH_WTMPX
1405 #endif /* HAVE_UPDWTMPX */
1406 #endif /* _PATH_WTMPX */
1407 #endif /* WTMPX_FILE */
1409 /* If it is *still* missing, assume /usr/adm/wtmp */
1412 #define WTMP_FILE "/usr/adm/wtmp"
1413 #endif /* WTMP_FILE */
1416 /* The following test can not be made portably */
1418 /* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
1420 This is ugly, but the lack of standardization in the utmp/utmpx space, and
1421 what glibc implements and doesn't make available, is even worse.
1423 /* #undef HAVE_UPDWTMPX */ /* Don't use updwtmpx for glibc 2.1 */
1424 /* #endif */ /* __GLIBC__ etc */
1429 #undef HAVE_UPDWTMPX /* Don't use updwtmpx for glibc period */
1430 #endif /* __GLIBC__ */
1431 #endif /* COMMENT */
1434 ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
1439 #ifdef HAVE_UPDWTMPX
1442 getutmpx(ent, &utx);
1444 strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
1448 strncpy(utx.ut_user, user, sizeof(utx.ut_user));
1449 updwtmpx(WTMPX_FILE, &utx);
1450 #endif /* HAVE_UPDWTMPX */
1453 #ifndef HAVE_UPDWTMPX
1454 /* This is already performed byupdwtmpx if present.*/
1455 updwtmp(WTMP_FILE, ent);
1456 #endif /* HAVE_UPDWTMPX*/
1457 #else /* HAVE_UPDWTMP */
1459 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
1460 if (!fstat(fd, &statb)) {
1461 memset((char *)&ut, 0, sizeof(ut));
1463 strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
1465 strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
1466 strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
1468 strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
1469 #endif /* NO_UT_HOST */
1472 ut.ut_time = uttime;
1474 #ifdef HAVE_GETUTENT
1478 ut.ut_pid = getpid();
1480 ut.ut_type = USER_PROCESS;
1482 ut.ut_type = ent->ut_type;
1490 ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
1494 #endif /* USER_PROCESS */
1495 #endif /* HAVE_GETUTENT */
1497 if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
1498 sizeof(struct utmp))
1500 ftruncate(fd, statb.st_size);
1502 chsize(fd, statb.st_size);
1503 #endif /* COHERENT */
1507 #endif /* HAVE_UPDWTMP */
1508 return(0); /* no current failure cases; file not found is not failure! */
1510 #endif /* WANT_UTMP */
1512 /* This is for ancient Unixes that don't have these tty symbols defined. */
1515 #define PENDIN ICANON
1518 #define FLUSHO ICANON
1521 #define IMAXBEL ICANON
1522 #endif /* IMAXBEL */
1524 #define EXTPROC ICANON
1525 #endif /* EXTPROC */
1527 static char Xline[17] = { 0, 0 };
1530 Open the slave side of the pty, and do any initialization that is necessary.
1531 The return value fd is a file descriptor for the slave side.
1532 fc = function code from do_pty() (q.v.)
1535 getptyslave(fd, fc) int * fd, fc; {
1541 extern int cmd_rows, cmd_cols;
1542 #endif /* TIOCGWINSZ */
1545 debug(F111,"getptyslave()","ttyfd",ttyfd);
1547 * Opening the slave side may cause initilization of the
1548 * kernel tty structure. We need remember the state of:
1549 * if linemode was turned on
1550 * terminal window size
1552 * so that we can reset them if we need to.
1554 if ((retval = pty_open_slave(Xline, &t, fc)) != 0) {
1557 debug(F111,"getptyslave()","Unable to open slave",retval);
1560 debug(F111,"getptyslave","t",t);
1563 debug(F111,"getptyslave","spty",spty);
1564 #endif /* INIT_SPTY */
1566 if (ioctl(t,I_PUSH,"pckt") < 0) {
1567 debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
1569 fatal("I_PUSH pckt");
1572 #endif /* STREAMSPTY */
1574 /* Set up the tty modes as we like them to be. */
1576 /* Originally like this... But this is the master - we want the slave */
1577 /* Anyway, this fails on Solaris and probably other System V OS's */
1578 init_termbuf(ttyfd);
1581 #endif /* COMMENT */
1583 if (cmd_rows || cmd_cols) {
1584 memset((char *)&ws, 0, sizeof(ws));
1585 ws.ws_col = cmd_cols;
1586 ws.ws_row = cmd_rows;
1587 debug(F101,"getptyslave() doing TIOCSWINSZ...","",t);
1588 ioctl(t, TIOCSWINSZ, (char *)&ws);
1590 #endif /* TIOCGWINSZ */
1592 /* For external protocols, put the pty in no-echo mode */
1594 debug(F100,"getptyslave() setting rawmode","",0);
1596 termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
1597 termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF);
1598 termbuf.c_iflag |= IGNBRK;
1600 termbuf.c_iflag &= ~IUCLC;
1604 termbuf.c_oflag &= ~OPOST;
1606 termbuf.c_oflag &= ~OXTABS;
1609 termbuf.c_oflag &= ~ONOCR;
1612 termbuf.c_oflag &= ~ONLRET;
1615 termbuf.c_oflag &= ~ONLCR;
1619 termbuf.c_lflag &= ~ECHO;
1621 termbuf.c_lflag &= ~ECHOE;
1624 termbuf.c_lflag &= ~ECHONL;
1627 termbuf.c_lflag &= ~ECHOPRT;
1628 #endif /* ECHOPRT */
1630 termbuf.c_lflag &= ~ECHOKE;
1633 termbuf.c_lflag &= ~ECHOCTL;
1634 #endif /* ECHOCTL */
1636 termbuf.c_lflag &= ~ALTWERASE;
1637 #endif /* ALTWERASE */
1639 termbuf.c_lflag &= ~EXTPROC;
1640 #endif /* EXTPROC */
1641 termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
1644 termbuf.c_lflag |= NOKERNINFO;
1645 #endif /* NOKERNINFO */
1646 /* termbuf.c_lflag |= NOFLSH; */
1647 termbuf.c_lflag &= ~NOFLSH;
1650 termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD);
1651 termbuf.c_cflag |= CS8|CREAD;
1653 termbuf.c_cc[VMIN] = 1;
1655 } else { /* Regular interactive use */
1656 debug(F100,"getptyslave() setting cooked mode","",0);
1658 /* Settings for sgtty based systems */
1661 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
1662 #endif /* USE_TERMIO */
1668 /* Settings for UNICOS and HPUX */
1671 termbuf.c_oflag = OPOST|ONLCR|TAB3;
1672 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1673 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1674 termbuf.c_cflag = EXTB|HUPCL|CS8;
1677 termbuf.c_oflag = OPOST|ONLCR|TAB3;
1678 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1679 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1680 termbuf.c_cflag = EXTB|HUPCL|CS8;
1684 Settings for all other termios/termio based systems, other than
1685 4.4BSD. In 4.4BSD the kernel does the initial terminal setup.
1689 termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
1690 termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
1691 termbuf.c_iflag |= ICRNL|IGNPAR;
1692 termbuf.c_cflag |= HUPCL;
1693 termbuf.c_iflag &= ~IXOFF;
1696 termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
1697 termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
1698 termbuf.c_iflag |= ICRNL|IGNPAR;
1699 termbuf.c_cflag |= HUPCL;
1700 termbuf.c_iflag &= ~IXOFF;
1702 #endif /* USE_TERMIO */
1707 /* Set the tty modes, and make this our controlling tty. */
1709 /* But this is the master - we want the slave */
1713 #endif /* COMMENT */
1722 } else if (fc == 1) {
1723 /* For external protocols, send stderr to /dev/null */
1727 char * s = "/dev/null";
1729 xx = open(s, O_WRONLY);
1731 char * s = "pty.log";
1733 xx = open(s, O_CREAT, 0644);
1734 #endif /* COMMENT */
1735 debug(F111,"getptyslave redirect stderr",s,errno);
1737 #endif /* COMMENT */
1753 To be called to determine if a trap is pending on a pty
1754 if and only if select() cannot be used.
1757 pty_trap_pending(fd) int fd; {
1761 rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
1763 debug(F101,"pty_trap_pending()","",pending);
1766 debug(F111,"pty_trap_pending()","ioctl() failed",rc);
1772 To be called after select() has returned indicating that an exception is
1773 waiting on a pty. It should be called with the file descriptor of the pty.
1774 Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
1777 pty_trap_handler(fd) int fd; {
1778 struct request_info ri;
1780 memset(&ri,0,sizeof(ri));
1781 if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
1782 debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
1785 switch (ri.request) {
1787 debug(F110,"pty_trap_handler()","an open() call",0);
1790 debug(F110,"pty_trap_handler()","a close() call",0);
1793 debug(F110,"pty_trap_handler()","an ioctl() call",0);
1794 ri.errno_error = EINVAL;
1796 if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
1797 debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
1800 if (ri.request == TIOCCLOSE)
1805 #endif /* HAVE_PTYTRAP */
1808 exec_cmd(s) char * s; {
1809 struct stringarray * q;
1810 char ** args = NULL;
1815 q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
1818 args = q->a_head + 1;
1824 for (i = 0; i <= n; i++) {
1826 debug(F111,"exec_cmd arg","NULL",i);
1829 debug(F111,"exec_cmd arg",args[i],i);
1830 if (i == n && args[i]) {
1831 debug(F101,"exec_cmd SUBSTITUTING NULL","",i);
1832 if (strlen(args[i]) == 0)
1833 makestr(&(args[i]),NULL);
1841 execvp(args[0],args);
1844 /* Get a pty, scan input lines. */
1845 /* fc = 0 for interactive access; fc = 1 for running external protocols */
1847 static int pty_fc = -1; /* Global copy of fc */
1850 do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; {
1856 #endif /* HAVE_PTYTRAP */
1858 debug(F101,"CKUPTY.C do_pty fc","",fc);
1866 msg = 0; /* Message counter */
1867 pty_init(); /* Find an available pty to use. */
1870 if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
1873 debug(F111,"do_pty()","pty_getpty() fails",retval);
1878 debug(F111,"do_pty() Xline",Xline,ttyfd);
1882 Ignoring SIGTTOU keeps the kernel from blocking us. we tweak the tty with
1883 an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
1885 signal(SIGTTOU, SIG_IGN);
1886 #endif /* SIGTTOU */
1888 /* Start up the command on the slave side of the terminal */
1890 if (pipe(syncpipe) < 0) {
1891 debug(F110,"do_pty()","pipe() fails",0);
1892 perror("pipe() failed");
1894 debug(F111,"do_pty()","pipe fails",errno);
1897 if ((i = fork()) < 0) {
1898 /* XXX - need to clean up the allocated pty */
1899 perror("fork() failed");
1901 debug(F111,"do_pty()","fork fails",errno);
1904 if (i) { /* Wait for child before writing to parent side of pty. */
1908 #endif /* HAVE_PTYTRAP */
1911 if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
1912 perror("Pipe read() failed");
1914 debug(F110,"do_pty()","Slave fails to initialize",0);
1918 pty_fork_pid = i; /* So we can clean it up later */
1919 pty_fork_active = 1;
1920 debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
1922 /* HPUX does not allow the master to read end of file. */
1923 /* Therefore, we must determine that the slave has been */
1924 /* closed by trapping the call to close(). */
1926 x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
1927 debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
1928 #endif /* HAVE_PTYTRAP */
1929 debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
1933 debug(F101,"do_pty getptyslave ttyfd A","",ttyfd);
1934 debug(F110,"do_pty()","Slave starts",0);
1935 x = getptyslave(&ttyfd,fc);
1936 debug(F101,"do_pty getptyslave","",x);
1938 debug(F101,"do_pty getptyslave ttyfd B","",ttyfd);
1940 pty_update_utmp(PTY_USER_PROCESS,
1947 #endif /* WANT_UTMP */
1948 /* Notify our parent we're ready to continue.*/
1949 debug(F110,"do_pty()","slave synchronizing",0);
1950 write(syncpipe[1],"y",1);
1954 debug(F110,"do_pty cmd",cmd,"");
1956 debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
1959 debug(F110,"do_pty()","getptyslave() fails - exiting",0);
1965 } /* end of do_pty() */
1970 msg = 0; /* Message counter */
1971 debug(F101,"end_pty pty_fork_pid","",pty_fork_pid);
1972 if (Xline[0] && pty_fork_pid >= 0) {
1973 pty_cleanup(Xline,pty_fork_pid,1);
1976 pty_fork_active = 0;
1977 debug(F101,"end_pty pty_fork_active","",pty_fork_active);