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