source: trunk/third/kermit/ckupty.c @ 20081

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