ckupty.c
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:42k
源码类别:

通讯/手机编程

开发平台:

Windows_Unix

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