home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckupty.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  50KB  |  1,980 lines

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