home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckl196.zip / ckupty.c < prev    next >
C/C++ Source or Header  |  1999-12-10  |  45KB  |  1,710 lines

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