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