home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / tmp4 / ckupty.c < prev    next >
C/C++ Source or Header  |  2009-10-16  |  52KB  |  1,969 lines

  1. char *ckptyv = "Pseudoterminal support, 9.0.100, 16 Oct 2009";
  2.  
  3. /*  C K U P T Y  --  C-Kermit pseudoterminal control functions for UNIX  */
  4.  
  5. /* Last update: Thu Sep 24 13:01:48 2009 */
  6.  
  7. /*
  8.   Copyright 1995 by the Massachusetts Institute of Technology.
  9.  
  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.
  21.  
  22.   Modified for use in C-Kermit, and new material added, by:
  23.  
  24.   Jeffrey Altman <jaltman@secure-endpoints.com>
  25.   Secure Endpoints Inc., New York City
  26.   November 1999
  27.  
  28.   Parameterized for pty file descriptor and function code,
  29.   Frank da Cruz, Columbia University, New York City
  30.   Dec 2006 - Sep 2009
  31. */
  32.  
  33. /*
  34.   Built and tested successully on:
  35.    . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
  36.    . AIX 4.1 and later
  37.    . DG/UX 5.4R4.11
  38.    . Digital UNIX 3.2 and 4.0
  39.    . HP-UX 9.00 and later
  40.    . IRIX 6.0 and later
  41.    . Linux
  42.    . Mac OS X 10.4
  43.    . NeXTSTEP 3.x
  44.    . OpenBSD
  45.    . QNX 4.25 (except PTY process termination not detected)
  46.    . SCO OSR5.0.5
  47.    . SCO Unixware 7
  48.    . SINIX 5.42
  49.    . Solaris 2.x and 7
  50.    . SunOS 4.1.3
  51.  
  52.   Failures include:
  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)
  55. */
  56.  
  57. #include "ckcsym.h"
  58. #include "ckcdeb.h"            /* To pick up NETPTY definition */
  59.  
  60. #ifndef NETPTY                /* Selector for PTY support */
  61.  
  62. char * ptyver = "No PTY support";
  63.  
  64. #else  /* (rest of this module...) */
  65.  
  66. char * ptyver = "PTY support 8.0.016, 22 Aug 2007";
  67.  
  68. /* These will no doubt need adjustment... */
  69.  
  70. #ifndef NEXT
  71. #define HAVE_SETSID
  72. #endif /* NEXT */
  73. #define HAVE_KILLPG
  74. #define HAVE_TTYNAME
  75. #define HAVE_WAITPID
  76.  
  77. #ifndef USE_TERMIO
  78. #ifdef LINUX
  79. #define USE_TERMIO
  80. #else
  81. #ifdef ATTSV
  82. #define USE_TERMIO
  83. #else
  84. #ifdef HPUX
  85. #define USE_TERMIO
  86. #else
  87. #ifdef AIX
  88. #define USE_TERMIO
  89. #else
  90. #ifdef BSD44ORPOSIX
  91. #define USE_TERMIO
  92. #else
  93. #ifdef IRIX60
  94. #define USE_TERMIO
  95. #else
  96. #ifdef QNX
  97. #define USE_TERMIO
  98. #endif /* QNX */
  99. #endif /* IRIX60 */
  100. #endif /* BSD44ORPOSIX */
  101. #endif /* AIX */
  102. #endif /* HPUX */
  103. #endif /* ATTSV */
  104. #endif /* LINUX */
  105. #endif /* USE_TERMIO */
  106.  
  107. #ifdef QNX
  108. #include <fcntl.h>
  109. #endif /* QNX */
  110.  
  111. #ifdef USE_TERMIO
  112. #define POSIX_TERMIOS            /* Seems to be a misnomer */
  113. #endif /* USE_TERMIO */
  114.  
  115. #ifdef NEXT
  116. #ifndef GETPGRP_ONEARG
  117. #define GETPGRP_ONEARG
  118. #endif /* GETPGRP_ONEARG */
  119. #endif /* NEXT */
  120.  
  121. #ifdef WANT_UTMP            /* See ckupty.h */
  122. /*
  123.   WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
  124.   nonportable part of this module, and (b) we're not logging anybody
  125.   in, we're just running a process, and don't need to write utmp/wtmp records.
  126. */
  127. #ifndef HAVE_SETUTXENT            /* Who has <utmpx.h> */
  128. #ifdef SOLARIS
  129. #define HAVE_SETUTXENT
  130. #else
  131. #ifdef IRIX60
  132. #define HAVE_SETUTXENT
  133. #else
  134. #ifdef CK_SCOV5
  135. #define HAVE_SETUTXENT
  136. #else
  137. #ifdef HPUX10
  138. #define HAVE_SETUTXENT
  139. #else
  140. #ifdef UNIXWARE
  141. #define HAVE_SETUTXENT
  142. #else
  143. #ifdef IRIX60
  144. #define HAVE_SETUTXENT
  145. #endif /* IRIX60 */
  146. #endif /* UNIXWARE */
  147. #endif /* HPUX10 */
  148. #endif /* CK_SCOV5 */
  149. #endif /* IRIX60 */
  150. #endif /* SOLARIS */
  151. #endif /* HAVE_SETUTXENT */
  152.  
  153. #ifndef HAVE_UTHOST            /* Does utmp include ut_host[]? */
  154. #ifdef HAVE_SETUTXENT            /* utmpx always does */
  155. #define HAVE_UTHOST
  156. #else
  157. #ifdef LINUX                /* Linux does */
  158. #define HAVE_UTHOST
  159. #else
  160. #ifdef SUNOS4                /* SunOS does */
  161. #define HAVE_UTHOST
  162. #else
  163. #ifdef AIX41                /* AIX 4.1 and later do */
  164. #define HAVE_UTHOST
  165. #endif /* AIX41 */
  166. #endif /* SUNOS4 */
  167. #endif /* LINUX */
  168. #endif /* HAVE_SETUTXENT */
  169. #endif /* HAVE_UTHOST */
  170.  
  171. #ifndef HAVE_UT_HOST
  172. #ifndef NO_UT_HOST
  173. #define NO_UT_HOST
  174. #endif /* NO_UT_HOST */
  175. #endif /* HAVE_UT_HOST */
  176.  
  177. #endif /* WANT_UTMP */
  178.  
  179. #ifdef LINUX
  180. #define CK_VHANGUP
  181. #define HAVE_SYS_SELECT_H
  182. #define HAVE_GETUTENT
  183. #define HAVE_SETUTENT
  184. #define HAVE_UPDWTMP
  185. #endif /* LINUX */
  186.  
  187. #ifdef HPUX10
  188. #define CK_VHANGUP
  189. #define VHANG_FIRST
  190. #define HAVE_PTSNAME
  191. #ifndef HAVE_PTYTRAP
  192. #define HAVE_PTYTRAP
  193. #endif /* HAVE_PTYTRAP */
  194. #else
  195. #ifdef HPUX9
  196. #define CK_VHANGUP
  197. #define VHANG_FIRST
  198. #define HAVE_PTSNAME
  199. #ifndef HAVE_PTYTRAP
  200. #define HAVE_PTYTRAP
  201. #endif /* HAVE_PTYTRAP */
  202. #endif /* HPUX9 */
  203. #endif /* HPUX10 */
  204.  
  205. #ifdef SUNOS4
  206. #define CK_VHANGUP
  207. #define NO_UT_PID
  208. #define VHANG_FIRST
  209. #endif /* SUNOS4 */
  210.  
  211. #ifdef IRIX60
  212. #define CK_VHANGUP
  213. #define HAVE__GETPTY
  214. #endif /* IRIX60 */
  215.  
  216. #ifdef SINIX
  217. #define HAVE_STREAMS
  218. #define HAVE_GRANTPT
  219. #define HAVE_PTSNAME
  220. #define PUSH_PTEM
  221. #define PUSH_LDTERM
  222. #define PUSH_TTCOMPAT
  223. #endif /* SINIX */
  224.  
  225. #ifdef ultrix
  226. #define MUST_SETPGRP
  227. #endif /* ultrix */
  228.  
  229. #ifdef QNX
  230. #define MUST_SETPGRP
  231. #define NO_DEVTTY
  232. #define INIT_SPTY
  233. #endif /* QNX */
  234.  
  235. #ifdef LINUX
  236. #ifdef HAVE_PTMX
  237. #define HAVE_GRANTPT
  238. #define HAVE_PTSNAME
  239. #endif /* HAVE_PTMX */
  240. #else
  241. #ifdef HAVE_STREAMS
  242. #define HAVE_PTMX
  243. #endif /* HAVE_STREAMS */
  244. #endif /* LINUX */
  245.  
  246. #include "ckupty.h"
  247.  
  248. #ifdef PTYNOBLOCK
  249. #ifndef O_NDELAY
  250. #ifdef O_NONBLOCK
  251. #define O_NDELAY O_NONBLOCK
  252. #endif /* O_NONBLOCK */
  253. #endif /* O_NDELAY */
  254. #else /* PTYNOBLOCK */
  255. #ifdef O_NDELAY
  256. #undef O_NDELAY
  257. #endif /* O_NDELAY */
  258. #define O_NDELAY 0
  259. #endif /* PTYNOBLOCK */
  260.  
  261. #ifndef ONLCR
  262. #define ONLCR 0
  263. #endif /* ONLCR */
  264.  
  265. #ifdef CK_WAIT_H
  266. #include <sys/wait.h>
  267. #endif /* CK_WAIT_H */
  268.  
  269. #ifdef STREAMSPTY
  270. #ifndef INIT_SPTY
  271. #define INIT_SPTY
  272. #endif /* INIT_SPTY */
  273.  
  274. #include <sys/stream.h>
  275. #include <stropts.h>
  276. #include <termio.h>
  277.  
  278. /* Make sure we don't get the BSD version */
  279.  
  280. #ifdef HAVE_SYS_TTY_H
  281. #include "/usr/include/sys/tty.h"
  282. #endif /* HAVE_SYS_TTY_H */
  283.  
  284. #ifdef HAS_PTYVAR            /* Where is this set? */
  285.  
  286. #include <sys/ptyvar.h>
  287.  
  288. #else /* HAS_PTYVAR */
  289.  
  290. #ifndef TIOCPKT_FLUSHWRITE
  291. #define TIOCPKT_FLUSHWRITE 0x02
  292. #define TIOCPKT_NOSTOP     0x10
  293. #define TIOCPKT_DOSTOP     0x20
  294. #define TIOCPKT_IOCTL      0x40
  295. #endif /* TIOCPKT_FLUSHWRITE */
  296.  
  297. #endif /* HAS_PTYVAR */
  298.  
  299. #ifdef HAVE_TTY_H
  300. #include <tty.h>
  301. #endif /* HAVE_TTY_H */
  302. /*
  303.   Because of the way ptyibuf is used with streams messages, we need
  304.   ptyibuf+1 to be on a full-word boundary.  The following weirdness
  305.   is simply to make that happen.
  306. */
  307. long ptyibufbuf[BUFSIZ/sizeof(long)+1];
  308. char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
  309. char *ptyip = ((char *)&ptyibufbuf[1])-1;
  310. char ptyibuf2[BUFSIZ];
  311. unsigned char ctlbuf[BUFSIZ];
  312. struct strbuf strbufc, strbufd;
  313.  
  314. int readstream();
  315.  
  316. #else  /* ! STREAMSPTY */
  317.  
  318. /* I/O data buffers, pointers, and counters. */
  319.  
  320. char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  321. char ptyibuf2[BUFSIZ];
  322.  
  323. #endif /* ! STREAMSPTY */
  324.  
  325. #ifndef USE_TERMIO
  326. struct termbuf {
  327.     struct sgttyb sg;
  328.     struct tchars tc;
  329.     struct ltchars ltc;
  330.     int state;
  331.     int lflags;
  332. } termbuf, termbuf2;
  333.  
  334. #define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
  335. #define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
  336. #define cfgetospeed(tp)     (tp)->sg.sg_ospeed
  337. #define cfgetispeed(tp)     (tp)->sg.sg_ispeed
  338.  
  339. #else  /* USE_TERMIO */
  340.  
  341. #ifdef SYSV_TERMIO
  342. #define termios termio
  343. #endif /* SYSV_TERMIO */
  344.  
  345. #ifndef TCSANOW
  346.  
  347. #ifdef TCSETS
  348.  
  349. #define TCSANOW TCSETS
  350. #define TCSADRAIN TCSETSW
  351. #define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
  352.  
  353. #else /* TCSETS */
  354.  
  355. #ifdef TCSETA
  356. #define TCSANOW TCSETA
  357. #define TCSADRAIN TCSETAW
  358. #define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
  359. #else /* TCSETA */
  360. #define TCSANOW TIOCSETA
  361. #define TCSADRAIN TIOCSETAW
  362. #define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
  363. #endif /* TCSETA */
  364.  
  365. #endif /* TCSETS */
  366.  
  367. #define tcsetattr(f,a,t) ioctl(f,a,t)
  368. #define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
  369. #define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
  370.  
  371. #ifdef CIBAUD
  372. #define cfsetispeed(tp,val) \
  373.  (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
  374. #define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
  375. #else /* CIBAUD */
  376. #define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
  377. #define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
  378. #endif /* CIBAUD */
  379.  
  380. #endif /* TCSANOW */
  381.  
  382. struct termios termbuf, termbuf2;       /* pty control structure */
  383.  
  384. #ifdef INIT_SPTY
  385. static int spty = -1;
  386. #endif /* INIT_SPTY */
  387.  
  388. #endif /* USE_TERMIO */
  389.  
  390. static int msg = 0;
  391.  
  392. /* Variables available to other modules */
  393.  
  394. int pty_fork_active = 0;        /* pty fork is active */
  395. PID_T pty_fork_pid = -1;        /* pty fork pid */
  396. int pty_slave_fd = -1;            /* pty slave file descriptor */
  397. int pty_master_fd = -1;            /* pty master file descriptor */
  398.  
  399. /* termbuf routines (begin) */
  400. /*
  401.   init_termbuf()
  402.   copy_termbuf(cp)
  403.   set_termbuf()
  404.  
  405.   These three routines are used to get and set the "termbuf" structure
  406.   to and from the kernel.  init_termbuf() gets the current settings.
  407.   copy_termbuf() hands in a new "termbuf" to write to the kernel, and
  408.   set_termbuf() writes the structure into the kernel.
  409. */
  410. VOID
  411. init_termbuf(fd) int fd; {
  412.     int ttyfd;
  413.     int rc = 0;
  414.  
  415.     ttyfd = fd;
  416.  
  417. #ifdef HAVE_STREAMS
  418.     debug(F100,"init_termbuf HAVE_STREAMS","",0);
  419. #else
  420.     debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0);
  421. #endif    /* HAVE_STREAMS */
  422. #ifdef STREAMSPTY
  423.     debug(F100,"init_termbuf STREAMSPTY","",0);
  424. #else
  425.     debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0);
  426. #endif    /* STREAMSPTY */
  427. #ifdef INIT_SPTY
  428.     debug(F100,"init_termbuf INIT_SPTY","",0);
  429. #else
  430.     debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0);
  431. #endif    /* INIT_SPTY */
  432.  
  433.     debug(F101,"init_termbuf ttyfd","",ttyfd);
  434. #ifdef INIT_SPTY
  435.     debug(F101,"init_termbuf spty","",spty);
  436. #endif    /* INIT_SPTY */
  437.  
  438.     memset(&termbuf,0,sizeof(termbuf));
  439.     memset(&termbuf2,0,sizeof(termbuf2));
  440. #ifndef    USE_TERMIO
  441.     rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
  442.     rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
  443.     rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
  444. #ifdef TIOCGSTATE
  445.     rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
  446. #endif /* TIOCGSTATE */
  447. #else /* USE_TERMIO */
  448.     errno = 0;
  449. #ifdef INIT_SPTY
  450.     rc = tcgetattr(spty, &termbuf);
  451.     debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
  452. #else
  453.     rc = tcgetattr(ttyfd, &termbuf);
  454.     debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
  455. #endif /* INIT_SPTY */
  456. #endif /* USE_TERMIO */
  457.     if (!rc)
  458.       termbuf2 = termbuf;
  459. }
  460.  
  461. #ifdef TIOCPKT_IOCTL
  462. VOID
  463. copy_termbuf(cp, len) char *cp; int len; {
  464.     if (len > sizeof(termbuf))
  465.       len = sizeof(termbuf);
  466.     memcpy((char *)&termbuf, cp, len);
  467.     termbuf2 = termbuf;
  468. }
  469. #endif /* TIOCPKT_IOCTL */
  470.  
  471. VOID
  472. set_termbuf(fd) int fd; {        /* Only make the necessary changes. */
  473.     int x;
  474.     int ttyfd;
  475.     ttyfd = fd;
  476.  
  477.     debug(F101,"set_termbuf ttyfd","",ttyfd);
  478. #ifdef INIT_SPTY
  479.     debug(F101,"set_termbuf spty","",spty);
  480. #endif    /* INIT_SPTY */
  481.  
  482. #ifndef    USE_TERMIO
  483.     debug(F100,"set_termbuf USE_TERMIO","",0);
  484.     if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
  485.       ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
  486.     if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
  487.       ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
  488.     if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
  489.            sizeof(termbuf.ltc)))
  490.       ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
  491.     if (termbuf.lflags != termbuf2.lflags)
  492.       ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
  493. #else  /* USE_TERMIO */
  494.     x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf));
  495.     debug(F101,"set_termbuf !USE_TERMIO memcmp","",x);
  496.     x = 1;                /* Force this */
  497.     if (x) {
  498.     int x;
  499.     errno = 0;
  500. #ifdef INIT_SPTY
  501.     debug(F100,"set_termbuf INIT_SPTY","",0);
  502.     x = tcsetattr(spty, TCSANOW, &termbuf);
  503.     debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
  504. #else
  505.     debug(F100,"set_termbuf !INIT_SPTY","",0);
  506.     x = tcsetattr(ttyfd, TCSANOW, &termbuf);
  507.     debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
  508. #endif /* INIT_SPTY */
  509.     }
  510. #endif /* USE_TERMIO */
  511. }
  512. /* termbuf routines (end) */
  513.  
  514. VOID
  515. ptyint_vhangup() {
  516. #ifdef CK_VHANGUP
  517. #ifdef CK_POSIX_SIG
  518.     struct sigaction sa;
  519.     /* Initialize "sa" structure. */
  520.     sigemptyset(&sa.sa_mask);
  521.     sa.sa_flags = 0;
  522.     sa.sa_handler = SIG_IGN;
  523.     sigaction(SIGHUP, &sa, (struct sigaction *)0);
  524.     vhangup();
  525.     sa.sa_handler = SIG_DFL;
  526.     sigaction(SIGHUP, &sa, (struct sigaction *)0);
  527. #else /* CK_POSIX_SIG */
  528.     signal(SIGHUP,SIG_IGN);
  529.     vhangup();
  530.     signal(SIGHUP,SIG_DFL);
  531. #endif /* CK_POSIX_SIG */
  532. #endif /* CK_VHANGUP */
  533. }
  534.  
  535. /*
  536.   This routine is called twice.  It's not particularly important that the
  537.   setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
  538.   rather that we have a controlling terminal at the end.  It is assumed that
  539.   vhangup doesn't exist and confuse the process's notion of controlling
  540.   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
  541.   the controlling terminal in tact, breaks the association completely, or the
  542.   system provides TIOCNOTTY to get things back into a reasonable state.  In
  543.   practice, vhangup() either breaks the association completely or doesn't
  544.   effect controlling terminals, so this condition is met.
  545. */
  546. long
  547. ptyint_void_association() {
  548.     int con_fd;
  549. #ifdef HAVE_SETSID
  550.     debug(F110,
  551.       "ptyint_void_association()",
  552.       "setsid()",
  553.       0
  554.       );
  555.     setsid();
  556. #endif /* HAVE_SETSID */
  557.  
  558. #ifndef NO_DEVTTY
  559.     /* Void tty association first */
  560. #ifdef TIOCNOTTY
  561.     con_fd = open("/dev/tty", O_RDWR);
  562.     debug(F111,
  563.       "ptyint_void_association() open(/dev/tty,O_RDWR)",
  564.       "/dev/tty",
  565.       con_fd);
  566.     if (con_fd >= 0) {
  567.         ioctl(con_fd, TIOCNOTTY, 0);
  568.         close(con_fd);
  569.     }
  570. #ifdef DEBUG
  571.     else debug(F101, "ptyint_void_association() open() errno","",errno);
  572. #endif /* DEBUG */
  573. #endif /* TIOCNOTTY */
  574. #endif /* NO_DEVTTY */
  575.     return(0);
  576. }
  577.  
  578. /* PID may be zero for unknown.*/
  579.  
  580. long
  581. pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
  582. #ifdef VHANG_LAST
  583.     int retval, fd;
  584. #endif /* VHANG_LAST */
  585.  
  586.     debug(F111,"pty_cleanup()",slave,pid);
  587. #ifdef WANT_UTMP
  588.     if (update_utmp)
  589.       pty_update_utmp(PTY_DEAD_PROCESS,
  590.               0,
  591.               "",
  592.               slave,
  593.               (char *)0,
  594.               PTY_UTMP_USERNAME_VALID
  595.               );
  596. #endif /* WANT_UTMP */
  597.  
  598. #ifdef SETUID
  599.     chmod(slave, 0666);
  600.     chown(slave, 0, 0);
  601. #endif /* SETUID */
  602.  
  603. #ifdef HAVE_REVOKE
  604.     revoke(slave);
  605.     /*
  606.        Revoke isn't guaranteed to send a SIGHUP to the processes it
  607.        dissociates from the terminal.  The best solution without a Posix
  608.        mechanism for forcing a hangup is to killpg() the process group of the
  609.        pty.  This will at least kill the shell and hopefully, the child
  610.        processes.  This is not always the case, however.  If the shell puts
  611.        each job in a process group and doesn't pass along SIGHUP, all
  612.        processes may not die.
  613.     */
  614.     if (pid > 0) {
  615. #ifdef HAVE_KILLPG
  616.     killpg(pid, SIGHUP);
  617. #else
  618.     kill(-(pid), SIGHUP);
  619. #endif /*HAVE_KILLPG*/
  620.     }
  621. #else /* HAVE_REVOKE*/
  622. #ifdef VHANG_LAST
  623.     {
  624.         int status;
  625. #ifdef CK_POSIX_SIG
  626.         sigset_t old, new;
  627.         sigemptyset(&new);
  628.         sigaddset(&new, SIGCHLD);
  629.         sigprocmask(SIG_BLOCK, &new, &old);
  630. #else /*CK_POSIX_SIG*/
  631.         int mask = sigblock(sigmask(SIGCHLD));
  632. #endif /*CK_POSIX_SIG*/
  633.         switch (retval = fork()) {
  634.       case -1:
  635. #ifdef CK_POSIX_SIG
  636.             sigprocmask(SIG_SETMASK, &old, 0);
  637. #else /*CK_POSIX_SIG*/
  638.             sigsetmask(mask);
  639. #endif /*CK_POSIX_SIG*/
  640.             return errno;
  641.       case 0:
  642.             ptyint_void_association();
  643.             if (retval = (pty_open_ctty(slave, &fd, -1)))
  644.           exit(retval);
  645.             ptyint_vhangup();
  646.             exit(0);
  647.         break;
  648.       default:
  649. #ifdef HAVE_WAITPID
  650.             waitpid(retval, &status, 0);
  651. #else /*HAVE_WAITPID*/
  652.             wait(&status);
  653. #endif /* HAVE_WAITPID */
  654. #ifdef CK_POSIX_SIG
  655.             sigprocmask(SIG_SETMASK, &old, 0);
  656. #else /*CK_POSIX_SIG*/
  657.             sigsetmask(mask);
  658. #endif /*CK_POSIX_SIG*/
  659.             break;
  660.         }
  661.     }
  662. #endif /*VHANG_LAST*/
  663. #endif /* HAVE_REVOKE*/
  664. #ifndef HAVE_STREAMS
  665.     slave[strlen("/dev/")] = 'p';
  666. #ifdef SETUID
  667.     chmod(slave, 0666);
  668.     chown(slave, 0, 0);
  669. #endif /* SETUID */
  670. #endif /* HAVE_STREAMS */
  671.     return(0);
  672. }
  673.  
  674. long
  675. pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
  676.     char *cp;
  677.     char *p;
  678.     int i, ptynum;
  679.     struct stat stb;
  680. #ifndef HAVE_OPENPTY
  681. #ifndef HAVE__GETPTY
  682.     char slavebuf[1024];
  683. #endif /* HAVE__GETPTY */
  684. #endif /* HAVE_OPENPTY */
  685. #ifdef HAVE__GETPTY
  686.     char *slaveret;            /* Temp to hold pointer to slave */
  687. #endif /*HAVE__GETPTY*/
  688.  
  689. #ifdef HAVE_OPENPTY
  690.     int slavefd;
  691.  
  692.     pty_master_fd = -1;
  693.     debug(F100,"HAVE_OPENPTY","",0);
  694.     if (openpty(fd,
  695.         &slavefd,
  696.         slave,
  697.         (struct termios *)0,
  698.         (struct winsize *)0
  699.         )
  700.     ) {
  701.     pty_master_fd = *fd;
  702.     return(1);
  703.     }
  704.     close(slavefd);
  705.     return(0);
  706.  
  707. #else /* HAVE_OPENPTY */
  708.  
  709. #ifdef HAVE__GETPTY
  710. /*
  711.   This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
  712.   it fails to work properly; even after calling unlockpt, root gets permission
  713.   denied opening the pty.  The code to support _getpty should be removed if
  714.   Irix gets working streams ptys in favor of maintaining the least needed code
  715.   paths.
  716. */
  717.     debug(F100,"HAVE__GETPTY","",0);
  718.     if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
  719.     *fd = -1;
  720.     return(PTY_GETPTY_NOPTY);
  721.     }
  722.     if (strlen(slaveret) > slavelength - 1) {
  723.     close(*fd);
  724.     *fd = -1;
  725.     return(PTY_GETPTY_SLAVE_TOOLONG);
  726.     } else {
  727.     ckstrncpy(slave, slaveret, slavelength);
  728.     }
  729.     return(0);
  730.  
  731. #else /* HAVE__GETPTY */
  732.  
  733.     *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
  734.     if (*fd >= 0) {
  735.         debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
  736.         goto have_fd;
  737.     }
  738.  
  739. #ifdef HAVE_PTMX
  740.     debug(F100,"HAVE_PTMX","",0);
  741.     *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
  742.     if (*fd >= 0) {
  743.         debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
  744.         goto have_fd;
  745.     }
  746. #endif /* HAVE_PTMX */
  747.  
  748.     *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
  749.     if (*fd >= 0) {
  750.         debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
  751.         goto have_fd;
  752.     }
  753.     *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
  754.     if (*fd >= 0)
  755.         debug(F110,"pty_getpty()","open(/dev/pty) success",0);
  756.  
  757.   have_fd:
  758.     /* This would be the pty master */
  759.     debug(F101,"pty_getpty fd(A)","",*fd);
  760.     if (*fd >= 0) {
  761.     pty_master_fd = *fd;
  762.  
  763. #ifdef HAVE_GRANTPT
  764. #ifdef HAVE_PTMX
  765.         debug(F100,"HAVE_GRANTPT","",0);
  766.     if (grantpt(*fd) || unlockpt(*fd))
  767.       return(PTY_GETPTY_STREAMS);
  768. #endif /* HAVE_PTMX */
  769. #endif /* HAVE_GRANTPT */
  770.  
  771. #ifdef HAVE_PTSNAME
  772.         debug(F100,"HAVE_PTSNAME","",0);
  773.     p = (char *)ptsname(*fd);
  774.         debug(F110,"pty_getpty() ptsname()",p,0);
  775. #else
  776. #ifdef HAVE_TTYNAME
  777.         debug(F100,"HAVE_TTYNAME","",0);
  778.     p = ttyname(*fd);
  779.         debug(F110,"pty_getpty() ttyname()",p,0);
  780. #else
  781.     /* If we don't have either what do we do? */
  782.       return(PTY_GETPTY_NOPTY);    /* punt */
  783. #endif /* HAVE_TTYNAME */
  784. #endif /* HAVE_PTSNAME */
  785.     if (p) {
  786.         if (strlen(p) > slavelength - 1) {
  787.                 close (*fd);
  788.                 *fd = -1;
  789.                 return(PTY_GETPTY_SLAVE_TOOLONG);
  790.         }
  791.         ckstrncpy(slave, p, slavelength);
  792.         return(0);
  793.     }
  794.     if (fstat(*fd, &stb) < 0) {
  795.         close(*fd);
  796.         return(PTY_GETPTY_FSTAT);
  797.     }
  798.     ptynum = (int)(stb.st_rdev&0xFF);
  799.     sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
  800.     if (strlen(slavebuf) > slavelength - 1) {
  801.         close(*fd);
  802.         *fd = -1;
  803.         return(PTY_GETPTY_SLAVE_TOOLONG);
  804.     }
  805.         debug(F110,"pty_getpty() slavebuf",slavebuf,0);
  806.     ckstrncpy(slave, slavebuf, slavelength);
  807.     return(0);
  808.     } else {
  809.         for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
  810.         sprintf(slavebuf,"/dev/ptyXX"); /* safe */
  811.         slavebuf[sizeof("/dev/pty") - 1] = *cp;
  812.         slavebuf[sizeof("/dev/ptyp") - 1] = '0';
  813.         if (stat(slavebuf, &stb) < 0)
  814.           break;
  815.         for (i = 0; i < 16; i++) {
  816.         slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
  817.         errno = 0;
  818.         *fd = open(slavebuf, O_RDWR|O_NDELAY);
  819.         if (*fd < 0) {
  820.             debug(F111,"pty_getpty() pty master open error",
  821.               slavebuf,errno);
  822.             continue;
  823.         }
  824.                 debug(F111,"pty_getpty() found pty master",slavebuf,*fd);
  825.         slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
  826.         if (strlen(slavebuf) > slavelength -1) {
  827.             close(*fd);
  828.             *fd = -1;
  829.             return(PTY_GETPTY_SLAVE_TOOLONG);
  830.         }
  831.         ckstrncpy(slave, slavebuf, slavelength);
  832.                 debug(F110,"pty_getpty slave name",slave,0);
  833.         pty_master_fd = *fd;
  834.         return(0);
  835.         }
  836.     }
  837.     return(PTY_GETPTY_NOPTY);
  838.     }
  839. #endif /*HAVE__GETPTY*/
  840. #endif /* HAVE_OPENPTY */
  841. }
  842.  
  843. long
  844. pty_init() {
  845. #ifdef HAVE_PTYM
  846.     static char dummy;
  847.     debug(F100,"HAVE_PTYM","",0);
  848.     tty_bank =  &master_name[strlen("/dev/ptym/pty")];
  849.     tty_num  =  &master_name[strlen("/dev/ptym/ptyX")];
  850.     slave_bank = &slave_name[strlen("/dev/pty/tty")];
  851.     slave_num  = &slave_name[strlen("/dev/pty/ttyX")];
  852. #endif
  853.     return(0L);
  854. }
  855.  
  856. /*
  857.   The following is an array of modules that should be pushed on the stream.
  858.   See configure.in for caviats and notes about when this array is used and not
  859.   used.
  860. */
  861. #ifdef HAVE_STREAMS
  862. #ifndef HAVE_LINE_PUSH
  863. static char *push_list[] = {
  864. #ifdef PUSH_PTEM
  865.     "ptem",
  866. #endif
  867. #ifdef PUSH_LDTERM
  868.     "ldterm",
  869. #endif
  870. #ifdef PUSH_TTCOMPAT
  871.     "ttcompat",
  872. #endif
  873.     0
  874. };
  875. #endif /* HAVE_LINE_PUSH */
  876. #endif /* HAVE_STREAMS */
  877.  
  878. long
  879. pty_initialize_slave (fd) int fd; {
  880. #ifdef POSIX_TERMIOS
  881. #ifndef ultrix
  882.     struct termios new_termio;
  883. #else
  884.     struct sgttyb b;
  885. #endif /* ultrix */
  886. #else
  887.     struct sgttyb b;
  888. #endif /* POSIX_TERMIOS */
  889.     int pid;
  890. #ifdef POSIX_TERMIOS
  891. #ifndef ultrix
  892.     int rc;
  893. #endif /* ultrix */
  894. #endif /* POSIX_TERMIOS */
  895.  
  896.     debug(F111,"pty_initialize_slave()","fd",fd);
  897.  
  898. #ifdef HAVE_STREAMS
  899. #ifdef HAVE_LINE_PUSH
  900.     while (ioctl(fd,I_POP,0) == 0) ;    /* Clear out any old lined's */
  901.  
  902.     if (line_push(fd) < 0) {
  903.         debug(F110,"pty_initialize_slave()","line_push() failed",0);
  904.     close(fd);
  905.         fd = -1;
  906.         return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
  907.     }
  908. #else /*No line_push */
  909.     {
  910.         char **module = &push_list[0];
  911.         while (*module) {
  912.         if (ioctl(fd, I_PUSH, *(module++)) < 0) {
  913.                 debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
  914.         return(PTY_OPEN_SLAVE_PUSH_FAIL);
  915.         }
  916.     }
  917.     }
  918. #endif /*LINE_PUSH*/
  919. #endif /*HAVE_STREAMS*/
  920. /*
  921.   Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
  922.   explicitly.  Why rlogind works at all without this on 4.3BSD is a mystery.
  923. */
  924. #ifdef GETPGRP_ONEARG
  925.     pid = getpgrp(getpid());
  926. #else
  927.     pid = getpgrp();
  928. #endif /* GETPGRP_ONEARG */
  929.  
  930.     debug(F111,"pty_initialize_slave()","pid",pid);
  931.  
  932. #ifdef TIOCSPGRP
  933.     ioctl(fd, TIOCSPGRP, &pid);
  934. #endif /* TIOCSPGRP */
  935.  
  936. #ifdef POSIX_TERMIOS
  937. #ifndef ultrix
  938.     tcsetpgrp(fd, pid);
  939.     errno = 0;
  940.     rc = tcgetattr(fd,&new_termio);
  941.     debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
  942.     if (rc == 0) {
  943.     new_termio.c_cc[VMIN] = 1;
  944.     new_termio.c_cc[VTIME] = 0;
  945.     rc = tcsetattr(fd,TCSANOW,&new_termio);
  946.     debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
  947.     }
  948. #endif /* ultrix */
  949. #endif /* POSIX_TERMIOS */
  950.     return(0L);
  951. }
  952.  
  953. #ifdef WANT_UTMP
  954. long
  955. pty_logwtmp (tty, user, host) char *user, *tty, *host; {
  956. #ifdef HAVE_LOGWTMP
  957.     logwtmp(tty,user,host);
  958.     return(0);
  959. #else
  960.     struct utmp ut;
  961.     char *tmpx;
  962.     char utmp_id[5];
  963.     int loggingin = user[0];        /* Will be empty for logout */
  964.  
  965. #ifndef NO_UT_HOST
  966.     strncpy(ut.ut_host, host, sizeof(ut.ut_host));
  967. #endif /* NO_UT_HOST */
  968.  
  969.     strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
  970.     ut.ut_time = time(0);
  971.  
  972. #ifndef NO_UT_PID
  973.     ut.ut_pid = getpid();
  974.     strncpy(ut.ut_user, user, sizeof(ut.ut_user));
  975.  
  976.     tmpx = tty + strlen(tty) - 2;
  977.     ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
  978.     strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
  979.     ut.ut_pid = (loggingin ? getpid() : 0);
  980.     ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
  981. #else
  982.     strncpy(ut.ut_name, user, sizeof(ut.ut_name));
  983. #endif /* NO_UT_PID */
  984.  
  985.     return(ptyint_update_wtmp(&ut, host, user));
  986.  
  987. #endif /* HAVE_LOGWTMP */
  988. }
  989. #endif /* WANT_UTMP */
  990.  
  991. /*
  992.   This routine is called twice.  It's not particularly important that the
  993.   setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but
  994.   rather that we have a controlling terminal at the end.  It is assumed that
  995.   vhangup doesn't exist and confuse the process's notion of controlling
  996.   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
  997.   the controlling terminal in tact, breaks the association completely, or the
  998.   system provides TIOCNOTTY to get things back into a reasonable state.  In
  999.   practice, vhangup() either breaks the association completely or doesn't
  1000.   effect controlling terminals, so this condition is met.
  1001. */
  1002. long
  1003. pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; {
  1004.     int retval;
  1005.  
  1006.     debug(F110,"pty_open_ctty() slave",slave,0);
  1007.  
  1008. /* First, dissociate from previous terminal */
  1009.  
  1010.     if ((retval = ptyint_void_association()) != 0) {
  1011.         debug(F111,
  1012.           "pty_open_ctty()",
  1013.           "ptyint_void_association() failed",
  1014.           retval
  1015.           );
  1016.     return(retval);
  1017.     }
  1018. #ifdef MUST_SETPGRP
  1019. /*
  1020.   The Ultrix (and other BSD tty drivers) require the process group
  1021.   to be zero in order to acquire the new tty as a controlling tty.
  1022. */
  1023.     setpgrp(0,0);
  1024.     debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno);
  1025. #endif /* MUST_SETPGRP */
  1026.  
  1027.     errno = 0;
  1028.     *fd = open(slave, O_RDWR);
  1029.     debug(F111,"pty_open_ctty open(slave) fd",slave,*fd);
  1030.     if (*fd < 0) {
  1031.     debug(F111,"pty_open_ctty() open failure", slave, errno);
  1032.     return(PTY_OPEN_SLAVE_OPENFAIL);
  1033.     }
  1034. #ifdef SOLARIS
  1035.     /* This forces the job to have a controlling terminal. */
  1036.     close(*fd);
  1037.     *fd = open(slave, O_RDWR);
  1038.     debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd);
  1039. #ifdef DEBUG
  1040.     /* This shows that /dev/tty exists */
  1041. if (deblog) {
  1042.     int x;
  1043.     x = open("/dev/tty", O_RDWR);
  1044.     debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x);
  1045.     if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno);
  1046.     debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0);
  1047.     if (x > -1) close(x);
  1048.     }
  1049. #endif    /* DEBUG */
  1050. #endif /* SOLARIS */
  1051.  
  1052. #ifdef MUST_SETPGRP
  1053.     setpgrp(0, getpid());
  1054. #endif /* MUST_SETPGRP */
  1055.  
  1056. #ifdef TIOCSCTTY
  1057.     if (
  1058. #ifdef COMMENT
  1059.     fc == 0
  1060. #else
  1061.     1
  1062. #endif    /* COMMENT */
  1063.     ) {
  1064.     /* TIOCSCTTY = Make this the job's controlling terminal */
  1065.     errno = 0;
  1066.     retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
  1067.     debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
  1068.     }
  1069. #endif /* TIOCSCTTY */
  1070.     return(0L);
  1071. }
  1072.  
  1073. long
  1074. pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; {
  1075.     int vfd, testfd;
  1076.     long retval;
  1077. #ifdef CK_POSIX_SIG
  1078.     struct sigaction sa;
  1079.  
  1080.     sigemptyset(&sa.sa_mask);        /* Initialize "sa" structure. */
  1081.     sa.sa_flags = 0;
  1082. #endif /* CK_POSIX_SIG */
  1083.  
  1084. /*
  1085.   First, chmod and chown the slave.  If we have vhangup then we really need
  1086.   pty_open_ctty to make sure our controlling terminal is the pty we're
  1087.   opening.  However, if we are using revoke or nothing then we just need a
  1088.   file descriiptor for the pty.  Considering some OSes in this category break
  1089.   on the second call to open_ctty (currently OSF but others may), we simply
  1090.   use a descriptor if we can.
  1091. */
  1092. #ifdef VHANG_FIRST
  1093.     if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) {
  1094.         debug(F111,
  1095.           "pty_open_slave() VHANG_FIRST",
  1096.           "pty_open_ctty() failed",
  1097.           retval
  1098.           );
  1099.         return(retval);
  1100.     }
  1101.     if (vfd < 0) {
  1102.         debug(F111,
  1103.           "pty_open_slave() VHANG_FIRST",
  1104.           "PTY_OPEN_SLAVE_OPENFAIL",
  1105.           vfd
  1106.           );
  1107.     return(PTY_OPEN_SLAVE_OPENFAIL);
  1108.     }
  1109. #endif /* VHANG_FIRST */
  1110.  
  1111.     if (slave == NULL || *slave == '\0') {
  1112.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
  1113.         return(PTY_OPEN_SLAVE_TOOSHORT);
  1114.     }
  1115.  
  1116. #ifdef SETUID
  1117.     if (chmod(slave, 0)) {
  1118.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
  1119.         return(PTY_OPEN_SLAVE_CHMODFAIL);
  1120.     }
  1121.     if (chown(slave, 0, 0 ) == -1 ) {
  1122.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
  1123.         return(PTY_OPEN_SLAVE_CHOWNFAIL);
  1124.     }
  1125. #endif /* SETUID */
  1126. #ifdef VHANG_FIRST
  1127.     ptyint_vhangup();
  1128.     close(vfd);
  1129. #endif /* VHANG_FIRST */
  1130.  
  1131.     if ((retval = ptyint_void_association()) != 0) {
  1132.         debug(F111,
  1133.           "pty_open_slave()",
  1134.           "ptyint_void_association() failed",
  1135.           retval
  1136.           );
  1137.         return(retval);
  1138.     }
  1139.  
  1140. #ifdef HAVE_REVOKE
  1141.     if (revoke (slave) < 0 ) {
  1142.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
  1143.     return(PTY_OPEN_SLAVE_REVOKEFAIL);
  1144.     }
  1145. #endif /* HAVE_REVOKE */
  1146.  
  1147. /* Open the pty for real. */
  1148.  
  1149.     retval = pty_open_ctty(slave, fd, fc);
  1150.     debug(F111,"pty_open_slave retval",slave,retval);
  1151.     debug(F111,"pty_open_slave fd",slave,*fd);
  1152.     if (retval != 0) {
  1153.         debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
  1154.     return(PTY_OPEN_SLAVE_OPENFAIL);
  1155.     }
  1156.     pty_slave_fd = *fd;           /* This is not visible to the upper fork */
  1157.     debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd);
  1158.     retval = pty_initialize_slave(*fd);
  1159.     debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd);
  1160.     if (retval) {
  1161.         debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
  1162.         return(retval);
  1163.     }
  1164.     /* (VOID)pty_make_raw(*fd); */
  1165.  
  1166.     debug(F100,"pty_open_slave OK","",*fd);
  1167.     return(0L);
  1168. }
  1169.  
  1170. #ifdef WANT_UTMP
  1171.  
  1172. #ifndef UTMP_FILE
  1173. #ifdef _PATH_UTMP
  1174. #define UTMP_FILE _PATH_UTMP
  1175. #endif /* _PATH_UTMP */
  1176. #endif /*  UTMP_FILE */
  1177.  
  1178. /* If it is *still* missing, assume /etc/utmp */
  1179.  
  1180. #ifndef UTMP_FILE
  1181. #define    UTMP_FILE "/etc/utmp"
  1182. #endif /* UTMP_FILE */
  1183.  
  1184. #ifndef NO_UT_PID
  1185. #define WTMP_REQUIRES_USERNAME
  1186. #endif /* NO_UT_PID */
  1187.  
  1188. long
  1189. pty_update_utmp(process_type, pid, username, line, host, flags)
  1190.     int process_type;
  1191.     int pid;
  1192.     char *username, *line, *host;
  1193.     int flags;
  1194. /* pty_update_utmp */ {
  1195.     struct utmp ent, ut;
  1196. #ifndef HAVE_SETUTENT
  1197.     struct stat statb;
  1198.     int tty;
  1199. #endif /* HAVE_SETUTENT */
  1200. #ifdef HAVE_SETUTXENT
  1201.     struct utmpx utx;
  1202. #endif /* HAVE_SETUTXENT */
  1203. #ifndef NO_UT_PID
  1204.     char *tmpx;
  1205.     char utmp_id[5];
  1206. #endif /* NO_UT_PID */
  1207.     char userbuf[32];
  1208.     int fd;
  1209.  
  1210.     debug(F100,"pty_update_utmp()","",0);
  1211.     strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
  1212.     ent.ut_time = time(0);
  1213.  
  1214. #ifdef NO_UT_PID
  1215.     if (process_type == PTY_LOGIN_PROCESS)
  1216.       return(0L);
  1217. #else /* NO_UT_PID */
  1218.  
  1219.     ent.ut_pid = pid;
  1220.  
  1221.     switch (process_type) {
  1222.       case PTY_LOGIN_PROCESS:
  1223.     ent.ut_type = LOGIN_PROCESS;
  1224.     break;
  1225.       case PTY_USER_PROCESS:
  1226.     ent.ut_type = USER_PROCESS;
  1227.     break;
  1228.       case PTY_DEAD_PROCESS:
  1229.     ent.ut_type = DEAD_PROCESS;
  1230.     break;
  1231.       default:
  1232.     return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
  1233.     }
  1234. #endif /*NO_UT_PID*/
  1235.  
  1236. #ifndef NO_UT_HOST
  1237.     if (host)
  1238.       strncpy(ent.ut_host, host, sizeof(ent.ut_host));
  1239.     else
  1240.       ent.ut_host[0] = '\0';
  1241. #endif /* NO_UT_HOST */
  1242.  
  1243. #ifndef NO_UT_PID
  1244.     if (!strcmp (line, "/dev/console")) {
  1245.     char * s = NULL;
  1246.  
  1247. #ifdef sun
  1248. #ifdef __SVR4
  1249.     s = "co";
  1250. #else
  1251.     s = "cons";
  1252. #endif /* __SVR4 */
  1253. #else
  1254.     s = "cons";
  1255. #endif /* sun */
  1256.  
  1257.     strncpy(ent.ut_id, s, 4);
  1258.  
  1259.     } else {
  1260.  
  1261.     tmpx = line + strlen(line)-1;
  1262.     if (*(tmpx-1) != '/') tmpx--;    /* last 2 chars unless it's a '/' */
  1263. #ifdef __hpux
  1264.     ckstrncpy(utmp_id, tmpx, 5);
  1265. #else
  1266.     ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
  1267. #endif /* __hpux */
  1268.     strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
  1269.     }
  1270.     strncpy(ent.ut_user, username, sizeof(ent.ut_user));
  1271.  
  1272. #else
  1273.  
  1274.     strncpy(ent.ut_name, username, sizeof(ent.ut_name));
  1275.  
  1276. #endif /* NO_UT_PID */
  1277.  
  1278.     if (username[0])
  1279.       strncpy(userbuf, username, sizeof(userbuf));
  1280.     else
  1281.       userbuf[0] = '\0';
  1282.  
  1283. #ifdef HAVE_SETUTENT
  1284.  
  1285.     utmpname(UTMP_FILE);
  1286.     setutent();
  1287. /*
  1288.   If we need to preserve the user name in the wtmp structure and Our flags
  1289.   tell us we can obtain it from the utmp and we succeed in obtaining it, we
  1290.   then save the utmp structure we obtain, write out the utmp structure and
  1291.   change the username pointer so it is used by update_wtmp.
  1292. */
  1293.  
  1294. #ifdef WTMP_REQUIRES_USERNAME
  1295.     if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
  1296.     struct utmp *utptr;
  1297.     strncpy(ut.ut_line, line, sizeof(ut.ut_line));
  1298.     utptr = getutline(&ut);
  1299.     if (utptr)
  1300.       strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
  1301.     }
  1302. #endif /* WTMP_REQUIRES_USERNAME */
  1303.  
  1304.     pututline(&ent);
  1305.     endutent();
  1306.  
  1307. #ifdef HAVE_SETUTXENT
  1308.     setutxent();
  1309. #ifdef HAVE_GETUTMPX
  1310.     getutmpx(&ent, &utx);
  1311. #else /* HAVE_GETUTMPX */
  1312.     /* For platforms like HPUX and Dec Unix which don't have getutmpx */
  1313.     strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
  1314.     strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
  1315.     strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
  1316.     utx.ut_pid = pid;        /* kludge for Irix, etc. to avoid trunc. */
  1317.     utx.ut_type = ent.ut_type;
  1318. #ifdef UT_EXIT_STRUCTURE_DIFFER
  1319.     utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
  1320. #else /* UT_EXIT_STRUCTURE_DIFFER */
  1321. /* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
  1322. #ifdef __hpux
  1323.     utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
  1324.     utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
  1325. #else /* __hpux */
  1326.     /* XXX do nothing for now; we don't even know the struct member exists */
  1327. #endif /* __hpux */
  1328. #endif /* UT_EXIT_STRUCTURE_DIFFER */
  1329.     utx.ut_tv.tv_sec = ent.ut_time;
  1330.     utx.ut_tv.tv_usec = 0;
  1331. #endif /* HAVE_GETUTMPX */
  1332.     if (host)
  1333.       strncpy(utx.ut_host, host, sizeof(utx.ut_host));
  1334.     else
  1335.       utx.ut_host[0] = 0;
  1336.     pututxline(&utx);
  1337.     endutxent();
  1338. #endif /* HAVE_SETUTXENT */
  1339.  
  1340. #else /* HAVE_SETUTENT */
  1341.     if (flags&PTY_TTYSLOT_USABLE) {
  1342.     tty = ttyslot();
  1343.     } else {
  1344.     int lc;
  1345.     tty = -1;
  1346.     if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
  1347.       return(errno);
  1348.     for (lc = 0;
  1349.          lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
  1350.          lc++
  1351.          ) {
  1352.         if (read(fd,
  1353.              (char *)&ut,
  1354.              sizeof(struct utmp)
  1355.              ) != sizeof(struct utmp)
  1356.         )
  1357.           break;
  1358.         if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
  1359.         tty = lc;
  1360. #ifdef WTMP_REQUIRES_USERNAME
  1361.         if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
  1362.           strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
  1363. #endif /* WTMP_REQUIRES_USERNAME */
  1364.         break;
  1365.         }
  1366.     }
  1367.     close(fd);
  1368.     }
  1369.     if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
  1370.     lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
  1371.     write(fd, (char *)&ent, sizeof(struct utmp));
  1372.     close(fd);
  1373.     }
  1374. #endif /* HAVE_SETUTENT */
  1375.  
  1376.     /* Don't record LOGIN_PROCESS entries. */
  1377.     if (process_type == PTY_LOGIN_PROCESS)
  1378.       return(0);
  1379.     else
  1380.       return(ptyint_update_wtmp(&ent, host, userbuf));
  1381. }
  1382. #ifndef WTMP_FILE
  1383. #ifdef _PATH_WTMP
  1384. #define WTMP_FILE _PATH_WTMP
  1385. #endif /* _PATH_WTMP */
  1386. #endif /* WTMP_FILE */
  1387.  
  1388. #ifndef WTMPX_FILE
  1389. #ifdef _PATH_WTMPX
  1390. #ifdef HAVE_UPDWTMPX
  1391. #define WTMPX_FILE _PATH_WTMPX
  1392. #endif /* HAVE_UPDWTMPX */
  1393. #endif /* _PATH_WTMPX */
  1394. #endif /* WTMPX_FILE */
  1395.  
  1396. /* If it is *still* missing, assume /usr/adm/wtmp */
  1397.  
  1398. #ifndef WTMP_FILE
  1399. #define    WTMP_FILE "/usr/adm/wtmp"
  1400. #endif /* WTMP_FILE */
  1401.  
  1402. #ifdef COMMENT
  1403. /* The following test can not be made portably */
  1404.  
  1405. /* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
  1406. /*
  1407.   This is ugly, but the lack of standardization in the utmp/utmpx space, and
  1408.   what glibc implements and doesn't make available, is even worse.
  1409. */
  1410. /* #undef HAVE_UPDWTMPX */    /* Don't use updwtmpx for glibc 2.1 */
  1411. /* #endif */ /* __GLIBC__ etc */
  1412.  
  1413. #else  /* COMMENT */
  1414.  
  1415. #ifdef __GLIBC__
  1416. #undef HAVE_UPDWTMPX        /* Don't use updwtmpx for glibc period */
  1417. #endif /* __GLIBC__ */
  1418. #endif /* COMMENT */
  1419.  
  1420. long
  1421. ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
  1422.     struct utmp ut;
  1423.     struct stat statb;
  1424.     int fd;
  1425.     time_t uttime;
  1426. #ifdef HAVE_UPDWTMPX
  1427.     struct utmpx utx;
  1428.  
  1429.     getutmpx(ent, &utx);
  1430.     if (host)
  1431.       strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
  1432.     else
  1433.       utx.ut_host[0] = 0;
  1434.     if (user)
  1435.       strncpy(utx.ut_user, user, sizeof(utx.ut_user));
  1436.     updwtmpx(WTMPX_FILE, &utx);
  1437. #endif /* HAVE_UPDWTMPX */
  1438.  
  1439. #ifdef HAVE_UPDWTMP
  1440. #ifndef HAVE_UPDWTMPX
  1441.     /* This is already performed byupdwtmpx if present.*/
  1442.     updwtmp(WTMP_FILE, ent);
  1443. #endif /* HAVE_UPDWTMPX*/
  1444. #else /* HAVE_UPDWTMP */
  1445.  
  1446.     if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
  1447.     if (!fstat(fd, &statb)) {
  1448.         memset((char *)&ut, 0, sizeof(ut));
  1449. #ifdef __hpux
  1450.         strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
  1451. #endif /* __hpux */
  1452.         strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
  1453.         strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
  1454. #ifndef NO_UT_HOST
  1455.         strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
  1456. #endif /* NO_UT_HOST */
  1457.  
  1458.         time(&uttime);
  1459.         ut.ut_time = uttime;
  1460.  
  1461. #ifdef HAVE_GETUTENT
  1462. #ifdef USER_PROCESS
  1463.         if (ent->ut_name) {
  1464.         if (!ut.ut_pid)
  1465.           ut.ut_pid = getpid();
  1466. #ifndef __hpux
  1467.         ut.ut_type = USER_PROCESS;
  1468. #else  /* __hpux */
  1469.         ut.ut_type = ent->ut_type;
  1470. #endif /* __hpux */
  1471.  
  1472.         } else {
  1473.  
  1474. #ifdef EMPTY
  1475.         ut.ut_type = EMPTY;
  1476. #else
  1477.         ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
  1478. #endif /* EMPTY */
  1479.  
  1480.         }
  1481. #endif /* USER_PROCESS */
  1482. #endif /* HAVE_GETUTENT */
  1483.  
  1484.         if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
  1485.         sizeof(struct utmp))
  1486. #ifndef COHERENT
  1487.           ftruncate(fd, statb.st_size);
  1488. #else
  1489.           chsize(fd, statb.st_size);
  1490. #endif /* COHERENT */
  1491.     }
  1492.     close(fd);
  1493.     }
  1494. #endif /* HAVE_UPDWTMP */
  1495.     return(0); /* no current failure cases; file not found is not failure! */
  1496. }
  1497. #endif /* WANT_UTMP */
  1498.  
  1499. /* This is for ancient Unixes that don't have these tty symbols defined. */
  1500.  
  1501. #ifndef PENDIN
  1502. #define PENDIN ICANON
  1503. #endif /* PENDIN */
  1504. #ifndef FLUSHO
  1505. #define FLUSHO ICANON
  1506. #endif /* FLUSHO */
  1507. #ifndef IMAXBEL
  1508. #define IMAXBEL ICANON
  1509. #endif /* IMAXBEL */
  1510. #ifndef EXTPROC
  1511. #define EXTPROC ICANON
  1512. #endif /* EXTPROC */
  1513.  
  1514. static char Xline[17] = { 0, 0 };
  1515. /*
  1516.   getptyslave()
  1517.   Open the slave side of the pty, and do any initialization that is necessary.
  1518.   The return value fd is a file descriptor for the slave side.
  1519.   fc = function code from do_pty() (q.v.)
  1520. */
  1521. int
  1522. getptyslave(fd, fc) int * fd, fc; {
  1523.     int ttyfd;
  1524.     int t = -1;
  1525.     long retval;
  1526. #ifdef TIOCGWINSZ
  1527.     struct winsize ws;
  1528.     extern int cmd_rows, cmd_cols;
  1529. #endif /* TIOCGWINSZ */
  1530.  
  1531.     ttyfd = *fd;
  1532.     debug(F111,"getptyslave()","ttyfd",ttyfd);
  1533.     /*
  1534.      * Opening the slave side may cause initilization of the
  1535.      * kernel tty structure.  We need remember the state of:
  1536.      *      if linemode was turned on
  1537.      *      terminal window size
  1538.      *      terminal speed
  1539.      * so that we can reset them if we need to.
  1540.      */
  1541.     if ((retval = pty_open_slave(Xline, &t, fc)) != 0) {
  1542.     perror(Xline);
  1543.     msg++;
  1544.         debug(F111,"getptyslave()","Unable to open slave",retval);
  1545.         return(-1);
  1546.     }
  1547.     debug(F111,"getptyslave","t",t);
  1548. #ifdef INIT_SPTY
  1549.     spty = t;
  1550.     debug(F111,"getptyslave","spty",spty);
  1551. #endif /* INIT_SPTY */
  1552. #ifdef STREAMSPTY
  1553.     if (ioctl(t,I_PUSH,"pckt") < 0) {
  1554.         debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
  1555. #ifndef _AIX
  1556.         fatal("I_PUSH pckt");
  1557. #endif /* _AIX */
  1558.     }
  1559. #endif /* STREAMSPTY */
  1560.  
  1561.     /* Set up the tty modes as we like them to be. */
  1562. #ifdef COMMENT
  1563.     /* Originally like this... But this is the master - we want the slave */
  1564.     /* Anyway, this fails on Solaris and probably other System V OS's */
  1565.     init_termbuf(ttyfd);
  1566. #else
  1567.     init_termbuf(t);
  1568. #endif    /* COMMENT */
  1569. #ifdef TIOCGWINSZ
  1570.     if (cmd_rows || cmd_cols) {
  1571.         memset((char *)&ws, 0, sizeof(ws));
  1572.         ws.ws_col = cmd_cols;
  1573.         ws.ws_row = cmd_rows;
  1574.     debug(F101,"getptyslave() doing TIOCSWINSZ...","",t);
  1575.         ioctl(t, TIOCSWINSZ, (char *)&ws);
  1576.     }
  1577. #endif /* TIOCGWINSZ */
  1578.  
  1579.     /* For external protocols, put the pty in no-echo mode */
  1580.     if (fc == 1) {
  1581.     debug(F100,"getptyslave() setting rawmode","",0);
  1582.     /* iflags */
  1583.     termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
  1584.     termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF);
  1585.     termbuf.c_iflag |= IGNBRK;
  1586. #ifdef IUCLC
  1587.     termbuf.c_iflag &= ~IUCLC;
  1588. #endif /* IUCLC */
  1589.  
  1590.     /* oflags */
  1591.     termbuf.c_oflag &= ~OPOST;
  1592. #ifdef OXTABS
  1593.     termbuf.c_oflag &= ~OXTABS;
  1594. #endif /* OXTABS */
  1595. #ifdef ONOCR
  1596.     termbuf.c_oflag &= ~ONOCR;
  1597. #endif /* ONOCR */
  1598. #ifdef ONLRET
  1599.     termbuf.c_oflag &= ~ONLRET;
  1600. #endif /* ONLRET */
  1601. #ifdef ONLCR
  1602.     termbuf.c_oflag &= ~ONLCR;
  1603. #endif /* ONLCR */
  1604.  
  1605.     /* lflags */
  1606.     termbuf.c_lflag &= ~ECHO;
  1607. #ifdef ECHOE
  1608.     termbuf.c_lflag &= ~ECHOE;
  1609. #endif /* ECHOE */
  1610. #ifdef ECHONL
  1611.     termbuf.c_lflag &= ~ECHONL;
  1612. #endif /* ECHONL */
  1613. #ifdef ECHOPRT
  1614.     termbuf.c_lflag &= ~ECHOPRT;
  1615. #endif /* ECHOPRT */
  1616. #ifdef ECHOKE
  1617.     termbuf.c_lflag &= ~ECHOKE;
  1618. #endif /* ECHOKE */
  1619. #ifdef ECHOCTL
  1620.     termbuf.c_lflag &= ~ECHOCTL;
  1621. #endif /* ECHOCTL */
  1622. #ifdef ALTWERASE
  1623.     termbuf.c_lflag &= ~ALTWERASE;
  1624. #endif /* ALTWERASE */
  1625. #ifdef EXTPROC
  1626.     termbuf.c_lflag &= ~EXTPROC;
  1627. #endif /* EXTPROC */
  1628.     termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
  1629.  
  1630. #ifdef NOKERNINFO
  1631.     termbuf.c_lflag |= NOKERNINFO;
  1632. #endif    /* NOKERNINFO */
  1633.     /* termbuf.c_lflag |= NOFLSH; */
  1634.     termbuf.c_lflag &= ~NOFLSH;
  1635.  
  1636.     /* cflags */
  1637.     termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD);
  1638.     termbuf.c_cflag |= CS8|CREAD;
  1639. #ifdef VMIN
  1640.     termbuf.c_cc[VMIN] = 1;
  1641. #endif    /* VMIN */
  1642.     } else {                /* Regular interactive use */
  1643.     debug(F100,"getptyslave() setting cooked mode","",0);
  1644.  
  1645.     /* Settings for sgtty based systems */
  1646.  
  1647. #ifndef USE_TERMIO
  1648.     termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
  1649. #endif /* USE_TERMIO */
  1650.  
  1651. #ifndef OXTABS
  1652. #define OXTABS 0
  1653. #endif /* OXTABS */
  1654.  
  1655.     /* Settings for UNICOS and HPUX */
  1656.  
  1657. #ifdef CRAY
  1658.     termbuf.c_oflag = OPOST|ONLCR|TAB3;
  1659.     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
  1660.     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  1661.     termbuf.c_cflag = EXTB|HUPCL|CS8;
  1662. #else /* CRAY */
  1663. #ifdef HPUX
  1664.     termbuf.c_oflag = OPOST|ONLCR|TAB3;
  1665.     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
  1666.     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  1667.     termbuf.c_cflag = EXTB|HUPCL|CS8;
  1668. #else /* HPUX */
  1669. #ifdef USE_TERMIO
  1670.     /*
  1671.       Settings for all other termios/termio based systems, other than 
  1672.       4.4BSD.  In 4.4BSD the kernel does the initial terminal setup.
  1673.     */
  1674. #ifdef BSD42
  1675. #ifndef BSD44
  1676.     termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
  1677.     termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
  1678.     termbuf.c_iflag |= ICRNL|IGNPAR;
  1679.     termbuf.c_cflag |= HUPCL;
  1680.     termbuf.c_iflag &= ~IXOFF;
  1681. #endif /* BSD44 */
  1682. #else /* BSD42 */
  1683.     termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
  1684.     termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
  1685.     termbuf.c_iflag |= ICRNL|IGNPAR;
  1686.     termbuf.c_cflag |= HUPCL;
  1687.     termbuf.c_iflag &= ~IXOFF;
  1688. #endif /* BSD42 */
  1689. #endif /* USE_TERMIO */
  1690. #endif /* HPUX */
  1691. #endif /* CRAY */
  1692.     }
  1693.  
  1694.     /* Set the tty modes, and make this our controlling tty. */
  1695. #ifdef COMMENT
  1696.     /* But this is the master - we want the slave */
  1697.     set_termbuf(ttyfd);
  1698. #else
  1699.     set_termbuf(t);
  1700. #endif    /* COMMENT */
  1701.  
  1702.     if (t != 0)
  1703.       dup2(t, 0);
  1704.     if (t != 1)
  1705.       dup2(t, 1);
  1706.     if (t != 2) {
  1707.     if (fc == 0) {
  1708.         dup2(t, 2);
  1709.     } else if (fc == 1) {
  1710.         /* For external protocols, send stderr to /dev/null */
  1711. #ifdef COMMENT
  1712.         int xx;
  1713. #ifndef COMMENT
  1714.         char * s = "/dev/null";
  1715.         errno = 0;
  1716.         xx = open(s, O_WRONLY);
  1717. #else
  1718.         char * s = "pty.log";
  1719.         errno = 0;
  1720.         xx = open(s, O_CREAT, 0644);
  1721. #endif /* COMMENT */
  1722.         debug(F111,"getptyslave redirect stderr",s,errno);
  1723.         dup2(xx,2);
  1724. #endif    /* COMMENT */
  1725.     }
  1726.     }
  1727.     if (t > 2)
  1728.       close(t);
  1729.  
  1730.     if (ttyfd > 2) {
  1731.     close(ttyfd);
  1732.         ttyfd = -1;
  1733.     *fd = ttyfd;
  1734.     }
  1735.     return(0);
  1736. }
  1737.  
  1738. #ifdef HAVE_PTYTRAP
  1739. /*
  1740.   To be called to determine if a trap is pending on a pty
  1741.   if and only if select() cannot be used.
  1742. */
  1743. int
  1744. pty_trap_pending(fd) int fd; {
  1745.     int pending;
  1746.     int rc;
  1747.  
  1748.     rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
  1749.     if (rc == 0) {
  1750.         debug(F101,"pty_trap_pending()","",pending);
  1751.         return(pending);
  1752.     } else {
  1753.         debug(F111,"pty_trap_pending()","ioctl() failed",rc);
  1754.         return(-1);
  1755.     }
  1756. }
  1757.  
  1758. /*
  1759.   To be called after select() has returned indicating that an exception is
  1760.   waiting on a pty.  It should be called with the file descriptor of the pty.
  1761.   Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
  1762. */
  1763. int
  1764. pty_trap_handler(fd) int fd; {
  1765.     struct request_info ri;
  1766.  
  1767.     memset(&ri,0,sizeof(ri));
  1768.     if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
  1769.         debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
  1770.         return(-1);
  1771.     }
  1772.     switch (ri.request) {
  1773.       case TIOCOPEN:
  1774.         debug(F110,"pty_trap_handler()","an open() call",0);
  1775.         break;
  1776.       case TIOCCLOSE:
  1777.         debug(F110,"pty_trap_handler()","a close() call",0);
  1778.         break;
  1779.       default:
  1780.         debug(F110,"pty_trap_handler()","an ioctl() call",0);
  1781.         ri.errno_error = EINVAL;
  1782.     }
  1783.     if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
  1784.         debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
  1785.         return(-1);
  1786.     }
  1787.     if (ri.request == TIOCCLOSE)
  1788.       return(1);
  1789.     else
  1790.       return(0);
  1791. }
  1792. #endif /* HAVE_PTYTRAP */
  1793.  
  1794. VOID
  1795. exec_cmd(s) char * s; {
  1796.     struct stringarray * q;
  1797.     char ** args = NULL;
  1798.  
  1799.     if (!s) return;
  1800.     if (!*s) return;
  1801.  
  1802.     q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
  1803.     if (!q) return;
  1804.  
  1805.     args = q->a_head + 1;
  1806.  
  1807. #ifdef DEBUG    
  1808.     {
  1809.     int i, n;
  1810.     n = q->a_size;
  1811.     for (i = 0; i <= n; i++) {
  1812.         if (!args[i]) {
  1813.         debug(F111,"exec_cmd arg","NULL",i);
  1814.         break;
  1815.         } else {
  1816.         debug(F111,"exec_cmd arg",args[i],i);
  1817.         if (i == n && args[i]) {
  1818.             debug(F101,"exec_cmd SUBSTITUTING NULL","",i);
  1819.             if (strlen(args[i]) == 0)
  1820.               makestr(&(args[i]),NULL);
  1821.         }
  1822.  
  1823.         }
  1824.     }        
  1825.     }
  1826. #endif    /* DEBUG */
  1827.  
  1828.     execvp(args[0],args);
  1829. }
  1830.  
  1831. /* Get a pty, scan input lines. */
  1832. /* fc = 0 for interactive access; fc = 1 for running external protocols */
  1833.  
  1834. static int pty_fc = -1;            /* Global copy of fc */
  1835.  
  1836. int
  1837. do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; {
  1838.     long retval;
  1839.     int syncpipe[2];
  1840.     int i, ttyfd;
  1841. #ifdef HAVE_PTYTRAP
  1842.     int x;
  1843. #endif /* HAVE_PTYTRAP */
  1844.  
  1845.     debug(F101,"CKUPTY.C do_pty fc","",fc);
  1846.  
  1847.     ttyfd = *fd;
  1848.  
  1849.     pty_master_fd = -2;
  1850.     pty_slave_fd = -2;
  1851.     pty_fork_pid = -2;
  1852.  
  1853.     msg = 0;                /* Message counter */
  1854.     pty_init();                /* Find an available pty to use. */
  1855.     errno = 0;
  1856.  
  1857.     if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
  1858.     if (msg++ == 0)
  1859.       perror(Xline);
  1860.         debug(F111,"do_pty()","pty_getpty() fails",retval);
  1861.     *fd = ttyfd;
  1862.         return(-1);
  1863.     }
  1864.     *fd = ttyfd;
  1865.     debug(F111,"do_pty() Xline",Xline,ttyfd);
  1866.  
  1867. #ifdef SIGTTOU
  1868. /*
  1869.   Ignoring SIGTTOU keeps the kernel from blocking us.  we tweak the tty with
  1870.   an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
  1871. */
  1872.      signal(SIGTTOU, SIG_IGN);
  1873. #endif /* SIGTTOU */
  1874.  
  1875. /* Start up the command on the slave side of the terminal */
  1876.  
  1877.     if (pipe(syncpipe) < 0) {
  1878.         debug(F110,"do_pty()","pipe() fails",0);
  1879.     perror("pipe() failed");
  1880.     msg++;
  1881.         debug(F111,"do_pty()","pipe fails",errno);
  1882.         return(-1);
  1883.     }
  1884.     if ((i = fork()) < 0) {
  1885.         /* XXX - need to clean up the allocated pty */
  1886.         perror("fork() failed");
  1887.     msg++;
  1888.         debug(F111,"do_pty()","fork fails",errno);
  1889.         return(-1);
  1890.     }
  1891.     if (i) {  /* Wait for child before writing to parent side of pty. */
  1892.         char c;
  1893. #ifdef HAVE_PTYTRAP
  1894.         int on = 1;
  1895. #endif /* HAVE_PTYTRAP */
  1896.     close(syncpipe[1]);
  1897.     errno = 0;
  1898.         if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
  1899.         perror("Pipe read() failed");
  1900.         msg++;
  1901.             debug(F110,"do_pty()","Slave fails to initialize",0);
  1902.             close(syncpipe[0]);
  1903.             return(-1);
  1904.         }
  1905.         pty_fork_pid = i;        /* So we can clean it up later */
  1906.     pty_fork_active = 1;
  1907.     debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
  1908. #ifdef HAVE_PTYTRAP
  1909.         /* HPUX does not allow the master to read end of file.  */
  1910.         /* Therefore, we must determine that the slave has been */
  1911.         /* closed by trapping the call to close().              */
  1912.     errno = 0;
  1913.     x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
  1914.     debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
  1915. #endif /* HAVE_PTYTRAP */
  1916.         debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
  1917.         close(syncpipe[0]);
  1918.     } else {
  1919.     int x;
  1920.     debug(F101,"do_pty getptyslave ttyfd A","",ttyfd);
  1921.         debug(F110,"do_pty()","Slave starts",0);
  1922.     x = getptyslave(&ttyfd,fc);
  1923.     debug(F101,"do_pty getptyslave","",x);
  1924.         if (x == 0) {
  1925.         debug(F101,"do_pty getptyslave ttyfd B","",ttyfd);
  1926. #ifdef WANT_UTMP
  1927.             pty_update_utmp(PTY_USER_PROCESS,
  1928.                 getpid(),
  1929.                 "KERMIT",
  1930.                 Xline,
  1931.                 cmd,
  1932.                 PTY_TTYSLOT_USABLE
  1933.                 );
  1934. #endif /* WANT_UTMP */
  1935.             /* Notify our parent we're ready to continue.*/
  1936.             debug(F110,"do_pty()","slave synchronizing",0);
  1937.             write(syncpipe[1],"y",1);
  1938.             close(syncpipe[0]);
  1939.             close(syncpipe[1]);
  1940.  
  1941.         debug(F110,"do_pty cmd",cmd,"");
  1942.             exec_cmd(cmd);
  1943.             debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
  1944.         }
  1945.     *fd = ttyfd;
  1946.         debug(F110,"do_pty()","getptyslave() fails - exiting",0);
  1947.         exit(1);
  1948.     }
  1949.     *fd = ttyfd;
  1950.     pty_fc = fc;
  1951.     return(getpid());
  1952. } /* end of do_pty() */
  1953.  
  1954.  
  1955. VOID
  1956. end_pty() {
  1957.     msg = 0;                /* Message counter */
  1958.     debug(F101,"end_pty pty_fork_pid","",pty_fork_pid);
  1959.     if (Xline[0] && pty_fork_pid >= 0) {
  1960.         pty_cleanup(Xline,pty_fork_pid,1);
  1961.         Xline[0] = '\0';
  1962.         pty_fork_pid = -1;
  1963.     pty_fork_active = 0;
  1964.     debug(F101,"end_pty pty_fork_active","",pty_fork_active);
  1965.     }
  1966.     pty_fc = -1;
  1967. }
  1968. #endif /* NETPTY */
  1969.