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