makefile patch
[ckermit.git] / ckutio.c
1 #define CKUTIO_C
2
3 #ifdef aegis
4 char *ckxv = "Aegis Communications support, 9.0.323, 10 June 2011";
5 #else
6 #ifdef Plan9
7 char *ckxv = "Plan 9 Communications support, 9.0.323, 10 June 2011";
8 #else
9 char *ckxv = "UNIX Communications support, 9.0.323, 10 June 2011";
10 #endif /* Plan9 */
11 #endif /* aegis */
12
13 /*  C K U T I O  */
14
15 /* C-Kermit interrupt, communications control and I/O functions for UNIX */
16
17 /*
18   Author: Frank da Cruz (fdc@columbia.edu),
19   Columbia University Academic Information Systems, New York City.
20
21   Copyright (C) 1985, 2011,
22     Trustees of Columbia University in the City of New York.
23     All rights reserved.  See the C-Kermit COPYING.TXT file or the
24     copyright text in the ckcmai.c module for disclaimer and permissions.
25 */
26
27 /*
28   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
29   compatible with C preprocessors that support only #ifdef, #else, #endif,
30   #define, and #undef.  Please do not use #if, logical operators, or other
31   preprocessor features in any of the portable C-Kermit modules.  You can,
32   of course, use these constructions in platform-specific modules when they
33   are supported by all compilers/preprocessors that could be used on that
34   platform.
35 */
36
37 extern int nettype;                     /* Defined in ckcmai.c */
38 extern int duplex;
39
40 /* Includes */
41
42 #include "ckcsym.h"                     /* This must go first   */
43 #include "ckcdeb.h"                     /* This must go second  */
44
45 #ifdef OSF13
46 #ifdef CK_ANSIC
47 #ifdef _NO_PROTO
48 #undef _NO_PROTO
49 #endif /* _NO_PROTO */
50 #endif /* CK_ANSIC */
51 #endif /* OSF13 */
52
53 #include <errno.h>                      /* System error numbers */
54
55 #ifdef __386BSD__
56 #define ENOTCONN 57
57 #else
58 #ifdef __bsdi__
59 #define ENOTCONN 57
60 #else
61 #ifdef __FreeBSD__
62 #define ENOTCONN 57
63 #endif /* __FreeBSD__ */
64 #endif /* __bsdi__ */
65 #endif /* __386BSD__ */
66
67 #ifdef SCO_OSR504
68 #define NBBY 8
69 #endif /* SCO_OSR504 */
70
71 #ifdef Plan9
72 #define SELECT
73 #include <sys/time.h>
74 #include <select.h>
75 #define FD_SETSIZE (3 * sizeof(long) * 8)
76 static struct timeval tv;
77 #endif /* Plan9 */
78
79 #ifdef CLIX
80 #include <sys/time.h>
81 #endif /* CLIX */
82
83 #include "ckcnet.h"                     /* Symbols for network types. */
84 #ifdef CK_SSL
85 #include "ck_ssl.h"
86 #endif /* CK_SSL */
87
88 /*
89   The directory-related includes are here because we need to test some
90   file-system-related symbols to find out which system we're being compiled
91   under.  For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
92 */
93 #ifdef SDIRENT                          /* Directory bits... */
94 #define DIRENT
95 #endif /* SDIRENT */
96
97 #ifdef XNDIR
98 #include <sys/ndir.h>
99 #else /* !XNDIR */
100 #ifdef NDIR
101 #include <ndir.h>
102 #else /* !NDIR, !XNDIR */
103 #ifdef RTU
104 #include "/usr/lib/ndir.h"
105 #else /* !RTU, !NDIR, !XNDIR */
106 #ifdef DIRENT
107 #ifdef SDIRENT
108 #include <sys/dirent.h>
109 #else
110 #include <dirent.h>
111 #endif /* SDIRENT */
112 #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
113 #include <sys/dir.h>
114 #endif /* DIRENT */
115 #endif /* RTU */
116 #endif /* NDIR */
117 #endif /* XNDIR */
118
119 #ifdef QNX
120 #include <sys/dev.h>
121 #endif /* QNX */
122
123 #ifdef HPUX5
124 #ifndef TCPSOCKET
125 /* I don't know why this is needed here since we never reference bzero(). */
126 /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
127 void
128 bzero(s,n) char *s; int n; {
129     extern char * memset();
130     memset(s,0,n);
131 }
132 #endif /* TCPSOCKET */
133 #endif /* HPUX5 */
134
135 /* Definition of HZ, used in msleep() */
136
137 #ifdef MIPS
138 #define HZ ( 1000 / CLOCK_TICK )
139 #else  /* MIPS */
140 #ifdef ATTSV
141 #ifndef NAP
142 #ifdef TRS16
143 #define HZ ( 1000 / CLOCK_TICK )
144 #endif /* TRS16 */
145 #ifdef NAPHACK
146 #define nap(x) (void)syscall(3112, (x))
147 #define NAP
148 #endif /* NAPHACK */
149 #endif /* NAP */
150 #endif /* ATTSV */
151 #endif /* MIPS */
152
153 #ifdef M_UNIX
154 #undef NGROUPS_MAX              /* Prevent multiple definition warnings */
155 #endif /* M_UNIX */
156
157 /*
158   NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
159   library routine, so _poll comes up undefined at link time.
160 */
161 #ifdef CK_POLL
162 #ifndef AIXRS                   /* IBM AIX needs special handling */
163 #include <poll.h>               /* "standard" (SVID) i/o multiplexing, etc */
164 #else /* AIXRS */
165 #ifdef SVR4                     /* AIX 3.2 is like SVID... */
166 #include <poll.h>
167 #else                           /* But AIX 3.1 is not ... */
168 #include <sys/poll.h>           /* The include file is in include/sys */
169 #define events reqevents        /* And it does not map IBM-specific member */
170 #define revents rtnevents       /* names to the System V equivalents */
171 #endif /* SVR4 */
172 #endif /* AIXRS */
173 #endif /* CK_POLL */
174
175 #include <signal.h>                     /* Signals */
176
177 /* For setjmp and longjmp */
178
179 #ifndef ZILOG
180 #include <setjmp.h>
181 #else
182 #include <setret.h>
183 #endif /* ZILOG */
184
185 /*
186   The following test differentiates between 4.1 BSD and 4.2 & later.
187   If you have a 4.1BSD system with the DIRENT library, this test could
188   mistakenly diagnose 4.2BSD and then later enable the use of system calls
189   that aren't defined.  If indeed there are such systems, we can use some
190   other way of testing for 4.1BSD, or add yet another compile-time switch.
191 */
192 #ifdef BSD4
193 #ifdef MAXNAMLEN
194 #ifndef FT21                            /* Except for Fortune. */
195 #ifndef FT18
196 #ifndef BELLV10                         /* And Bell Labs Research UNIX V10 */
197 #define BSD42
198 #endif /* BELLV10 */
199 #endif /* FT18 */
200 #endif /* FT21 */
201 #endif /* MAXNAMLEN */
202 #endif /* BSD4 */
203
204 #ifdef SUNOS41                          /* From Christian Corti */
205 #define BSD44ORPOSIX                    /* Uni Stuttgart */
206 #define SVORPOSIX                       /* February 2010 */
207 #include <termios.h>
208 #include <sys/ioctl.h>
209 #include <unistd.h>
210 #include <limits.h>
211 #endif  /* SUNOS41 */
212
213 #ifdef SNI542
214 #include <sys/filio.h>                  /* 299 for FIONREAD */
215 #endif  /* SNI542 */
216
217 /*
218   Minix 2.0 support added by Terry McConnell,
219   Syracuse University <tmc@barnyard.syr.edu>
220   No more sgtty interface, posix compliant.
221 */
222 #ifdef MINIX2
223 #define _MINIX   /* Needed for some Minix header files */
224 #define BSD44ORPOSIX
225 #define SVORPOSIX
226 #ifndef MINIX3
227 #define DCLTIMEVAL
228 #endif  /* MINIX3 */
229 #define NOFILEH
230 #include <sys/types.h>
231 #include <sys/ioctl.h>
232 #include <termios.h>
233 #include <limits.h>
234 #undef TIOCGETC    /* defined in sys/ioctl.h, but not really supported */
235 #define TANDEM 0
236 #endif /* MINIX2 */
237
238 /*
239  MINIX 1.0 support added by Charles Hedrick,
240  Rutgers University <hedrick@aramis.rutgers.edu>.
241  MINIX also has V7 enabled.
242 */
243 #ifdef MINIX
244 #define TANDEM 0
245 #define MYREAD
246 #define NOSYSIOCTLH
247 #include <limits.h>
248 #endif /* MINIX */
249
250 #ifdef CK_REDIR         /* <sys/wait.h> needed only for REDIRECT command. */
251 /*
252   If anybody can figure out how to make this work with NeXTSTEP, be
253   my guest!  (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
254 */
255 #ifndef CK_WAIT_H                       /* If wait.h not already included... */
256 #ifdef OSF                              /* force OSF to select POSIX wait */
257 #ifdef _BSD                             /* instead of BSD (see ckcdeb.h) */
258 #define CK_OSF_BSD
259 #undef _BSD
260 #endif /* _BSD */
261 #endif /* OSF */
262 #include <sys/wait.h>                   /* Include it */
263 #ifdef OSF
264 #ifdef CK_OSF_BSD
265 #define _BSD                            /* Restore it */
266 #undef CK_OSF_BSD
267 #endif /* CK_OSF_BSD */
268 #endif /* OSF */
269 #endif /* CK_WAIT_H */
270 #endif /* CK_REDIR */
271
272 #include "ckuver.h"                     /* Version herald */
273 char *ckxsys = HERALD;
274
275 #ifdef CK_UTSNAME
276 #include <sys/utsname.h>
277
278 #ifdef TRU64                            /* Tru64 UNIX 4.0 and later */
279 /* Verified on Tru64 4.0F - might break on 4.0E or earlier */
280 #include <sys/sysinfo.h>                /* (don't know about OSF/1 or DU) */
281 #include <machine/hal_sysinfo.h>
282 #endif /* TRU64 */
283
284 #ifdef SOLARIS25                        /* Solaris 2.5 and later */
285 #include <sys/systeminfo.h>             /* (don't know about earlier ones) */
286 #endif /* SOLARIS25 */
287
288 #ifdef UW7
289 #ifndef SYS_NMLN
290 #define SYS_NMLN 257
291 #endif /* NMLN */
292 #endif /* UW7 */
293 #ifdef HPUX9PLUS
294 static int hpis800 = 0;
295 #endif /* HPUX9PLUS */
296 #ifdef SYS_NMLN
297 #define CK_SYSNMLN SYS_NMLN
298 #else
299 #ifdef _SYS_NMLN
300 #define CK_SYSNMLN _SYS_NMLN
301 #else
302 #ifdef UTSLEN
303 #define CK_SYSNMLN UTSLEN
304 #else
305 #define CK_SYSNMLN 31
306 #endif /* UTSLEN */
307 #endif /* _SYS_NMLN */
308 #endif /* SYS_NMLN */
309 char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
310 char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
311 char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
312 char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
313 char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
314 #endif /* CK_UTSNAME */
315
316 #ifdef CIE
317 #include <stat.h>                       /* For chasing symlinks, etc. */
318 #else
319 #include <sys/stat.h>
320 #endif /* CIE */
321
322 #ifdef QNX                              /* 299 */
323 #ifndef IXANY
324 #define IXANY 0
325 #endif  /* IXANY */
326 #endif  /* QNX */
327
328 /* UUCP lockfile material... */
329
330 #ifndef NOUUCP
331 #ifdef USETTYLOCK
332 #ifdef HAVE_LOCKDEV                     /* Red Hat baudboy/lockdev */
333 /*
334   Watch out: baudboy.h references open() without making sure it has been
335   declared, resulting in warnings on at least Red Hat 7.3.  It's declared in
336   fcntl.h, but we don't include that until later.  In this case only, we
337   include it here, and then the second include is harmless because in Red Hat
338   Linux (the only place where you find baudboy.h) fcntl.h is protected from
339   multiple inclusion by _FCNTL_H.   - fdc, 10 May 2004.
340
341   NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
342   setgid bits to access the lockfile, C-Kermit will still need them to access
343   the serial port itself unless the port is open for world read/write.
344   Normally setgid uucp does the trick.
345
346   Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
347   but ttylock.  - jb, 26 Jul 2010
348 */
349 #include <fcntl.h>                      /* This has to come before baudboy */
350 #ifdef HAVE_BAUDBOY                     /* Red Hat baudboy/lockdev */
351 #include <baudboy.h>
352 #else  /* !HAVE_BAUDBOY */              /* openSuSE lock via ttylock */
353 #include <ttylock.h>
354 #endif  /* HAVE_BAUDBOY */
355 #define LOCK_DIR "/var/lock"            /* (even though we don't care) */
356
357 #else  /* !HAVE_LOCKDEV */
358
359 #ifdef USE_UU_LOCK
360 #ifdef __FreeBSD__
361 #include <libutil.h>                    /* FreeBSD */
362 #else
363 #include <util.h>                       /* OpenBSD */
364 #endif /* HAVE_LOCKDEV */
365 #endif /* __FreeBSD */
366 #endif /* USE_UU_LOCK */
367 #else  /* USETTYLOCK */
368
369 /* Name of UUCP tty device lockfile */
370
371 #ifdef LINUXFSSTND
372 #ifndef HDBUUCP
373 #define HDBUUCP
374 #endif /* HDBUUCP */
375 #endif /* LINUXFSSTND */
376
377 #ifdef ACUCNTRL
378 #define LCKDIR
379 #endif /* ACUCNTRL */
380
381 /*
382   PIDSTRING means use ASCII string to represent pid in lockfile.
383 */
384 #ifndef PIDSTRING
385 #ifdef HDBUUCP
386 #define PIDSTRING
387 #else
388 #ifdef BSD44
389 #define PIDSTRING
390 #else
391 #ifdef RTAIX
392 #define PIDSTRING
393 #else
394 #ifdef AIXRS
395 #define PIDSTRING
396 #else
397 #ifdef COHERENT
398 #define PIDSTRING
399 #endif /* COHERENT */
400 #endif /* AIXRS */
401 #endif /* RTAIX */
402 #endif /* BSD44 */
403 #endif /* HDBUUCP */
404 #endif /* PIDSTRING */
405
406 /* Now the PIDSTRING exceptions... */
407
408 #ifdef PIDSTRING
409 #ifdef HPUX
410 #undef PIDSTRING
411 #endif /* HPUX */
412 #endif /* PIDSTRING */
413
414 #ifdef __bsdi__                         /* BSDI (at least thru 1.1) */
415 #ifdef PIDSTRING
416 #undef PIDSTRING
417 #endif /* PIDSTRING */
418 #endif /* __bsdi__ */
419
420 #ifdef OSF32                            /* Digital UNIX (OSF/1) 3.2 */
421 #ifdef PIDSTRING
422 #undef PIDSTRING
423 #endif /* PIDSTRING */
424 #endif /* OSF32 */
425
426 /*
427   LOCK_DIR is the name of the lockfile directory.
428   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
429 */
430
431 #ifndef LOCK_DIR
432 #ifdef MACOSX
433 #define LOCK_DIR "/var/spool/lock"
434 #endif /* MACOSX */
435 #endif/* LOCK_DIR */
436
437 #ifndef LOCK_DIR
438 #ifdef BSD44
439 #ifdef __386BSD__
440 #define LOCK_DIR "/var/spool/lock"
441 #else
442 #ifdef __FreeBSD__
443 #define LOCK_DIR "/var/spool/lock"
444 #else
445 #ifdef __NetBSD__
446 #define LOCK_DIR "/var/spool/lock"
447 #else
448 #ifdef __OpenBSD__
449 #define LOCK_DIR "/var/spool/lock"
450 #else
451 /* So which ones is this for? */
452 /* Probably original 4.4BSD on Vangogh */
453 /* Plus who knows about Mac OS X... It doesn't even have a cu program */
454 #define LOCK_DIR "/var/spool/uucp"
455 #endif /* __OpenBSD__ */
456 #endif /* __NetBSD__ */
457 #endif /* __FreeBSD__ */
458 #endif /* __386BSD__ */
459 #else
460 #ifdef DGUX430
461 #define LOCK_DIR "/var/spool/locks"
462 #else
463 #ifdef HPUX10
464 #define LOCK_DIR "/var/spool/locks"
465 #else
466 #ifdef RTAIX                            /* IBM RT PC AIX 2.2.1 */
467 #define LOCK_DIR "/etc/locks"
468 #else
469 #ifdef AIXRS
470 #define LOCK_DIR "/etc/locks"
471 #else
472 #ifdef ISIII
473 #define LOCK_DIR "/etc/locks"
474 #else
475 #ifdef HDBUUCP
476 #ifdef M_SYS5
477 #define LOCK_DIR "/usr/spool/uucp"
478 #else
479 #ifdef M_UNIX
480 #define LOCK_DIR "/usr/spool/uucp"
481 #else
482 #ifdef SVR4
483 #define LOCK_DIR "/var/spool/locks"
484 #else
485 #ifdef SUNOS4
486 #define LOCK_DIR "/var/spool/locks"
487 #else
488 #ifdef LINUXFSSTND
489 #define LOCK_DIR "/var/lock";
490 #else
491 #define LOCK_DIR "/usr/spool/locks"
492 #endif /* LINUXFSSTND */
493 #endif /* SUNOS4 */
494 #endif /* SVR4 */
495 #endif /* M_UNIX */
496 #endif /* M_SYS5 */
497 #else
498 #ifdef LCKDIR
499 #define LOCK_DIR "/usr/spool/uucp/LCK"
500 #else
501 #ifdef COHERENT
502 #define LOCK_DIR "/usr/spool/uucp"
503 #else
504 #define LOCK_DIR "/usr/spool/uucp"
505 #endif /* COHERENT */
506 #endif /* LCKDIR */
507 #endif /* HDBUUCP */
508 #endif /* ISIII */
509 #endif /* AIXRS */
510 #endif /* RTAIX */
511 #endif /* HPUX10 */
512 #endif /* DGUX430 */
513 #endif /* BSD44 */
514 #endif /* !LOCK_DIR (outside ifndef) */
515
516 #ifdef OSF2                             /* OSF/1 2.0 or later */
517 #ifdef LOCK_DIR                         /* (maybe 1.x too, who knows...) */
518 #undef LOCK_DIR
519 #define LOCK_DIR "/var/spool/locks"
520 #endif /* LOCK_DIR */
521 #endif /* OSF2 */
522
523 #ifdef COMMENT
524 /* Sorry no more lockf() -- we lock first and THEN open the device. */
525 #ifdef SVR4
526 #ifndef BSD44
527 #ifndef LOCKF
528 #define LOCKF                           /* Use lockf() on tty device in SVR4 */
529 #endif /* LOCKF */
530 #endif /* BSD44 */
531 #endif /* SVR4 */
532 #endif /* COMMENT */
533
534 #ifdef NOLOCKF                          /* But NOLOCKF cancels LOCKF */
535 #ifdef LOCKF
536 #undef LOCKF
537 #endif /* LOCKF */
538 #endif /* NOLOCKF */
539
540 /* More about this below... */
541
542 #endif /* USETTYLOCK */
543 #endif /* NOUUCP */
544
545 /*
546   MYREAD means use our internally defined nonblocking buffered read routine.
547 */
548 #ifdef ATTSV
549 #define MYREAD
550 #endif /* ATTSV */
551
552 #ifdef ATT7300
553 #ifndef MYREAD
554 #define MYREAD
555 #endif /* MYREAD */
556 /* bits for attmodem: internal modem in use, restart getty */
557 #define ISMODEM 1
558 #define DOGETY 512
559 #endif  /* ATT7300 */
560
561 #ifdef BSD42
562 #define MYREAD
563 #endif /* BSD42 */
564
565 #ifdef POSIX
566 #define MYREAD
567 #endif /* POSIX */
568 #ifdef __bsdi__
569 #ifndef O_NDELAY
570 #define O_NDELAY O_NONBLOCK
571 #endif /* O_NDELAY */
572 #endif /* __bsdi__ */
573
574 /*
575  Variables available to outside world:
576
577    dftty  -- Pointer to default tty name string, like "/dev/tty".
578    dfloc  -- 0 if dftty is console, 1 if external line.
579    dfprty -- Default parity
580    dfflow -- Default flow control
581    ckxech -- Flag for who echoes console typein:
582      1 - The program (system echo is turned off)
583      0 - The system (or front end, or terminal).
584    functions that want to do their own echoing should check this flag
585    before doing so.
586
587    flfnam  -- Name of lock file, including its path, e.g.,
588                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
589    lkflfn  -- Name of link to lock file, including its paths
590    haslock -- Flag set if this kermit established a uucp lock.
591    lockpid -- PID of other process that has desired line open, as string.
592    backgrd -- Flag indicating program executing in background ( & on
593                 end of shell command). Used to ignore INT and QUIT signals.
594    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
595                 SIGTSTP)
596
597  Functions for assigned communication line (either external or console tty):
598
599    sysinit()               -- System dependent program initialization
600    syscleanup()            -- System dependent program shutdown
601    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
602    ttclos()                -- Close & reset the tty, releasing any access lock.
603    ttsspd(cps)             -- Set the transmission speed of the tty.
604    ttgspd()                -- Get (read) the the transmission speed of the tty.
605    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
606    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
607                                 or in DIALING or CONNECTED modem control state.
608    ttres()                 -- Restore original tty modes.
609    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
610    ttinl(dest,max,timo)    -- Timed read line from the tty.
611    ttinc(timo)             -- Timed read character from tty.
612    myread()                -- Raw mode bulk buffer read, gives subsequent
613                                 chars one at a time and simulates FIONREAD.
614    myunrd(c)               -- Places c back in buffer to be read (one only)
615    ttchk()                 -- See how many characters in tty input buffer.
616    ttxin(n,buf)            -- Read n characters from tty (untimed).
617    ttol(string,length)     -- Write a string to the tty.
618    ttoc(c)                 -- Write a character to the tty.
619    ttflui()                -- Flush tty input buffer.
620    ttsndb()                -- Send BREAK signal.
621    ttsndlb()               -- Send Long BREAK signal.
622
623    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
624    ttunlck()               -- Unlock tty device.
625
626                               For ATT7300/Unix PC, System V:
627    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
628    offgetty(ttname)        -- Turns off getty(1m) for comms line
629    ongetty(ttname)         -- Restores getty() to comms line
630 */
631
632 /*
633 Functions for console terminal:
634
635    congm()   -- Get console terminal modes.
636    concb(esc) -- Put the console in single-character wakeup mode with no echo.
637    conbin(esc) -- Put the console in binary (raw) mode.
638    conres()  -- Restore the console to mode obtained by congm().
639    conoc(c)  -- Unbuffered output, one character to console.
640    conol(s)  -- Unbuffered output, null-terminated string to the console.
641    conola(s) -- Unbuffered output, array of strings to the console.
642    conxo(n,s) -- Unbuffered output, n characters to the console.
643    conchk()  -- Check if characters available at console (bsd 4.2).
644                 Check if escape char (^\) typed at console (System III/V).
645    coninc(timo)  -- Timed get a character from the console.
646    congks(timo)  -- Timed get keyboard scan code.
647    conint()  -- Enable terminal interrupts on the console if not background.
648    connoi()  -- Disable terminal interrupts on the console if not background.
649
650 Time functions
651
652    msleep(m) -- Millisecond sleep
653    ztime(&s) -- Return pointer to date/time string
654    rtimer() --  Reset timer
655    gtimer()  -- Get elapsed time since last call to rtimer()
656 */
657
658 /* Conditional Includes */
659
660 /* Whether to include <sys/file.h> */
661
662 #ifdef RTU                              /* RTU doesn't */
663 #define NOFILEH
664 #endif /* RTU */
665
666 #ifdef CIE                              /* CIE does. */
667 #undef NOFILEH
668 #endif /* CIE */
669
670 #ifdef BSD41                            /* 4.1 BSD doesn't */
671 #define NOFILEH
672 #endif /* BSD41 */
673
674 #ifdef is68k                            /* Integrated Solutions 68000 UNIX  */
675 #define NOFILEH                         /* e.g. on Plexux P60 and Sun-1 */
676 #endif /* is68k */
677
678 #ifdef MINIX                            /* MINIX */
679 #define NOFILEH
680 #endif /* MINIX */
681
682 #ifdef COHERENT                         /* Coherent */
683 #define NOFILEH
684 #endif /* COHERENT */
685
686 #ifndef NOFILEH                         /* Now include if selected. */
687 #include <sys/file.h>
688 #endif /* NOFILEH */
689
690 /* POSIX */
691
692 #ifdef BSD44ORPOSIX                     /* POSIX uses termios.h */
693 #define TERMIOS
694 #ifdef __bsdi__
695 #ifdef POSIX
696 #undef _POSIX_SOURCE                    /* Get extra stuff from termios.h */
697 #endif /* POSIX */
698 #endif /* __bsdi__ */
699 #include <termios.h>
700 #ifdef LINUX
701 #include <sys/ioctl.h>
702 #endif /* LINUX */
703 #ifdef QNX16
704 #include <ioctl.h>
705 #else
706 #ifdef QNX6
707 #include <ioctl.h>
708 #endif /* QNX6 */
709 #endif /* QNX16 */
710 #ifdef __bsdi__
711 #ifdef POSIX
712 #define _POSIX_SOURCE
713 #endif /* POSIX */
714 #endif /* __bsdi__ */
715 #ifndef BSD44                           /* Really POSIX */
716 #ifndef CK_QNX32                        /* was CK_QNX32 */
717 #define NOSYSIOCTLH                     /* No ioctl's allowed. */
718 #undef ultrix                           /* Turn off any ultrix features. */
719 #endif /* CK_QNX32 */
720 #endif /* BSD44 */
721 #endif /* POSIX */
722
723 /* System III, System V */
724
725 #ifdef ATTSV
726 #ifndef BSD44
727 #ifndef POSIX
728 #include <termio.h>
729 #endif /* POSIX */
730 #endif /* BSD44 */
731 #ifdef TERMIOX
732 /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
733 #include <termiox.h>
734   struct termiox rctsx;
735 #else
736 #ifdef STERMIOX
737 #ifdef SCO_OSR504
738 /* Sorry, this is truly disgusting but it's SCO's fault. */
739 #ifndef _SVID3
740 #define _CK_SVID3_X
741 #define _SVID3
742 #endif /* _SVID3 */
743 #endif /* SCO_OSR504 */
744 #include <sys/termiox.h>
745   struct termiox rctsx;
746 #ifdef CK_SVID3_X
747 #undef _SVID3
748 #undef CK_SVID3_X
749 #endif /* CK_SVID3_X */
750 #endif /* STERMIOX */
751 #endif /* TERMIOX */
752 #endif /* ATTSV */
753
754 #ifdef COHERENT                 /* Use termio.h, not sgtty.h for Coherent */
755 #include <termio.h>
756 #endif /* COHERENT */
757
758 #ifdef MINIX                            /* MINIX uses ioctl's */
759 #define NOSYSIOCTLH                     /* but has no <sys/ioctl.h> */
760 #endif /* MINIX */
761
762 /* Others */
763
764 #ifndef NOSYSIOCTLH                     /* Others use ioctl() */
765 #ifdef SUN4S5
766 /*
767   This is to get rid of cpp warning messages that occur because all of
768   these symbols are defined by both termios.h and ioctl.h on the SUN.
769 */
770 #undef ECHO
771 #undef NL0
772 #undef NL1
773 #undef TAB0
774 #undef TAB1
775 #undef TAB2
776 #undef XTABS
777 #undef CR0
778 #undef CR1
779 #undef CR2
780 #undef CR3
781 #undef FF0
782 #undef FF1
783 #undef BS0
784 #undef BS1
785 #undef TOSTOP
786 #undef FLUSHO
787 #undef PENDIN
788 #undef NOFLSH
789 #endif /* SUN4S5 */
790 #include <sys/ioctl.h>
791 #endif /* NOSYSIOCTLH */
792 /*
793   We really, really, REALLY want FIONREAD, because it is the only way to find
794   out not just *if* stuff is waiting to be read, but how much, which is
795   critical to our sliding-window and streaming procedures, not to mention
796   efficiency of CONNECT, etc.
797 */
798 #ifdef BELLV10
799 #include <sys/filio.h>                  /* For FIONREAD */
800 #ifdef FIONREAD
801 #define MYREAD
802 #endif /* MYREAD */
803 #endif /* BELLV10 */
804
805 #ifndef FIONREAD
806 /* It wasn't found in ioctl.h or term*.h - try these places: */
807 #ifdef UNIXWARE
808 #include <sys/filio.h>
809 #else
810 #ifdef SOLARIS
811 #include <sys/filio.h>
812 #endif /* SOLARIS */
813 #endif /* UNIXWARE */
814 #endif /* FIONREAD */
815
816 #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
817 /*
818   <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
819   something.  Due to this, in_chk() uses the FIONREAD instead of RDCHK
820   and the hot keys during file transfer (X to cancel file etc) do not
821   work because FIONREAD doesn't work even though it is defined.
822
823   NOTE: This might also be true elsewhere.
824 */
825 #ifdef FIONREAD
826 #undef FIONREAD
827 #endif /* FIONREAD */
828 #endif /* XENIX */
829
830 #ifdef CK_SCOV5                         /* Ditto for SCO OpenServer 5.0 */
831 #ifdef FIONREAD
832 #undef FIONREAD
833 #endif /* FIONREAD */
834 #endif /* XENIX */
835
836 /* Whether to include <fcntl.h> */
837
838 #ifndef is68k                           /* Only a few don't have this one. */
839 #ifndef BSD41
840 #ifndef FT21
841 #ifndef FT18
842 #ifndef COHERENT
843 #include <fcntl.h>
844 #endif /* COHERENT */
845 #endif /* FT18 */
846 #endif /* FT21 */
847 #endif /* BSD41 */
848 #endif /* not is68k */
849
850 #ifdef COHERENT
851 #ifdef _I386
852 #include <fcntl.h>
853 #else
854 #include <sys/fcntl.h>
855 #endif /* _I386 */
856 #endif /* COHERENT */
857
858 #ifdef ATT7300                          /* Unix PC, internal modem dialer */
859 #include <sys/phone.h>
860 #endif /* ATT7300 */
861
862 #ifdef HPUX                             /* HP-UX variations. */
863 #define HPUXJOBCTL
864 #include <sys/modem.h>                  /* HP-UX modem signals */
865 #ifdef hp9000s500                       /* Model 500 */
866 #undef HPUXJOBCTL
867 #endif /* hp9000s500 */
868 #ifdef HPUXPRE65
869 #undef HPUXJOBCTL
870 typedef long mflag;
871 #endif /* HPUXPRE65 */
872 #ifdef HPUXJOBCTL
873 #include <sys/bsdtty.h>                 /* HP-UX Berkeley tty support */
874 #endif /* HPUXJOBCTL */
875 #endif /* HPUX */
876
877 /*
878   Which time.h files to include... See ckcdeb.h for defaults.
879   Note that 0, 1, 2, or all 3 of these can be included according to
880   the symbol definitions.
881 */
882 #ifndef NOTIMEH
883 #ifdef TIMEH
884 #include <time.h>
885 #endif /* TIMEH */
886 #endif /* NOTIMEH */
887
888 #ifndef NOSYSTIMEH
889 #ifdef SYSTIMEH
890 #include <sys/time.h>
891 #endif /* SYSTIMEH */
892 #endif /* NOSYSTIMEH */
893
894 #ifndef NOSYSTIMEBH
895 #ifdef SYSTIMEBH
896 #include <sys/timeb.h>
897 #endif /* SYSTIMEBH */
898 #endif /* NOSYSTIMEBH */
899
900 #ifndef NODCLTIMEVAL
901 #ifdef DCLTIMEVAL
902 /*
903   In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
904   define the structs we need to access the higher speeds, so we have to
905   do it ourselves.
906 */
907 struct timeval {
908     long tv_sec;
909     long tv_usec;
910 };
911 struct timezone {
912     int tz_minuteswest;
913     int tz_dsttime;
914 };
915 #endif /* DCLTIMEVAL */
916 #endif /* NODCLTIMEVAL */
917
918 #ifdef __linux__
919 /* THIS IS OBSOLETE since about Linux 0.92 */
920 #ifdef OLINUXHISPEED
921 #include <linux/serial.h>
922 #endif /* OLINUXHISPEED */
923 #ifdef __alpha__                        /* Linux on DEC Alpha */
924 #ifndef __GLIBC__                       /* But not with glibc */
925 #include <asm/termios.h>
926 #endif /* __GLIBC__ */
927 #endif /* __alpha__ */
928 #endif /* __linux__ */
929
930 #ifdef NOIEXTEN                         /* This is broken on some systems */
931 #undef IEXTEN                           /* like Convex/OS 9.1 */
932 #endif /* NOIEXTEN */
933 #ifndef IEXTEN                          /* Turn off ^O/^V processing. */
934 #define IEXTEN 0                        /* Needed, at least, on BSDI. */
935 #endif /* IEXTEN */
936 /*
937   Pick up definitions needed for select() if we don't have them already.
938   Normally they come from <sys/types.h> but some systems get them from
939   <sys/select.h>...  Rather than hardwire all of them into the source, we
940   include it if SELECT_H is defined in compile-time CFLAGS.
941 */
942 #ifndef SCO_OSR504
943 #ifdef SELECT_H
944 #include <sys/select.h>
945 #endif /* SELECT_H */
946 #endif /* SCO_OSR504 */
947
948 #ifdef aegis
949 #include "/sys/ins/base.ins.c"
950 #include "/sys/ins/error.ins.c"
951 #include "/sys/ins/ios.ins.c"
952 #include "/sys/ins/sio.ins.c"
953 #include "/sys/ins/pad.ins.c"
954 #include "/sys/ins/time.ins.c"
955 #include "/sys/ins/pfm.ins.c"
956 #include "/sys/ins/pgm.ins.c"
957 #include "/sys/ins/ec2.ins.c"
958 #include "/sys/ins/type_uids.ins.c"
959 #include <default_acl.h>
960 #undef TIOCEXCL
961 #undef FIONREAD
962 #endif /* aegis */
963
964 #ifdef sxaE50                           /* PFU Compact A SX/A TISP V10/L50 */
965 #undef FIONREAD
966 #endif /* sxaE50 */
967
968 /* The following #defines are catch-alls for those systems */
969 /* that didn't have or couldn't find <file.h>... */
970
971 #ifndef FREAD
972 #define FREAD 0x01
973 #endif /* FREAD */
974
975 #ifndef FWRITE
976 #define FWRITE 0x10
977 #endif /* FWRITE */
978
979 #ifndef O_RDONLY
980 #define O_RDONLY 000
981 #endif /* O_RDONLY */
982
983 /* This is for ancient Unixes that don't have these tty symbols defined. */
984
985 #ifndef PENDIN
986 #define PENDIN ICANON
987 #endif /* PENDIN */
988 #ifndef FLUSHO
989 #define FLUSHO ICANON
990 #endif /* FLUSHO */
991 #ifndef EXTPROC
992 #define EXTPROC ICANON
993 #endif /* EXTPROC */
994
995 #ifdef SVORPOSIX
996 /*
997   Modem signals are also forbidden in the POSIX world.  But some POSIX-based
998   platforms let us at them anyway if we know where to look.
999 */
1000 #ifndef NEEDMDMDEFS
1001 /* Doesn't work for Linux */
1002 #ifdef UNIXWARE7
1003 #define NEEDMDMDEFS
1004 #endif /* UNIXWARE7 */
1005 #endif /* NEEDMDMDEFS */
1006
1007 #ifdef NEEDMDMDEFS
1008 #ifndef TIOCMGET
1009 #define TIOCMGET (('t'<<8)|29)
1010 #endif /* TIOCMGET */
1011
1012 #ifndef TIOCM_DTR
1013 #define TIOCM_DTR 0x0002
1014 #endif /* TIOCM_DTR */
1015 #ifndef TIOCM_RTS
1016 #define TIOCM_RTS 0x0004
1017 #endif /* TIOCM_RTS */
1018 #ifndef TIOCM_CTS
1019 #define TIOCM_CTS 0x0020
1020 #endif /* TIOCM_CTS */
1021 #ifndef TIOCM_CAR
1022 #define TIOCM_CAR 0x0040
1023 #endif /* TIOCM_CAR */
1024 #ifndef TIOCM_RNG
1025 #define TIOCM_RNG 0x0080
1026 #endif /* TIOCM_RNG */
1027 #ifndef TIOCM_DSR
1028 #define TIOCM_DSR 0x0100
1029 #endif /* TIOCM_DSR */
1030 #endif /* NEEDMDMDEFS */
1031 #endif /* SVORPOSIX */
1032
1033 /* Declarations */
1034
1035 #ifdef OXOS
1036 #undef TCGETA
1037 #undef TCSETA
1038 #undef TCSETAW
1039 #undef TCSETAF
1040 #define TCGETA TCGETS
1041 #define TCSETA TCSETS
1042 #define TCSETAW TCSETSW
1043 #define TCSETAF TCSETSF
1044 #define termio termios
1045 #endif /* OXOS */
1046
1047 #ifdef SVORPOSIX                        /* AT&T Sys V or POSIX */
1048 #ifdef UNIXWAREPOSIX                    /* UnixWare 7 POSIX build */
1049 /*
1050   In Unixware POSIX builds, <[sys/]time.h> refuses to define the
1051   structs we need to access the higher speeds, so we have to do it
1052   ourselves.
1053 */
1054 struct timeval {
1055     long tv_sec;
1056     long tv_usec;
1057 };
1058 struct timezone {
1059     int tz_minuteswest;
1060     int tz_dsttime;
1061 };
1062 #endif /* UNIXWAREPOSIX */
1063 #endif /* SVORPOSIX */
1064
1065 #ifdef __GNUC__
1066 #ifdef XENIX
1067 /*
1068   Because Xenix <time.h> doesn't declare time() if we're using gcc.
1069 */
1070 time_t time();
1071 #endif /* XENIX */
1072 #endif /* __GNUC__ */
1073
1074 /* Special stuff for V7 input buffer peeking */
1075
1076 #ifdef  V7
1077 int kmem[2] = { -1, -1};
1078 char *initrawq(), *qaddr[2]={0,0};
1079 #define CON 0
1080 #define TTY 1
1081 #endif /* V7 */
1082
1083 /* dftty is the device name of the default device for file transfer */
1084 /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
1085
1086 #ifdef BEOS
1087     char * dftty = NULL;
1088     char * dfmdm = "none";
1089     int dfloc = 0;                  /* that goes in local mode by default */
1090 #else
1091 #ifndef DFTTY
1092 #ifdef PROVX1
1093     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
1094     char *dfmdm = "none";
1095     int dfloc = 1;                  /* that goes in local mode by default */
1096 #else
1097     char *dftty = CTTNAM;               /* Remote by default, use normal */
1098     char *dfmdm = "none";
1099     int dfloc = 0;                      /* controlling terminal name. */
1100 #endif /* PROVX1 */
1101 #else
1102     char *dftty = DFTTY;                /* Default location specified on */
1103     char *dfmdm = "none";               /* command line. */
1104     int dfloc = 1;                      /* controlling terminal name. */
1105 #endif /* DFTTY */
1106 #endif /* BEOS */
1107
1108 #define CON_RES 0                       /* Console state is "reset" */
1109 #define CON_CB  1                       /* Console state is CBREAK */
1110 #define CON_BIN 2                       /* Console state is binary */
1111     static int constate = CON_RES;
1112
1113 #define CONI_RES 0                      /* Console interrupts are "reset" */
1114 #define CONI_INT 1                      /* Console intterupts are set */
1115 #define CONI_NOI 2                      /* Console intterupts are disabled */
1116     static int conistate = CONI_RES;
1117
1118 #ifdef CK_SMALL
1119 #define CONBUFSIZ 15
1120 #else
1121 #define CONBUFSIZ 255
1122 #endif /* CK_SMALL */
1123     static char conbuf[CONBUFSIZ];      /* Console readahead buffer */
1124     static int  conbufn = 0;            /* Chars in readahead buffer */
1125     static char *conbufp = conbuf;      /* Next char in readahead buffer */
1126
1127     char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
1128
1129 #ifdef RTU
1130     int rtu_bug = 0;                /* set to 1 when returning from SIGTSTP */
1131 #endif /* RTU */
1132
1133     int dfprty = DEFPAR;                /* Default parity (0 = none) */
1134     int ttprty = 0;                     /* The parity that is in use. */
1135     static int ttpmsk = 0xff;           /* Parity stripping mask. */
1136     int ttmdm = 0;                      /* Modem in use. */
1137     int ttcarr = CAR_AUT;               /* Carrier handling mode. */
1138     int dfflow = FLO_NONE;              /* Default flow control is NONE */
1139     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
1140 #ifdef F_SETFL
1141     int iniflags = -1;                  /* fcntl flags for ttyfd */
1142 #endif /* F_SETFL */
1143     int fdflag = 0;                     /* Flag for redirected stdio */
1144     int ttfdflg = 0;                    /* Open File descriptor was given */
1145     int tvtflg = 0;                     /* Flag that ttvt has been called */
1146     long ttspeed = -1L;                 /* For saving speed */
1147     int ttflow = -9;                    /* For saving flow */
1148     int ttld = -1;                      /* Line discipline */
1149
1150 #ifdef sony_news
1151     static int km_con = -1;             /* Kanji mode for console tty */
1152     static int km_ext = -1;             /* Kanji mode for external device */
1153 #endif /* sony_news */
1154
1155 #ifdef PARSENSE
1156     static int needpchk = 1;            /* Need parity check */
1157 #else
1158     static int needpchk = 0;
1159 #endif /* PARSENSE */
1160
1161     extern int stopbits;                /* Stop bits */
1162 #ifdef HWPARITY
1163 /*
1164   Unfortunately we must do this with global variables rather than through the
1165   tt...() APIs to avoid changing the APIs and the many modules that use them.
1166   If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
1167   bits + parity or 8 data bits and no parity, and overrides the regular parity
1168   variable, which is communicated to this module thru ttpkt(), and represented
1169   locally by the ttprty variable.
1170 */
1171     extern int hwparity;                /* Hardware parity */
1172 #endif /* HWPARITY */
1173
1174 #ifdef TCPSOCKET
1175 #ifdef TCP_NODELAY
1176 static int nodelay_sav = -1;
1177 #endif /* TCP_NODELAY */
1178 #endif /* TCPSOCKET */
1179
1180 static int sigint_ign = 0;              /* SIGINT is ignored */
1181
1182 /*
1183   Having this module rely on external globals is bad, but fixing this
1184   requires overhaul of the ck*tio.c modules for all the different operating
1185   systems supported by C-Kermit.  Left for a future release.
1186 */
1187 extern int ttnproto;                    /* Defined in ckcnet.c */
1188 extern int ttnet;                       /* Defined in ckcnet.c */
1189 extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
1190 extern int xsuspend, wasclosed;
1191 extern int inserver, local;
1192
1193 int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
1194
1195 int ckmaxfiles = 0;                     /* Max number of open files */
1196
1197 #ifdef CK_ENCRYPTION                    /* Kerberos */
1198 #include "ckuath.h"
1199 extern int me_encrypt, u_encrypt;
1200 #endif /* CK_ENCRYPTION */
1201
1202 /* Declarations of variables global within this module */
1203
1204 #ifdef TTLEBUF                          /* See ckcnet.h */
1205 int ttpush = -1;
1206 #define LEBUFSIZ 4096
1207 static CHAR le_buf[LEBUFSIZ];
1208 static int le_start = 0, le_end = 0, le_data = 0;
1209 #endif /* TTLEBUF */
1210
1211 #define MSGBUF_SIZE 1024                /* For debugging */
1212 static char msgbuf[MSGBUF_SIZE];
1213
1214 static int gotsigs = 0;
1215
1216 static time_t tcount = (time_t)0;       /* Elapsed time counter */
1217
1218 static SIGTYP (*saval)()     = NULL;    /* For saving alarm() handler */
1219 static SIGTYP (*savquit)()   = NULL;    /* and other signal handlers */
1220 #ifdef SIGUSR1
1221 static SIGTYP (*savusr1)()   = NULL;
1222 #endif /* SIGUSR1 */
1223 #ifdef SIGUSR2
1224 static SIGTYP (*savusr2)()   = NULL;
1225 #endif /* SIGUSR2 */
1226 #ifdef SIGPIPE
1227 static SIGTYP (*savpipe)()   = NULL;
1228 #endif /* SIGPIPE */
1229 #ifdef SIGDANGER
1230 static SIGTYP (*savdanger)() = NULL;
1231 #endif /* SIGDANGER */
1232
1233 #ifndef NOJC
1234 static SIGTYP (*jchdlr)()    = NULL;    /* For checking suspend handler */
1235 #endif /* NOJC */
1236 static int jcshell = -1;                /* And flag for result */
1237
1238 /*
1239   BREAKNULS is defined for systems that simulate sending a BREAK signal
1240   by sending a bunch of NUL characters at low speed.
1241 */
1242 #ifdef PROVX1
1243 #ifndef BREAKNULS
1244 #define BREAKNULS
1245 #endif /* BREAKNULS */
1246 #endif /* PROVX1 */
1247
1248 #ifdef V7
1249 #ifndef BREAKNULS
1250 #define BREAKNULS
1251 #endif /* BREAKNULS */
1252 #endif /* V7 */
1253
1254 #ifdef BREAKNULS
1255 static char                             /* A string of nulls */
1256 *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
1257 #endif /* BREAKNULS */
1258
1259 #ifdef CK_POSIX_SIG                     /* Longjump buffers */
1260 static sigjmp_buf sjbuf;                /* POSIX signal handling */
1261 #else
1262 static jmp_buf sjbuf;
1263 #endif /* CK_POSIX_SIG */
1264
1265 #ifdef V7
1266 static jmp_buf jjbuf;
1267 #endif /* V7 */
1268
1269 /* static */                            /* (Not static any more) */
1270 int ttyfd = -1;                         /* TTY file descriptor */
1271
1272 int ttpipe = 0;                         /* NETCMD: Use pipe instead of ttyfd */
1273 int ttpty  = 0;                         /* NETPTY: Use pty instead of ttfyd */
1274
1275 #ifdef NETPTY                           /* These are in ckupty.c */
1276 extern PID_T pty_fork_pid;
1277 extern int pty_master_fd, pty_slave_fd;
1278 #endif  /* NETPTY */
1279
1280 #ifdef NETCMD
1281 #ifdef NETCONN
1282 static int pipe0[2], pipe1[2];          /* Pipes for net i/o */
1283 #endif /* NETCONN */
1284 static PID_T ttpid = 0;                 /* Process ID for fork */
1285 static int fdin, fdout;                 /* File descriptors for pipe */
1286 static FILE * ttout = NULL;             /* File pointer for output pipe */
1287 #ifdef DCLFDOPEN
1288 /* fdopen() needs declaring because it's not declared in <stdio.h> */
1289 _PROTOTYP( FILE * fdopen, (int, char *) );
1290 #endif /* DCLFDOPEN */
1291 #endif /* NETCMD */
1292
1293 extern int pexitstat, quiet;
1294
1295 #ifdef Plan9
1296 int ttyctlfd  = -1;   /* TTY control channel - What? UNIX doesn't have one? */
1297 int consctlfd = -1;                     /* Console control channel */
1298 int noisefd = -1;                       /* tone channel */
1299 static int ttylastspeed = -1;           /* So we can lie about the speed */
1300 #endif /* Plan9 */
1301
1302 int telnetfd = 0;                       /* File descriptor is for telnet */
1303 #ifdef NETCONN
1304 int x25fd = 0;                          /* File descriptor is for X.25 */
1305 #endif /* NETCONN */
1306
1307 char lockpid[16] = { '\0', '\0' };      /* PID stored in lockfile, as string */
1308
1309 static int lkf = 0,                     /* Line lock flag */
1310     cgmf = 0,                           /* Flag that console modes saved */
1311     xlocal = 0,                         /* Flag for tty local or remote */
1312     curcarr = 0;                        /* Carrier mode: require/ignore. */
1313
1314 static int netconn = 0;                 /* 1 if network connection active */
1315
1316 static char escchr;                     /* Escape or attn character */
1317
1318 #ifdef CK_SCO32V4
1319 #include <sys/time.h>
1320 #endif /* CK_SCO32V4 */
1321
1322 #ifdef HAVE_TV
1323     static struct timeval tv;           /* For getting time, from sys/time.h */
1324 #endif /* HAVE_TV */
1325 #ifdef HAVE_TZ
1326     static struct timezone tz;
1327 #endif /* HAVE_TZ */
1328
1329 #ifdef OSF
1330     static struct timeb ftp;            /* And from sys/timeb.h */
1331 #endif /* OSF */
1332
1333 #ifdef BSD29
1334     static long xclock;                 /* For getting time from sys/time.h */
1335     static struct timeb ftp;            /* And from sys/timeb.h */
1336 #endif /* BSD29 */
1337
1338 #ifdef BSD41
1339     static long xclock;                 /* For getting time from sys/time.h */
1340     static struct timeb ftp;            /* And from sys/timeb.h */
1341 #endif /* BSD41 */
1342
1343 #ifdef BELLV10
1344     static long xclock;                 /* For getting time from sys/time.h */
1345     static struct timeb ftp;            /* And from sys/timeb.h */
1346 #endif /* BELLV10 */
1347
1348 #ifdef FT21
1349     static long xclock;                 /* For getting time from sys/time.h */
1350     static struct timeb ftp;            /* And from sys/timeb.h */
1351 #endif /* FT21 */
1352
1353 #ifdef TOWER1
1354     static long xclock;                 /* For getting time from sys/time.h */
1355     static struct timeb ftp;            /* And from sys/timeb.h */
1356 #endif /* TOWER1 */
1357
1358 #ifdef COHERENT
1359     static long xclock;                 /* For getting time from sys/time.h */
1360     static struct timeb ftp;            /* And from sys/timeb.h */
1361 #endif /* COHERENT */
1362
1363 #ifdef V7
1364     static long xclock;
1365 #endif /* V7 */
1366
1367 /* sgtty/termio information... */
1368
1369 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
1370   static struct termios
1371     ttold, ttraw, tttvt, ttcur,
1372     ccold, ccraw, cccbrk;
1373 #else                                   /* BSD, V7, etc */
1374
1375 #ifdef COHERENT                         /* Hack alert... */
1376 #define ATTSV
1377 #endif /* COHERENT */
1378
1379 #ifdef ATTSV
1380   static struct termio ttold = {0};     /* Init'd for word alignment, */
1381   static struct termio ttraw = {0};     /* which is important for some */
1382   static struct termio tttvt = {0};     /* systems, like Zilog... */
1383   static struct termio ttcur = {0};
1384   static struct termio ccold = {0};
1385   static struct termio ccraw = {0};
1386   static struct termio cccbrk = {0};
1387 #else
1388   static struct sgttyb                  /* sgtty info... */
1389     ttold, ttraw, tttvt, ttcur,         /* for communication line */
1390     ccold, ccraw, cccbrk;               /* and for console */
1391 #ifdef BELLV10
1392   static struct ttydevb                 /* Device info... */
1393     tdold, tdcur;                       /* for communication device */
1394 #endif /* BELLV10 */
1395 #ifdef TIOCGETC
1396   static struct tchars tchold, tchnoi;
1397
1398   static int tcharf;
1399 #endif /* TIOCGETC */
1400 #ifdef TIOCGLTC
1401   static struct ltchars ltchold, ltchnoi;
1402   static int ltcharf;
1403 #endif /* TIOCGLTC */
1404   int lmodef = 0;                       /* Local modes */
1405   int lmode = 0;
1406 #endif /* ATTSV */
1407 #endif /* BSD44ORPOSIX */
1408
1409 #ifdef COMMENT
1410 /* It picks up the speeds but they don't work */
1411 #ifdef UNIXWARE                         /* For higher serial speeds */
1412 #ifdef UW7                              /* in Unixware 7.0 */
1413 #include <sys/asyc.h>                   /* This picks up 57600 and 115200 */
1414 #endif /* UW7 */
1415 #endif /* UNIXWARE */
1416 #endif /* COMMENT */
1417
1418 #ifdef PROVX1
1419   static struct sgttyb ttbuf;
1420 #endif /* PROVX1 */
1421
1422 #ifdef ultrix
1423 /* do we really need this? */
1424   static struct sgttyb vanilla;
1425 #endif /* ultrix */
1426
1427 #ifdef ATT7300
1428 static int attmodem = 0;                /* ATT7300 internal-modem status */
1429 struct updata dialer = {0};             /* Condition dialer for data call */
1430 #endif /* ATT7300 */
1431
1432 #ifndef NOUUCP
1433 #define FLFNAML 128
1434 #ifndef USETTYLOCK
1435 #ifdef RTAIX
1436 char lkflfn[FLFNAML] = { '\0', '\0' };  /* and possible link to it */
1437 #endif /* RTAIX */
1438 char lock2[FLFNAML] =  { '\0', '\0' };  /* Name of second lockfile */
1439 #endif /* USETTYLOCK */
1440 #else
1441 #define FLFNAML 7
1442 #endif /* NOUUCP */
1443 char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
1444
1445 int haslock = 0;                        /* =1 if this kermit locked uucp */
1446
1447 #ifndef OXOS
1448 #ifdef SVORPOSIX
1449 static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
1450 #else
1451 #ifdef V7
1452 static int conesc = 0;
1453 #else
1454 #ifdef C70
1455 static int conesc = 0;
1456 #endif /* C70 */
1457 #endif /* V7 */
1458 #endif /* SVORPOSIX */
1459 #endif /* OXOS */
1460
1461 /* Local copy of comm device name or network host */
1462 static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
1463 #ifdef USETTYLOCK
1464 static char lockname[DEVNAMLEN+1];      /* Ditto, the part after "/dev/". */
1465 #endif /* USETTYLOCK */
1466
1467 #ifdef aegis
1468 static status_$t st;                    /* error status return value */
1469 static short concrp = 0;                /* true if console is CRP pad */
1470 static uid_$t ttyuid;                   /* tty type uid */
1471 static uid_$t conuid;                   /* stdout type uid */
1472
1473 /* APOLLO Aegis main()
1474  * establish acl usage and cleanup handling
1475  *    this makes sure that CRP pads
1476  *    get restored to a usable mode
1477  */
1478 main(argc,argv) int argc; char **argv; {
1479         status_$t status;
1480         pfm_$cleanup_rec dirty;
1481
1482         PID_T pid = getpid();
1483
1484         /* acl usage according to invoking environment */
1485         default_acl(USE_DEFENV);
1486
1487         /* establish a cleanup continuation */
1488         status = pfm_$cleanup(dirty);
1489         if (status.all != pfm_$cleanup_set) {
1490                 /* only handle faults for the original process */
1491                 if (pid == getpid() && status.all > pgm_$max_severity) {
1492                     /* blew up in main process */
1493                     status_$t quo;
1494                     pfm_$cleanup_rec clean;
1495
1496                     /* restore the console in any case */
1497                     conres();
1498
1499                     /* attempt a clean exit */
1500                     debug(F101, "cleanup fault status", "", status.all);
1501
1502                     /* doexit(), then send status to continuation */
1503                     quo = pfm_$cleanup(clean);
1504                     if (quo.all == pfm_$cleanup_set)
1505                       doexit(pgm_$program_faulted,-1);
1506                     else if (quo.all > pgm_$max_severity)
1507                       pfm_$signal(quo); /* blew up in doexit() */
1508                 }
1509                 /* send to the original continuation */
1510                 pfm_$signal(status);
1511                 /*NOTREACHED*/
1512             }
1513         return(ckcmai(argc, argv));
1514 }
1515 #endif /* aegis */
1516
1517 /* ANSI-style prototypes for internal functions. */
1518 /* Functions used outside this module are prototyped in ckcker.h. */
1519
1520 #ifdef apollo
1521 _PROTOTYP( SIGTYP timerh, () );
1522 _PROTOTYP( SIGTYP cctrap, () );
1523 _PROTOTYP( SIGTYP esctrp, () );
1524 _PROTOTYP( SIGTYP sig_ign, () );
1525 #else
1526 _PROTOTYP( SIGTYP timerh, (int) );
1527 _PROTOTYP( SIGTYP cctrap, (int) );
1528 _PROTOTYP( SIGTYP esctrp, (int) );
1529 #endif /* apollo */
1530 _PROTOTYP( int do_open, (char *) );
1531 _PROTOTYP( static int in_chk, (int, int) );
1532 _PROTOTYP( static int ttrpid, (char *) );
1533 _PROTOTYP( static int ttchkpid, (char *) );
1534 _PROTOTYP( static int ttlock, (char *) );
1535 _PROTOTYP( static int ttunlck, (void) );
1536 _PROTOTYP( static VOID sigchld_handler, (int) );
1537 _PROTOTYP( int mygetbuf, (void) );
1538 _PROTOTYP( int myfillbuf, (void) );
1539 _PROTOTYP( VOID conbgt, (int) );
1540 #ifdef ACUCNTRL
1541 _PROTOTYP( VOID acucntrl, (char *, char *) );
1542 #endif /* ACUCNTRL */
1543
1544 #ifdef BSD44ORPOSIX
1545 _PROTOTYP( int carrctl, (struct termios *, int) );
1546 #else
1547 #ifdef ATTSV
1548 _PROTOTYP( int carrctl, (struct termio *, int) );
1549 #else
1550 _PROTOTYP( int carrctl, (struct sgttyb *, int) );
1551 #endif /* ATTSV */
1552 #endif /* BSD44ORPOSIX */
1553
1554 #ifdef ATT7300
1555 _PROTOTYP( int attdial, (char *, long, char *) );
1556 _PROTOTYP( int offgetty, (char *) );
1557 _PROTOTYP( int ongetty, (char *) );
1558 #endif /* ATT7300 */
1559
1560 #ifdef BEOSORBEBOX
1561 #ifdef SELECT
1562     /* BeOS is not capable of using SELECT on anything but sockets */
1563 #undef SELECT
1564 #endif /* SELECT */
1565 #include <kernel/OS.h>
1566 /* #ifdef BE_DR_7 */
1567 static double time_started = 0.0;
1568 struct ALARM_STRUCT {
1569     thread_id thread;
1570     int time;
1571 };
1572 static thread_id alarm_thread = -1;
1573 static struct ALARM_STRUCT alarm_struct;
1574 _PROTOTYP( long do_alarm, (void *) );
1575 _PROTOTYP( unsigned int alarm, (unsigned int) );
1576 _PROTOTYP( void alarm_expired, (void) );
1577 /* #endif */ /* BE_DR_7 */
1578 #endif /* BEOSORBEBOX */
1579
1580 #ifndef xunchar
1581 #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
1582 #endif /* xunchar */
1583
1584 #ifdef CK_ANSIC
1585 static char *
1586 xxlast(char *s, char c)
1587 #else
1588 static char *
1589 xxlast(s,c) char *s; char c;
1590 #endif /* CK_ANSIC */
1591 /* xxlast */ {          /*  Last occurrence of character c in string s. */
1592     int i;
1593     for (i = (int)strlen(s); i > 0; i--)
1594       if (s[i-1] == c ) return(s + (i - 1));
1595     return(NULL);
1596 }
1597
1598 /* Timeout handler for communication line input functions */
1599
1600 /*ARGSUSED*/
1601 SIGTYP
1602 timerh(foo) int foo; {
1603     ttimoff();
1604 #ifdef BEOSORBEBOX
1605 /* #ifdef BE_DR_7 */
1606     alarm_expired();
1607 /* #endif */ /* BE_DR_7 */
1608 #endif /* BEOSORBEBOX */
1609 #ifdef CK_POSIX_SIG
1610     siglongjmp(sjbuf,1);
1611 #else
1612     longjmp(sjbuf,1);
1613 #endif /* CK_POSIX_SIG */
1614 }
1615
1616 /*ARGSUSED*/
1617 SIGTYP
1618 xtimerh(foo) int foo; {                 /* Like timerh() but does */
1619 #ifdef BEOSORBEBOX                      /* not reset the timer itself */
1620 /* #ifdef BE_DR_7 */
1621     alarm_expired();
1622 /* #endif */ /* BE_DR_7 */
1623 #endif /* BEOSORBEBOX */
1624 #ifdef CK_POSIX_SIG
1625     siglongjmp(sjbuf,1);
1626 #else
1627     longjmp(sjbuf,1);
1628 #endif /* CK_POSIX_SIG */
1629 }
1630
1631
1632 /* Control-C trap for communication line input functions */
1633
1634 int cc_int;                             /* Flag */
1635 SIGTYP (* occt)();                      /* For saving old SIGINT handler */
1636
1637 /*ARGSUSED*/
1638 SIGTYP
1639 cctrap(foo) int foo; {                  /* Needs arg for ANSI C */
1640   cc_int = 1;                           /* signal() prototype. */
1641   return;
1642 }
1643
1644 /*  S Y S I N I T  --  System-dependent program initialization.  */
1645
1646 /*
1647  * ttgwsiz() returns:
1648  *      1    tt_rows and tt_cols are known, both altered, both > 0
1649  *      0    tt_rows and/or tt_cols are known, both altered, one or both <= 0
1650  *      -1   tt_rows and tt_cols are unknown and unaltered
1651  */
1652
1653 extern int tt_rows, tt_cols;
1654
1655 static int
1656 xttgwsiz() {
1657     char *p;
1658     int rows = 0, cols = 0;
1659     p = getenv("LINES");
1660     debug(F110,"xttgwsiz LINES",p,0);
1661     if (p) {
1662         rows = atol(p);
1663         if (rows > 0) {
1664             p = getenv("COLUMNS");
1665             debug(F110,"xttgwsiz COLUMNS",p,0);
1666             if (p) {
1667                 cols = atol(p);
1668                 if (cols > 0) {
1669                     tt_rows = rows;
1670                     tt_cols = cols;
1671                     return(1);
1672                 }
1673                 return(0);
1674             }
1675         }
1676     }
1677     return(-1);
1678 }
1679
1680 #ifdef TTLEBUF
1681 VOID
1682 le_init() {                             /* LocalEchoInit() */
1683     int i;
1684     for (i = 0; i < LEBUFSIZ; i++)
1685       le_buf[i] = '\0';
1686     le_start = 0;
1687     le_end = 0;
1688     le_data = 0;
1689 }
1690
1691 VOID
1692 le_clean() {                            /* LocalEchoCleanup() */
1693     le_init();
1694     return;
1695 }
1696
1697 int
1698 le_inbuf() {
1699     int rc = 0;
1700     if (le_start != le_end) {
1701         rc = (le_end -
1702               le_start +
1703               LEBUFSIZ) % LEBUFSIZ;
1704     }
1705     debug(F111,"le_inbuf","chars waiting",rc);
1706     return(rc);
1707 }
1708
1709 int
1710 #ifdef CK_ANSIC
1711 le_putchar(CHAR ch)
1712 #else
1713 le_putchar(ch) CHAR ch;
1714 #endif /* CK_ANSIC */
1715 /* le_putchar */ {
1716 #ifdef COMMENT
1717     /* In UNIX we do not have another thread taking chars out of the buffer */
1718     while ((le_start - le_end == 1) ||
1719             (le_start == 0 && le_end == LEBUFSIZ - 1)) {
1720         /* Buffer is full */
1721         debug(F111,"le_putchar","Buffer is Full",ch);
1722         ReleaseLocalEchoMutex() ;
1723         msleep(250);
1724         RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
1725     }
1726 #else
1727     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
1728         debug(F110,"le_putchar","buffer is full",0);
1729         return(-1);
1730     }
1731 #endif /* COMMENT */
1732     le_buf[le_end++] = ch;
1733     if (le_end == LEBUFSIZ)
1734       le_end = 0;
1735     le_data = 1;
1736     return(0);
1737 }
1738
1739 int
1740 #ifdef CK_ANSIC
1741 le_puts(CHAR * s, int n)
1742 #else
1743 le_puts(s,n) CHAR * s; int n;
1744 #endif /* CK_ANSIC */
1745 /* le_puts */ {
1746     int rc = 0;
1747     int i = 0;
1748     CHAR * p = (CHAR *)"le_puts";
1749     ckhexdump(p,s,n);
1750     for (i = 0; i < n; i++)
1751       rc = le_putchar((char)s[i]);
1752     debug(F101,"le_puts","",rc);
1753     return(rc);
1754 }
1755
1756 int
1757 #ifdef CK_ANSIC
1758 le_putstr(CHAR * s)
1759 #else
1760 le_putstr(s) CHAR * s;
1761 #endif /* CK_ANSIC */
1762 /* le_puts */ {
1763     CHAR * p;
1764     int rc = 0;
1765     p = (CHAR *)"le_putstr";
1766     ckhexdump(p,s,(int)strlen((char *)s));
1767     for (p = s; *p && !rc; p++)
1768       rc = le_putchar(*p);
1769     return(rc);
1770 }
1771
1772 int
1773 #ifdef CK_ANSIC
1774 le_getchar(CHAR * pch)
1775 #else /* CK_ANSIC */
1776 le_getchar(pch) CHAR * pch;
1777 #endif /* CK_ANSIC */
1778 /* le_gatchar */ {
1779     int rc = 0;
1780     if (le_start != le_end) {
1781         *pch = le_buf[le_start];
1782         le_buf[le_start] = 0;
1783         le_start++;
1784
1785         if (le_start == LEBUFSIZ)
1786           le_start = 0;
1787
1788         if (le_start == le_end) {
1789             le_data = 0;
1790         }
1791         rc++;
1792     } else {
1793         *pch = 0;
1794     }
1795     return(rc);
1796 }
1797 #endif /* TTLEBUF */
1798
1799 #ifdef COMMENT
1800 /*
1801   Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
1802   But as far as I know, whenever TIOCGSIZE is defined, it is
1803   equated to TIOCGWINSZ.  For cases where this is not done, try this:
1804 */
1805 #ifndef TIOCGWINSZ
1806 #ifdef TIOCGSIZE
1807 #define TIOCGWINSZ TIOCGSIZE
1808 #endif /* TIOCGSIZE */
1809 #endif /* TIOCGWINSZ */
1810 #endif /* COMMENT */
1811
1812 static int tt_xpixel = 0, tt_ypixel = 0;
1813
1814 int
1815 ttgwsiz() {
1816     int x = 0;
1817 #ifndef NONAWS
1818 #ifdef QNX
1819 /*
1820   NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
1821   This code works for both the 16- and 32-bit versions.
1822 */
1823     extern int dev_size(int, int, int, int *, int *);
1824     int r, c;
1825
1826     if (dev_size(0, -1, -1, &r, &c) == 0) {
1827         debug(F101,"ttgwsiz QNX r","",r);
1828         debug(F101,"ttgwsiz QNX c","",c);
1829         tt_rows = r;
1830         tt_cols = c;
1831         return ((r > 0 && c > 0) ? 1 : 0);
1832     } else return(xttgwsiz());
1833 #else /* QNX */
1834 #ifdef TIOCGWINSZ
1835
1836 /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
1837 #ifdef XENIX                            /* SCO UNIX 3.2v4.0 */
1838 #include <sys/stream.h>                 /* typedef mblk_t needed by ptem.h */
1839 #include <sys/ptem.h>                   /* for ttgwsiz() */
1840 #endif /* XENIX */
1841
1842 #ifdef I386IX                           /* Ditto for Interactive */
1843 #include <sys/stream.h>
1844 #include <sys/ptem.h>
1845 #endif /* I386IX */
1846
1847 /* Note, the above might be needed for some other older SVR3 Intel makes... */
1848
1849     struct winsize w;
1850     tt_xpixel = 0;
1851     tt_ypixel = 0;
1852
1853 #ifdef IKSD
1854     if (inserver)
1855       return(xttgwsiz());
1856 #endif /* IKSD */
1857     x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
1858     debug(F101,"ttgwsiz TIOCGWINSZ","",x);
1859     if (x < 0) {
1860         return(xttgwsiz());
1861     } else if (w.ws_row > 0 && w.ws_col > 0) {
1862         tt_rows = w.ws_row;
1863         tt_cols = w.ws_col;
1864         tt_xpixel = w.ws_xpixel;
1865         tt_ypixel = w.ws_ypixel;
1866         debug(F101,"ttgwsiz tt_rows","",tt_rows);
1867         debug(F101,"ttgwsiz tt_cols","",tt_cols);
1868         return(1);
1869     } else {
1870         debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
1871         return(xttgwsiz());
1872     }
1873 #else
1874     return(xttgwsiz());
1875 #endif /* TIOCGWINSZ */
1876 #endif /* QNX */
1877 #endif /* NONAWS */
1878 }
1879
1880
1881 #ifdef RLOGCODE
1882 _PROTOTYP( int rlog_naws, (void) );
1883 #endif  /* RLOGCODE */
1884
1885 #ifndef NOSIGWINCH
1886 #ifdef SIGWINCH
1887 SIGTYP
1888 winchh(foo) int foo; {                  /* SIGWINCH handler */
1889     int x = 0;
1890 #ifdef CK_TTYFD
1891 #ifndef VMS
1892     extern int ttyfd;
1893 #endif /* VMS */
1894 #endif /* CK_TTYFD */
1895     extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
1896 #ifdef DEBUG
1897     if (deblog) {
1898         debug(F100,"***************","",0);
1899         debug(F100,"SIGWINCH caught","",0);
1900         debug(F100,"***************","",0);
1901 #ifdef NETPTY
1902         debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
1903 #endif /* NETPTY */
1904     }
1905 #endif /* DEUB */
1906     signal(SIGWINCH,winchh);            /* Re-arm the signal */
1907     x = ttgwsiz();                      /* Get new window size */
1908     cmd_rows = tt_rows;                 /* Adjust command screen too */
1909     cmd_cols = tt_cols;
1910
1911 #ifdef CK_TTYFD
1912     if                                  /* If we don't have a connection */
1913 #ifdef VMS                              /* we're done. */
1914       (vmsttyfd() == -1)
1915 #else
1916       (ttyfd == -1)
1917 #endif /* VMS */
1918 #else
1919       (!local)
1920 #endif /* CK_TTYFD */
1921         return;
1922
1923 #ifdef NETPTY
1924     if (pty_fork_pid > -1) {            /* "set host" to a PTY? */
1925         int x;
1926
1927 #ifdef TIOCSWINSZ
1928         struct winsize w;               /* Resize the PTY */
1929         errno = 0;
1930         w.ws_col = tt_cols;
1931         w.ws_row = tt_rows;
1932         w.ws_xpixel = tt_xpixel;
1933         w.ws_ypixel = tt_ypixel;
1934         x = ioctl(ttyfd,TIOCSWINSZ,&w);
1935         debug(F101,"winchh TIOCSWINSZ","",x);
1936         debug(F101,"winchh TIOCSWINSZ errno","",errno);
1937 #endif /* TIOCSWINSZ */
1938
1939         errno = 0;
1940         x = kill(pty_fork_pid,SIGWINCH);
1941         debug(F101,"winchh kill","",x);
1942         debug(F101,"winchh kill errno","",errno);
1943     }
1944 #endif /* NETPTY */
1945
1946 /*
1947   This should be OK.  It might seem that sending this from
1948   interrupt level could interfere with another TELNET IAC string
1949   that was in the process of being sent.  But we always send
1950   TELNET strings with a single write(), which should prevent mixups.
1951   blah_snaws() should protect themselves from being called on the
1952   wrong kind of connection.
1953 */
1954 #ifdef TCPSOCKET
1955 #ifndef NOTTGWSIZ
1956     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
1957         tn_snaws();
1958 #ifdef RLOGCODE
1959         rlog_naws();
1960 #endif /* RLOGCODE */
1961     }
1962 #endif /* NOTTGWSIZ */
1963 #endif /* TCPSOCKET */
1964     SIGRETURN;
1965 }
1966 #endif /* SIGWINCH */
1967 #endif /* NOSIGWINCH */
1968
1969 SIGTYP
1970 sighup(foo) int foo; {                  /* SIGHUP handler */
1971     backgrd = 1;
1972     debug(F100,"***************","",0);
1973     debug(F100,"SIGHUP received","",0);
1974     debug(F100,"***************","",0);
1975     doexit(BAD_EXIT,-1);
1976     /*NOTREACHED*/
1977     SIGRETURN;                          /* Shut picky compilers up... */
1978 }
1979
1980 #ifdef CK_SCO32V4
1981 /* Exists but there is no prototype in the header files */
1982 _PROTOTYP( char * ttyname, (int) );
1983 #else
1984 #ifdef SV68R3V6
1985 _PROTOTYP( char * ttyname, (int) );
1986 #else
1987 #ifdef ultrix
1988 _PROTOTYP( char * ttyname, (int) );
1989 #else
1990 #ifdef HPUX6
1991 _PROTOTYP( char * ttyname, (int) );
1992 #else
1993 #ifdef HPUX5
1994 _PROTOTYP( char * ttyname, (int) );
1995 #else
1996 #ifdef PS2AIX10
1997 _PROTOTYP( char * ttyname, (int) );
1998 #else
1999 #ifdef BSD42
2000 _PROTOTYP( char * ttyname, (int) );
2001 #endif /* BSD42 */
2002 #endif /* PS2AIX10 */
2003 #endif /* HPUX5 */
2004 #endif /* HPUX6 */
2005 #endif /* ultrix */
2006 #endif /* SV68R3V6 */
2007 #endif /* CK_SCO32V4 */
2008
2009 #ifndef SIGUSR1                         /* User-defined signals */
2010 #define SIGUSR1 30
2011 #endif /* SIGUSR1 */
2012
2013 #ifndef SIGUSR2
2014 #define SIGUSR2 31
2015 #endif /* SIGUSR2 */
2016
2017 /*
2018   ignorsigs() sets certain signals to SIG_IGN.  But when a signal is
2019   ignored, it remains ignored across exec(), so we have to restore these
2020   signals before exec(), which is the purpose of restorsigs().
2021 */
2022 static VOID
2023 ignorsigs() {                           /* Ignore these signals */
2024     savquit = signal(SIGQUIT,SIG_IGN);  /* Ignore Quit signal */
2025
2026 #ifdef SIGDANGER                        /* Ignore danger signals */
2027 /*
2028   This signal is sent when the system is low on swap space.  Processes
2029   that don't handle it are candidates for termination.  If swap space doesn't
2030   clear out enough, we still might be terminated via kill() -- nothing we can
2031   do about that!  Conceivably, this could be improved by installing a real
2032   signal handler that warns the user, but that would be pretty complicated,
2033   since we are not always in control of the screen -- e.g. during remote-mode
2034   file transfer.
2035 */
2036     savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
2037 #endif /* SIGDANGER */
2038 #ifdef SIGPIPE
2039 /*
2040   This one comes when a TCP/IP connection is broken by the remote.
2041   We prefer to catch this situation by examining error codes from write().
2042 */
2043     savpipe = signal(SIGPIPE,SIG_IGN);
2044 #endif /* SIGPIPE */
2045     savusr1 = signal(SIGUSR1,SIG_IGN);  /* Ignore user-defined signals */
2046     savusr2 = signal(SIGUSR2,SIG_IGN);
2047 }
2048
2049 VOID
2050 restorsigs() {                          /* Restore these signals */
2051     (VOID) signal(SIGQUIT,savquit);     /* (used in ckufio.c) */
2052 #ifdef SIGDANGER
2053     (VOID) signal(SIGDANGER,savdanger);
2054 #endif /* SIGDANGER */
2055 #ifdef SIGPIPE
2056     (VOID) signal(SIGPIPE,savpipe);
2057 #endif /* SIGPIPE */
2058     (VOID) signal(SIGUSR1,savusr1);
2059     (VOID) signal(SIGUSR2,savusr2);
2060 }
2061
2062 int
2063 sysinit() {
2064     int x;
2065     char * s;
2066 #ifdef CK_UTSNAME
2067     struct utsname name;
2068 #endif /* CK_UTSNAME */
2069
2070     extern char startupdir[];
2071 /*
2072   BEFORE ANYTHING ELSE: Initialize the setuid package.
2073   Change to the user's real user and group ID.
2074   If this can't be done, don't run at all.
2075 */
2076     x = priv_ini();
2077 #ifdef SUIDDEBUG
2078     fprintf(stderr,"PRIV_INI=%d\n",x);
2079 #endif /* SUIDDEBUG */
2080     if (x) {
2081         if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
2082         if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
2083         if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
2084         exit(1);
2085     }
2086     signal(SIGINT,SIG_IGN);             /* Ignore interrupts at first */
2087     signal(SIGFPE,SIG_IGN);             /* Ignore floating-point exceptions */
2088     signal(SIGHUP,sighup);              /* Catch SIGHUP */
2089 #ifndef NOSIGWINCH
2090 #ifdef SIGWINCH
2091     signal(SIGWINCH,winchh);            /* Catch window-size change */
2092 #endif /* SIGWINCH */
2093 #endif /* NOSIGWINCH */
2094
2095 #ifdef SIGXFSZ
2096     signal(SIGXFSZ,SIG_IGN);            /* Ignore writing past file limit */ 
2097 #endif  /* SIGXFSZ */
2098
2099 #ifndef NOJC
2100 /*
2101   Get the initial job control state.
2102   If it is SIG_IGN, that means the shell does not support job control,
2103   and so we'd better not suspend ourselves.
2104 */
2105 #ifdef SIGTSTP
2106     jchdlr = signal(SIGTSTP,SIG_IGN);
2107     if (jchdlr == SIG_IGN) {
2108         jcshell = 0;
2109         debug(F100,"sysinit jchdlr: SIG_IGN","",0);
2110     } else if (jchdlr == SIG_DFL) {
2111         debug(F100,"sysinit jchdlr: SIG_DFL","",0);
2112         jcshell = 1;
2113     } else {
2114         debug(F100,"sysinit jchdlr: other","",0);
2115         jcshell = 3;
2116     }
2117     (VOID) signal(SIGTSTP,jchdlr);      /* Put it back... */
2118 #endif /* SIGTSTP */
2119 #endif /* NOJC */
2120
2121     conbgt(0);                          /* See if we're in the background */
2122     congm();                            /* Get console modes */
2123
2124     (VOID) signal(SIGALRM,SIG_IGN);     /* Ignore alarms */
2125
2126     ignorsigs();                        /* Ignore some other signals */
2127
2128 #ifdef F_SETFL
2129     iniflags = fcntl(0,F_GETFL,0);      /* Get stdin flags */
2130 #endif /* F_SETFL */
2131
2132 #ifdef ultrix
2133     gtty(0,&vanilla);                   /* Get sgtty info */
2134 #else
2135 #ifdef AUX
2136     set42sig();                         /* Don't ask! (hakanson@cs.orst.edu) */
2137 #endif /* AUX */
2138 #endif /* ultrix */
2139 /*
2140   Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
2141   never closes it.  If it is called often enough, we run out of file
2142   descriptors and subsequent open()'s of other devices or files can fail.
2143 */
2144     s = NULL;
2145 #ifndef MINIX
2146     if (isatty(0))                      /* Name of controlling terminal */
2147       s = ttyname(0);
2148     else if (isatty(1))
2149       s = ttyname(1);
2150     else if (isatty(2))
2151       s = ttyname(2);
2152     debug(F110,"sysinit ttyname(0)",s,0);
2153 #endif /* MINIX */
2154
2155 #ifdef BEOS
2156     if (!dftty)
2157       makestr(&dftty,s);
2158 #endif /* BEOS */
2159
2160     if (s)
2161       ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
2162 #ifdef SVORPOSIX
2163     if (!cttnam[0])
2164       ctermid(cttnam);
2165 #endif /* SVORPOSIX */
2166     if (!cttnam[0])
2167       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
2168     debug(F110,"sysinit CTTNAM",CTTNAM,0);
2169     debug(F110,"sysinit cttnam",cttnam,0);
2170
2171     ttgwsiz();                          /* Get window (screen) dimensions. */
2172
2173 #ifndef NOSYSCONF
2174 #ifdef _SC_OPEN_MAX
2175     ckmaxfiles = sysconf(_SC_OPEN_MAX);
2176 #endif /* _SC_OPEN_MAX */
2177 #endif /* NOSYSCONF */
2178
2179 #ifdef Plan9
2180     if (!backgrd) {
2181         consctlfd = open("/dev/consctl", O_WRONLY);
2182         /*noisefd = open("/dev/noise", O_WRONLY)*/
2183     }
2184     ckxech = 1;
2185 #endif /* Plan9 */
2186
2187 #ifdef CK_UTSNAME
2188     if (uname(&name) > -1) {
2189         ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
2190         ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
2191         ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
2192         ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
2193 #ifdef DEBUG
2194         if (deblog) {
2195             debug(F110,"sysinit uname machine",unm_mch,0);
2196             debug(F110,"sysinit uname sysname",unm_nam,0);
2197             debug(F110,"sysinit uname release",unm_rel,0);
2198             debug(F110,"sysinit uname version",unm_ver,0);
2199         }
2200 #endif /* DEBUG */
2201
2202 #ifdef HPUX9PLUS
2203         if (name.machine[5] == '8')
2204           hpis800 = 1;
2205         else
2206           hpis800 = 0;
2207         debug(F101,"sysinit hpis800","",hpis800);
2208 #endif /* HPUX9PLUS */
2209 #ifdef TRU64
2210         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
2211         debug(F110,"sysinit getsysinfo model",unm_mod,0);
2212 #endif /* TRU64 */
2213 #ifdef SOLARIS25
2214         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
2215         debug(F110,"sysinit sysinfo model",unm_mod,0);
2216 #endif /* SOLARIS25 */
2217     }
2218 #endif /* CK_UTSNAME */
2219
2220 #ifdef CK_ENVIRONMENT
2221     {
2222 #ifdef TNCODE
2223         extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
2224         tn_env_prnt[], tn_env_sys[];
2225 #endif /* TNCODE */
2226         extern char uidbuf[];
2227         extern char * whoami();
2228         char *p;
2229 #ifdef CKSENDUID
2230         uidbuf[0] = '\0';
2231 #ifdef IKSD
2232         if (!inserver) {
2233 #endif /* IKSD */
2234             p = getenv("USER");
2235             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
2236             if (!p) p = "";
2237             if (!*p) {
2238                 p = getenv("LOGNAME");
2239                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
2240             }
2241             if (!p) p = "";
2242             if (!*p) {
2243                 p = whoami();
2244                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
2245             }
2246             if (!p) p = "";
2247             ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
2248 #ifdef IKSD
2249         }
2250 #endif /* IKSD */
2251         debug(F110,"sysinit final uidbuf",uidbuf,0);
2252 #endif /* CKSENDUID */
2253
2254 #ifdef TNCODE
2255         if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
2256         if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
2257         if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
2258         if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
2259 #ifdef aegis
2260         ckstrncpy(tn_env_sys,"Aegis",64);
2261 #else
2262 #ifdef Plan9
2263         ckstrncpy(tn_env_sys,"Plan9",64);
2264 #else
2265         ckstrncpy(tn_env_sys,"UNIX",64);
2266 #endif /* Plan9 */
2267 #endif /* aegis */
2268 #endif /* TNCODE */
2269     }
2270 #endif /* CK_ENVIRONMENT */
2271 #ifdef CK_SNDLOC
2272     {
2273         extern char * tn_loc;
2274         char *p;
2275         if (p = getenv("LOCATION"))
2276           if (tn_loc = (char *)malloc((int)strlen(p)+1))
2277             strcpy(tn_loc,p);           /* safe */
2278     }
2279 #endif /* CK_SNDLOC */
2280
2281     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
2282     startupdir[CKMAXPATH] = '\0';
2283     x = strlen(startupdir);
2284     if (x <= 0) {
2285         startupdir[0] = '/';
2286         startupdir[1] = '\0';
2287     } else if (startupdir[x-1] != '/') {
2288         startupdir[x] = '/';
2289         startupdir[x+1] = '\0';
2290     }
2291     debug(F110,"sysinit startupdir",startupdir,0);
2292 #ifdef TTLEBUF
2293     le_init();
2294 #endif /* TTLEBUF */
2295 #ifdef BSD44ORPOSIX
2296     /* This should catch the ncurses platforms */
2297     /* Some platforms don't have putenv(), like NeXTSTEP */
2298     putenv("NCURSES_NO_SETBUF=1");
2299 #endif /* BSD44ORPOSIX */
2300     return(0);
2301 }
2302
2303 /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
2304
2305 int
2306 syscleanup() {
2307 #ifdef F_SETFL
2308     if (iniflags > -1)
2309       fcntl(0,F_SETFL,iniflags);        /* Restore stdin flags */
2310 #endif /* F_SETFL */
2311 #ifdef ultrix
2312     stty(0,&vanilla);                   /* Get sgtty info */
2313 #endif /* ultrix */
2314 #ifdef NETCMD
2315     if (ttpid) kill(ttpid,9);
2316 #endif /* NETCMD */
2317     return(0);
2318 }
2319
2320 /*  T T O P E N  --  Open a tty for exclusive access.  */
2321
2322 /*
2323   Call with:
2324     ttname: character string - device name or network host name.
2325     lcl:
2326   If called with lcl < 0, sets value of lcl as follows:
2327   0: the terminal named by ttname is the job's controlling terminal.
2328   1: the terminal named by ttname is not the job's controlling terminal.
2329   But watch out: if a line is already open, or if requested line can't
2330   be opened, then lcl remains (and is returned as) -1.
2331     modem:
2332   Less than zero: ttname is a network host name.
2333   Zero or greater: ttname is a terminal device name.
2334   Zero means a local connection (don't use modem signals).
2335   Positive means use modem signals.
2336    timo:
2337   0 = no timer.
2338   nonzero = number of seconds to wait for open() to return before timing out.
2339
2340   Returns:
2341     0 on success
2342    -5 if device is in use
2343    -4 if access to device is denied
2344    -3 if access to lock directory denied
2345    -2 upon timeout waiting for device to open
2346    -1 on other error
2347 */
2348 static int ttotmo = 0;                  /* Timeout flag */
2349 /* Flag kept here to avoid being clobbered by longjmp.  */
2350
2351 int
2352 ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
2353
2354 #ifdef BSD44
2355 #define ctermid(x) strcpy(x,"")
2356 #else
2357 #ifdef SVORPOSIX
2358 #ifndef CIE
2359     extern char *ctermid();             /* Wish they all had this! */
2360 #else                                   /* CIE Regulus */
2361 #define ctermid(x) strcpy(x,"")
2362 #endif /* CIE */
2363 #endif /* SVORPOSIX */
2364 #endif /* BSD44 */
2365
2366 #ifdef ultrix
2367     int temp = 0;
2368 #endif /* ultrix */
2369
2370 #ifndef OPENFIRST
2371     char fullname[DEVNAMLEN+1];
2372 #endif /* OPENFIRST */
2373
2374     char * fnam;                        /* Full name after expansion */
2375
2376     int y;
2377
2378 #ifndef pdp11
2379 #define NAMEFD   /* Feature to allow name to be an open file descriptor */
2380 #endif /* pdp11 */
2381
2382 #ifdef NAMEFD
2383     char *p;
2384     debug(F101,"ttopen telnetfd","",telnetfd);
2385 #endif /* NAMEFD */
2386
2387     debug(F110,"ttopen ttname",ttname,0);
2388     debug(F110,"ttopen ttnmsv",ttnmsv,0);
2389     debug(F101,"ttopen modem","",modem);
2390     debug(F101,"ttopen netconn","",netconn);
2391     debug(F101,"ttopen ttyfd","",ttyfd);
2392     debug(F101,"ttopen *lcl","",*lcl);
2393     debug(F101,"ttopen ttmdm","",ttmdm);
2394     debug(F101,"ttopen ttnet","",ttnet);
2395
2396     ttpmsk = 0xff;
2397     lockpid[0] = '\0';
2398
2399     if (ttyfd > -1) {                   /* If device already opened */
2400         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
2401           return(0);                    /* Yes, nothing to do - just return */
2402         ttnmsv[0] = '\0';               /* No, clear out old name */
2403         ttclos(ttyfd);                  /* close old connection.  */
2404     }
2405     wasclosed = 0;                      /* New connection, not closed yet. */
2406     ttpipe = 0;                         /* Assume it's not a pipe */
2407     ttpty = 0;                          /* or a pty... */
2408
2409 #ifdef NETCONN
2410 /*
2411   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
2412   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
2413   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
2414   this point we've obliterated the negative modem type hack, and so would
2415   treat the IP hostname as a device name, and would then fail because of "No
2416   such device or directory".  But the previous connection has left behind some
2417   clues, so let's use them...
2418 */
2419     if (ttyfd < 0) {                    /* Connection is not open */
2420         if (!strcmp(ttname,ttnmsv)) {   /* Old and new names the same? */
2421             if (((netconn > 0) && (ttmdm < 0)) ||
2422                 ((ttnet > 0) &&
2423                  (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
2424                 ) {
2425                 int x, rc;
2426                 x = (ttmdm < 0) ? -ttmdm : ttnet;
2427                 rc = netopen(ttname, lcl, x);
2428                 debug(F111,"ttopen REOPEN netopen",ttname,rc);
2429                 if (rc > -1) {
2430                     netconn = 1;
2431                     xlocal = *lcl = 1;
2432                 } else {
2433                     netconn = 0;
2434                 }
2435                 gotsigs = 0;
2436                 return(rc);
2437             }
2438         }
2439     }
2440 #endif /* NETCONN */
2441
2442 #ifdef MAXNAMLEN
2443     debug(F100,"ttopen MAXNAMLEN defined","",0);
2444 #else
2445     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
2446 #endif
2447
2448 #ifdef BSD4
2449     debug(F100,"ttopen BSD4 defined","",0);
2450 #else
2451     debug(F100,"ttopen BSD4 *NOT* defined","",0);
2452 #endif /* BSD4 */
2453
2454 #ifdef BSD42
2455     debug(F100,"ttopen BSD42 defined","",0);
2456 #else
2457     debug(F100,"ttopen BSD42 *NOT* defined","",0);
2458 #endif /* BSD42 */
2459
2460 #ifdef MYREAD
2461     debug(F100,"ttopen MYREAD defined","",0);
2462 #else
2463     debug(F100,"ttopen MYREAD *NOT* defined","",0);
2464 #endif /* MYREAD */
2465
2466 #ifdef  NETCONN
2467     if (modem < 0) {                    /* modem < 0 = code for network */
2468         int x;
2469         ttmdm = modem;
2470         modem = -modem;                 /* Positive network type number */
2471         fdflag = 0;                     /* Stdio not redirected. */
2472         netconn = 1;                    /* And it's a network connection */
2473         debug(F111,"ttopen net",ttname,modem);
2474 #ifdef NAMEFD
2475         for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
2476         if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
2477             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2478             ttfdflg = 1;                /* We got an open file descriptor */
2479             debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
2480             debug(F101,"ttopen net ttyfd","",ttyfd);
2481             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2482             x = 1;                      /* Return code is "good". */
2483             if (telnetfd) {
2484                 ttnet = NET_TCPB;
2485                 if (ttnproto != NP_TCPRAW)
2486                   ttnproto = NP_TELNET;
2487 #ifdef SUNX25
2488             } else if (x25fd) {
2489                 ttnet = NET_SX25;
2490                 ttnproto = NP_NONE;
2491 #endif /* SUNX25 */
2492             }
2493         } else {                        /* Host name or address given */
2494 #ifdef NETPTY
2495             if (modem == NET_PTY) {
2496                 int x;
2497                 if (nopush) {
2498                     debug(F100,"ttopen PTY: nopush","",0);
2499                     return(-1);
2500                 }
2501                 ttnet = NET_PTY;
2502                 ttnproto = NP_NONE;
2503                 netconn = 1;            /* but we don't use network i/o */
2504                 ttpty = 1;
2505                 debug(F110,"ttopen PTY",ttname,0);
2506                 x = do_pty(&ttyfd,ttname,0);
2507                 if (x > -1) {
2508                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2509                     xlocal = *lcl = 1;  /* It's local */
2510                 } else {
2511                     ttpty = 0;
2512                     netconn = 0;
2513                 }
2514                 gotsigs = 0;
2515                 return(x);
2516             }
2517 #endif /* NETPTY */
2518 #ifdef NETCMD
2519 /*
2520   dup2() is not available on older System V platforms like AT&T 3Bx.  For
2521   those systems we punt by not defining NETCMD, but we might be able to do
2522   better -- see workarounds for this problem in ckufio.c (search for dup2).
2523 */
2524             if (modem == NET_CMD) {
2525                 if (nopush) {
2526                     debug(F100,"ttopen pipe: nopush","",0);
2527                     return(-1);
2528                 }
2529                 if (pipe(pipe0) || pipe(pipe1)) {
2530                     perror("Pipe error");
2531                     return(-1);
2532                 }
2533                 ttpid = fork();         /* Make a fork */
2534
2535                 switch (ttpid) {
2536                   case -1:              /* Error making fork */
2537                     close(pipe0[0]);
2538                     close(pipe0[1]);
2539                     close(pipe1[0]);
2540                     close(pipe1[1]);
2541                     perror("Fork error");
2542                     return(-1);
2543                   case 0:               /* Child. */
2544                     close(pipe0[0]);
2545                     close(pipe1[1]);
2546                     dup2(pipe0[1], 1);
2547                     close(pipe0[1]);
2548                     dup2(pipe1[0], 0);
2549                     close(pipe1[0]);
2550                     system(ttname);
2551                     _exit(0);
2552                   default:              /* Parent */
2553                     close(pipe0[1]);
2554                     close(pipe1[0]);
2555                     fdin = pipe0[0];    /* Read from pipe */
2556                     fdout = pipe1[1];   /* Write to pipe */
2557                     ttout = fdopen(fdout,"w"); /* Get stream so we can */
2558                     if (!ttout) {       /* make it unbuffered. */
2559                         perror("fdopen failure");
2560                         return(-1);
2561                     }
2562                     setbuf(ttout,NULL);
2563                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2564                     xlocal = *lcl = 1;  /* It's local */
2565                     netconn = 1;        /* Call it a network connection */
2566                     ttmdm = modem;      /* Remember network type */
2567                     ttyfd = fdin;
2568                     ttpipe = 1;
2569                     gotsigs = 0;
2570                     return(0);
2571                 }
2572             }
2573 #endif /* NETCMD */
2574 #endif /* NAMEFD */
2575             x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
2576             if (x > -1) {
2577                 ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2578             } else netconn = 0;
2579 #ifdef NAMEFD
2580         }
2581 #endif /* NAMEFD */
2582
2583 #ifdef sony_news                        /* Sony NEWS */
2584         if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
2585             perror("ttopen error getting Kanji mode (network)");
2586             debug(F111,"ttopen error getting Kanji mode","network",0);
2587             km_ext = -1;                /* Make sure this stays undefined. */
2588         }
2589 #endif /* sony_news */
2590
2591         xlocal = *lcl = 1;              /* Network connections are local. */
2592         debug(F101,"ttopen net x","",x);
2593 #ifdef COMMENT
2594 /* Let netopen() do this */
2595         if (x > -1 && !x25fd)
2596           x = tn_ini();                 /* Initialize TELNET protocol */
2597 #endif /* COMMENT */
2598         gotsigs = 0;
2599         return(x);
2600     } else {                            /* Terminal device */
2601 #endif  /* NETCONN */
2602
2603 #ifdef NAMEFD
2604 /*
2605   This code lets you give Kermit an open file descriptor for a serial
2606   communication device, rather than a device name.  Kermit assumes that the
2607   line is already open, locked, conditioned with the right parameters, etc.
2608 */
2609         for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
2610         if (*p == '\0') {
2611             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2612             debug(F111,"ttopen got open fd",ttname,ttyfd);
2613             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2614             if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
2615               xlocal = *lcl = 0;        /* we're in remote mode */
2616             else                        /* otherwise */
2617               xlocal = *lcl = 1;        /* local mode. */
2618             netconn = 0;                /* Assume it's not a network. */
2619             tvtflg = 0;                 /* Might need to initialize modes. */
2620             ttmdm = modem;              /* Remember modem type. */
2621             fdflag = 0;                 /* Stdio not redirected. */
2622             ttfdflg = 1;                /* Flag we were opened this way. */
2623             debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
2624             debug(F101,"ttopen non-net ttyfd","",ttyfd);
2625
2626 #ifdef sony_news                        /* Sony NEWS */
2627             /* Get device Kanji mode */
2628             if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
2629                 perror("ttopen error getting Kanji mode");
2630                 debug(F101,"ttopen error getting Kanji mode","",0);
2631                 km_ext = -1;            /* Make sure this stays undefined. */
2632             }
2633 #endif /* sony_news */
2634             gotsigs = 0;
2635             return(0);                  /* Return success */
2636         }
2637 #endif /* NAMEFD */
2638 #ifdef NETCONN
2639     }
2640 #endif /* NETCONN */
2641
2642 /* Here we have to open a serial device of the given name. */
2643
2644     netconn = 0;                        /* So it's not a network connection */
2645     occt = signal(SIGINT, cctrap);      /* Set Control-C trap, save old one */
2646     sigint_ign = 0;
2647
2648     tvtflg = 0;                 /* Flag for use by ttvt(). */
2649                                 /* 0 = ttvt not called yet for this device */
2650
2651     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
2652     debug(F101,"ttopen fdflag","",fdflag);
2653
2654     ttmdm = modem;                      /* Make this available to other fns */
2655     xlocal = *lcl;                      /* Make this available to other fns */
2656
2657 /* Code for handling bidirectional tty lines goes here. */
2658 /* Use specified method for turning off logins and suppressing getty. */
2659
2660 #ifdef ACUCNTRL
2661     /* Should put call to priv_on() here, but that would be very risky! */
2662     acucntrl("disable",ttname);         /* acucntrl() program. */
2663     /* and priv_off() here... */
2664 #else
2665 #ifdef ATT7300
2666     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
2667       attmodem |= offgetty(ttname);     /* Remember response.  */
2668 #endif /* ATT7300 */
2669 #endif /* ACUCNTRL */
2670
2671 #ifdef OPENFIRST
2672 /*
2673  1985-2001: opens device first then gets lock; reason:
2674  Kermit usually has to run setuid or setgid in order to create a lockfile.
2675  If you give a SET LINE command for a device that happens to be your job's
2676  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
2677  should not create one, and would fail if it tried to if it did not have the
2678  required privileges.  But you can't find out if two tty device names are
2679  equivalent until you have a file descriptor that you can give to ttyname().
2680  But this can cause a race condition between Kermit and [m]getty.  So see
2681  the [#]else part...
2682 */ 
2683
2684 /*
2685  In the following section, we open the tty device for read/write.
2686  If a modem has been specified via "set modem" prior to "set line"
2687  then the O_NDELAY parameter is used in the open, provided this symbol
2688  is defined (e.g. in fcntl.h), so that the program does not hang waiting
2689  for carrier (which in most cases won't be present because a connection
2690  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
2691  would make more sense to first determine if the line is local before
2692  doing this, but because ttyname() requires a file descriptor, we have
2693  to open it first.  See do_open().
2694
2695  Now open the device using the desired treatment of carrier.
2696  If carrier is REQUIRED, then open could hang forever, so an optional
2697  timer is provided.  If carrier is not required, the timer should never
2698  go off, and should do no harm...
2699 */
2700     ttotmo = 0;                         /* Flag no timeout */
2701     debug(F101,"ttopen timo","",timo);
2702     debug(F101,"ttopen xlocal","",xlocal);
2703     if (timo > 0) {
2704         int xx;
2705         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2706         xx = alarm(timo);               /* Timed open() */
2707         debug(F101,"ttopen alarm","",xx);
2708         if (
2709 #ifdef CK_POSIX_SIG
2710             sigsetjmp(sjbuf,1)
2711 #else
2712             setjmp(sjbuf)
2713 #endif /* CK_POSIX_SIG */
2714             ) {
2715             ttotmo = 1;                 /* Flag timeout. */
2716         } else ttyfd = do_open(ttname);
2717         ttimoff();
2718         debug(F111,"ttopen","modem",modem);
2719         debug(F101,"ttopen ttyfd","",ttyfd);
2720         debug(F101,"ttopen alarm return","",ttotmo);
2721     } else {
2722         errno = 0;
2723         ttyfd = do_open(ttname);
2724     }
2725     debug(F111,"ttopen ttyfd",ttname,ttyfd);
2726     if (ttyfd < 0) {                    /* If couldn't open, fail. */
2727         debug(F101,"ttopen errno","",errno);
2728         if (errno > 0 && !quiet)
2729           perror(ttname);               /* Print message */
2730
2731 #ifdef ATT7300
2732         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
2733           ongetty(ttnmsv);              /* yes, restart on tty line */
2734         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
2735 #else
2736 #ifdef ACUCNTRL
2737         /* Should put call to priv_on() here, but that would be risky! */
2738         acucntrl("enable",ttname);      /* acucntrl() program. */
2739         /* and priv_off() here... */
2740 #endif /* ACUNTRL */
2741 #endif /* ATT7300 */
2742
2743         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
2744         if (errno == EACCES) {          /* Device is protected against user */
2745             debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
2746             return(-4);
2747         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2748     }
2749
2750 #ifdef QNX
2751     {
2752         extern int qnxportlock;
2753         x = qnxopencount();
2754         debug(F101,"ttopen qnxopencount","",x);
2755         debug(F101,"ttopen qnxportlock","",qnxportlock);
2756         if (x < 0 && qnxportlock) {
2757             ttclos(0);
2758             printf("?Can't get port open count\n");
2759             printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
2760             return(-1);                 /* Indicate device is in use */
2761         }
2762         if (x > 1) {                    /* 1 == me */
2763             if (qnxportlock)
2764               ttclos(0);
2765               return(-2);               /* Indicate device is in use */
2766             else if (!quiet)
2767               printf("WARNING: \"%s\" looks busy...\n",ttdev);
2768         }
2769     }
2770 #endif /* QNX */
2771
2772 #ifdef Plan9
2773     /* take this opportunity to open the control channel */
2774     if (p9openttyctl(ttname) < 0)
2775 #else
2776     /* Make sure it's a real tty. */
2777     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
2778 #endif /* Plan9 */
2779       {
2780         fprintf(stderr,"%s is not a terminal device\n",ttname);
2781         debug(F111,"ttopen not a tty",ttname,errno);
2782         close(ttyfd);
2783         ttyfd = -1;
2784         wasclosed = 1;
2785         signal(SIGINT,occt);
2786         return(-1);
2787     }
2788
2789 #ifdef aegis
2790         /* Apollo C runtime claims that console pads are tty devices, which
2791          * is reasonable, but they aren't any good for packet transfer. */
2792         ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2793         if (st.all != status_$ok) {
2794             fprintf(stderr, "problem getting tty object type: ");
2795             error_$print(st);
2796         } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
2797             close(ttyfd); ttyfd = -1;
2798             wasclosed = 1;
2799             errno = ENOTTY; perror(ttname);
2800             signal(SIGINT,occt);
2801             return(-1);
2802         }
2803 #endif /* aegis */
2804
2805     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2806
2807     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
2808
2809 /* Caller wants us to figure out if line is controlling tty */
2810
2811     if (*lcl < 0) {
2812         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
2813             xlocal = 0;
2814             debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
2815         } else if (strcmp(ttname,cttnam) == 0) {
2816             xlocal = 0;
2817             debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
2818         } else if (cttnam[0]) {
2819 #ifdef BEBOX_DR7
2820             x = ttnmsv;                 /* ttyname() is broken */
2821 #else
2822             x = ttyname(ttyfd);         /* Get real name of ttname. */
2823 #endif /* BEBOX_DR7 */
2824             if (!x) x = "";
2825             if (*x)
2826               xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
2827             else
2828               xlocal = 1;
2829             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
2830         }
2831     }
2832
2833 #ifndef NOFDZERO
2834 /* Note, the following code was added so that Unix "idle-line" snoopers */
2835 /* would not think Kermit was idle when it was transferring files, and */
2836 /* maybe log people out. */
2837     if (xlocal == 0) {                  /* Remote mode */
2838         if (fdflag == 0) {              /* Standard i/o is not redirected */
2839             debug(F100,"ttopen setting ttyfd = 0","",0);
2840 #ifdef LYNXOS
2841             /* On Lynx OS, fd 0 is open for read only. */
2842             dup2(ttyfd,0);
2843 #endif /* LYNXOS */
2844             close(ttyfd);               /* Use file descriptor 0 */
2845             ttyfd = 0;
2846         } else {                        /* Standard i/o is redirected */
2847             debug(F101,"ttopen stdio redirected","",ttyfd);
2848         }
2849     }
2850 #endif /* NOFDZERO */
2851
2852 /* Now check if line is locked -- if so fail, else lock for ourselves */
2853 /* Note: After having done this, don't forget to delete the lock if you */
2854 /* leave ttopen() with an error condition. */
2855
2856     lkf = 0;                            /* Check lock */
2857     if (xlocal > 0) {
2858         int xx; int xpid;
2859         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
2860             debug(F111,"ttopen ttlock fails",ttname,xx);
2861             /* WARNING - This close() can hang if tty is an empty socket... */
2862             close(ttyfd);               /* Close the device. */
2863             ttyfd = -1;                 /* Erase its file descriptor. */
2864             wasclosed = 1;
2865             signal(SIGINT,occt);        /* Put old SIGINT back. */
2866             sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2867             if (xx == -2) {             /* If lockfile says device in use, */
2868 #ifndef NOUUCP
2869                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2870                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2871                 if (xpid > -1) {        /* If we got a pid */
2872                     if (!quiet)
2873                       printf("Locked by process %d\n",xpid); /* tell them. */
2874                     sprintf(lockpid,"%d",xpid); /* Record it too */
2875                     debug(F110,"ttopen lockpid",lockpid,0);
2876                 } else if (*flfnam) {
2877                     extern char *DIRCMD;
2878                     char *p = NULL;
2879                     int x;
2880                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2881                     p = malloc(x);      /* Print a directory listing. */
2882 /*
2883   Note: priv_on() won't help here, because we do not pass privs along to
2884   to inferior processes, in this case ls.  So if the real user does not have
2885   directory-listing access to the lockfile directory, this will result in
2886   something like "not found".  That's why we try this only as a last resort.
2887 */
2888                     if (p) {            /* If we got the space... */
2889                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2890                         zsyscmd(p);     /* Get listing. */
2891                         if (p) {        /* free the space */
2892                             free(p);
2893                             p = NULL;
2894                         }
2895                     }
2896                 }
2897 #endif /* NOUUCP */
2898                 return(-5);             /* Code for device in use */
2899             } else return(-3);          /* Access denied */
2900         } else lkf = 1;
2901     }
2902 #else  /* OPENFIRST */
2903
2904 /*
2905   27 Oct 2001: New simpler code that gets the lock first and then opens the
2906   device, which eliminates the race condition.  The downside is you can no
2907   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
2908   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
2909   privs, and if it succeeds, it has created a lockfile where it didn't create
2910   one before.
2911 */
2912     xlocal = *lcl;                      /* Is the device my login terminal? */
2913     debug(F111,"ttopen xlocal","A",xlocal);
2914     fnam = ttname;
2915     if (strcmp(ttname,CTTNAM) && netconn == 0) {
2916         if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
2917             if ((int)strlen(fullname) > 0)
2918               fnam = fullname;
2919         }
2920     }
2921     debug(F110,"ttopen fnam",fnam,0);
2922     if (xlocal < 0) {
2923         xlocal = (strcmp(fnam,CTTNAM) != 0);
2924     }
2925     debug(F111,"ttopen xlocal","B",xlocal);
2926
2927     lkf = 0;                            /* No lock yet */
2928     if (xlocal > 0) {                   /* If not... */
2929         int xx; int xpid;
2930         xx = ttlock(fnam);              /* Try to lock it. */
2931         debug(F101,"ttopen ttlock","",xx);
2932         if (xx < 0) {                   /* Can't lock it. */
2933             debug(F111,"ttopen ttlock fails",fnam,xx);
2934             if (xx == -2) {             /* If lockfile says device in use, */
2935 #ifndef NOUUCP
2936                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2937                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2938                 if (xpid > -1) {        /* If we got a pid */
2939                     if (!quiet)
2940                       printf("Locked by process %d\n",xpid); /* tell them. */
2941                     ckstrncpy(lockpid,ckitoa(xpid),16);
2942                     debug(F110,"ttopen lockpid",lockpid,0);
2943 #ifndef NOPUSH
2944                 } else if (flfnam[0] && !nopush) {
2945                     extern char *DIRCMD;
2946                     char *p = NULL;
2947                     int x;
2948                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2949                     p = malloc(x);      /* Print a directory listing. */
2950 /*
2951   Note: priv_on() won't help here, because we do not pass privs along to
2952   to inferior processes, in this case ls.  So if the real user does not have
2953   directory-listing access to the lockfile directory, this will result in
2954   something like "not found".  That's why we try this only as a last resort.
2955 */
2956                     if (p) {            /* If we got the space... */
2957                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2958                         zsyscmd(p);     /* Get listing. */
2959                         if (p) {        /* free the space */
2960                             free(p);
2961                             p = NULL;
2962                         }
2963                     }
2964 #endif /* NOPUSH */
2965                 }
2966 #endif /* NOUUCP */
2967                 return(-5);             /* Code for device in use */
2968             } else return(-3);          /* Access denied */
2969         } else lkf = 1;
2970     }
2971     /* Have lock -- now it's safe to open the device */
2972
2973     debug(F101,"ttopen lkf","",lkf);
2974     debug(F101,"ttopen timo","",timo);
2975
2976     ttotmo = 0;                         /* Flag no timeout */
2977     if (timo > 0) {
2978         int xx;
2979         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2980         xx = alarm(timo);               /* Timed open() */
2981         debug(F101,"ttopen alarm","",xx);
2982         if (
2983 #ifdef CK_POSIX_SIG
2984             sigsetjmp(sjbuf,1)
2985 #else
2986             setjmp(sjbuf)
2987 #endif /* CK_POSIX_SIG */
2988             ) {
2989             ttotmo = 1;                 /* Flag timeout. */
2990         } else {
2991             ttyfd = do_open(fnam);
2992         }
2993         ttimoff();
2994         debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
2995     } else {
2996         errno = 0;
2997         ttyfd = do_open(fnam);
2998         debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
2999     }
3000     if (ttyfd < 0) {                    /* If couldn't open, fail. */
3001         debug(F111,"ttopen errno",fnam,errno);
3002         debug(F111,"ttopen xlocal","C",xlocal);
3003         if (xlocal == 0) {
3004             debug(F100,"ttopen substituting 0","",0);
3005             ttyfd = 0;
3006         } else {
3007             if (errno > 0 && !quiet) {
3008                 debug(F111,"ttopen perror",fnam,errno);
3009                 perror(fnam);           /* Print message */
3010             }
3011             if (ttunlck())                  /* Release the lock file */
3012               fprintf(stderr,"Warning, problem releasing lock\r\n");
3013         }
3014     }
3015
3016     if (ttyfd < 0) {                    /* ttyfd is still < 0? */
3017 #ifdef ATT7300
3018         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
3019           ongetty(ttnmsv);              /* yes, restart on tty line */
3020         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
3021 #else
3022 #ifdef ACUCNTRL
3023         /* Should put call to priv_on() here, but that would be risky! */
3024         acucntrl("enable",fnam);        /* acucntrl() program. */
3025         /* and priv_off() here... */
3026 #endif /* ACUNTRL */
3027 #endif /* ATT7300 */
3028
3029         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
3030         if (errno == EACCES) {          /* Device is protected against user */
3031             debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
3032             return(-4);
3033         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
3034     }
3035
3036 /* Make sure it's a real tty. */
3037
3038 #ifdef Plan9
3039     /* take this opportunity to open the control channel */
3040     if (p9openttyctl(fnam) < 0)       
3041 #else
3042       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
3043 #endif /* Plan9 */
3044         {
3045             fprintf(stderr,"%s is not a terminal device\n",fnam);
3046             debug(F111,"ttopen not a tty",fnam,errno);
3047             if (ttunlck())              /* Release the lock file */
3048               fprintf(stderr,"Warning, problem releasing lock\r\n");
3049             close(ttyfd);
3050             ttyfd = -1;
3051             wasclosed = 1;
3052             signal(SIGINT,occt);
3053             return(-1);
3054         }
3055
3056 #ifdef aegis
3057     /*
3058       Apollo C runtime claims that console pads are tty devices, which
3059       is reasonable, but they aren't any good for packet transfer.
3060     */
3061     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
3062     if (st.all != status_$ok) {
3063         fprintf(stderr, "problem getting tty object type: ");
3064         error_$print(st);
3065     } else if (ttyuid != sio_$uid) {    /* Reject non-SIO lines */
3066         close(ttyfd); ttyfd = -1;
3067         wasclosed = 1;
3068         errno = ENOTTY; perror(fnam);
3069         signal(SIGINT,occt);
3070         return(-1);
3071     }
3072 #endif /* aegis */
3073
3074     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3075
3076     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
3077
3078 /* Caller wants us to figure out if line is controlling tty */
3079
3080     if (*lcl < 0) {
3081         char * s;
3082         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
3083             xlocal = 0;
3084             debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
3085         } else if (strcmp(fnam,cttnam) == 0) {
3086             xlocal = 0;
3087             debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
3088         } else if (cttnam[0]) {
3089 #ifdef BEBOX_DR7
3090             s = ttnmsv;                 /* ttyname() is broken */
3091 #else
3092             s = ttyname(ttyfd);         /* Get real name of ttname. */
3093 #endif /* BEBOX_DR7 */
3094             if (!s) s = "";
3095             if (*s)
3096               xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
3097             else
3098               xlocal = 1;
3099             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
3100         }
3101     }
3102
3103 #ifndef NOFDZERO
3104 /* Note, the following code was added so that Unix "idle-line" snoopers */
3105 /* would not think Kermit was idle when it was transferring files, and */
3106 /* maybe log people out. */
3107     if (xlocal == 0) {                  /* Remote mode */
3108         if (fdflag == 0) {              /* Standard i/o is not redirected */
3109             debug(F100,"ttopen setting ttyfd = 0","",0);
3110 #ifdef LYNXOS
3111             /* On Lynx OS, fd 0 is open for read only. */
3112             dup2(ttyfd,0);
3113 #endif /* LYNXOS */
3114             close(ttyfd);               /* Use file descriptor 0 */
3115             ttyfd = 0;
3116         } else {                        /* Standard i/o is redirected */
3117             debug(F101,"ttopen stdio redirected","",ttyfd);
3118         }
3119     }
3120 #endif /* NOFDZERO */
3121 #endif /* OPENFIRST */
3122
3123 /* Got the line, now set the desired value for local. */
3124
3125     if (*lcl != 0) *lcl = xlocal;
3126
3127 /* Some special stuff for v7... */
3128
3129 #ifdef  V7
3130 #ifndef MINIX
3131     if (kmem[TTY] < 0) {                /*  If open, then skip this.  */
3132         qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
3133         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
3134             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
3135             perror("/dev/kmem");
3136             exit(1);
3137         }
3138     }
3139 #endif /* !MINIX */
3140 #endif /* V7 */
3141
3142 /* No failure returns after this point */
3143
3144 #ifdef ultrix
3145     ioctl(ttyfd, TIOCMODEM, &temp);
3146 #ifdef TIOCSINUSE
3147     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
3148         if (!quiet)
3149           perror(fnam);
3150     }
3151 #endif /* TIOCSINUSE */
3152 #endif /* ultrix */
3153
3154 /* Get tty device settings  */
3155
3156 #ifdef BSD44ORPOSIX                     /* POSIX */
3157     tcgetattr(ttyfd,&ttold);
3158     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
3159     tcgetattr(ttyfd,&ttraw);
3160     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
3161     tcgetattr(ttyfd,&tttvt);
3162     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
3163 #else                                   /* BSD, V7, and all others */
3164 #ifdef ATTSV                            /* AT&T UNIX */
3165     ioctl(ttyfd,TCGETA,&ttold);
3166     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
3167     ioctl(ttyfd,TCGETA,&ttraw);
3168     ioctl(ttyfd,TCGETA,&tttvt);
3169 #else
3170 #ifdef BELLV10
3171     ioctl(ttyfd,TIOCGETP,&ttold);
3172     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
3173     ioctl(ttyfd,TIOCGDEV,&tdold);
3174     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
3175 #else
3176     gtty(ttyfd,&ttold);
3177     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
3178 #endif /* BELLV10 */
3179
3180 #ifdef sony_news                        /* Sony NEWS */
3181     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
3182         perror("ttopen error getting Kanji mode");
3183         debug(F101,"ttopen error getting Kanji mode","",0);
3184         km_ext = -1;                    /* Make sure this stays undefined. */
3185     }
3186 #endif /* sony_news */
3187
3188 #ifdef TIOCGETC
3189     debug(F100,"ttopen TIOCGETC","",0);
3190     tcharf = 0;                         /* In remote mode, also get */
3191     if (xlocal == 0) {                  /* special characters */
3192         if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
3193             debug(F100,"ttopen TIOCGETC failed","",0);
3194         } else {
3195             tcharf = 1;                 /* It worked. */
3196             ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
3197             debug(F100,"ttopen TIOCGETC ok","",0);
3198         }
3199     }
3200 #else
3201     debug(F100,"ttopen TIOCGETC not defined","",0);
3202 #endif /* TIOCGETC */
3203
3204 #ifdef TIOCGLTC
3205     debug(F100,"ttopen TIOCGLTC","",0);
3206     ltcharf = 0;                        /* In remote mode, also get */
3207     if (xlocal == 0) {                  /* local special characters */
3208         if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
3209             debug(F100,"ttopen TIOCGLTC failed","",0);
3210         } else {
3211             ltcharf = 1;                /* It worked. */
3212             ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
3213             debug(F100,"ttopen TIOCGLTC ok","",0);
3214         }
3215     }
3216 #else
3217     debug(F100,"ttopen TIOCGLTC not defined","",0);
3218 #endif /* TIOCGLTC */
3219
3220 #ifdef TIOCLGET
3221     debug(F100,"ttopen TIOCLGET","",0);
3222     lmodef = 0;
3223     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
3224         debug(F100,"ttopen TIOCLGET failed","",0);
3225     } else {
3226         lmodef = 1;
3227         debug(F100,"ttopen TIOCLGET ok","",0);
3228     }
3229 #endif /* TIOCLGET */
3230
3231 #ifdef BELLV10
3232     ioctl(ttyfd,TIOCGETP,&ttraw);
3233     ioctl(ttyfd,TIOCGETP,&tttvt);
3234 #else
3235     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
3236     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
3237 #endif /* BELLV10 */
3238
3239 #endif /* ATTSV */
3240 #endif /* BSD44ORPOSIX */
3241
3242 /* Section for changing line discipline.  It's restored in ttres(). */
3243
3244 #ifdef AIXRS
3245 #ifndef AIX41
3246     { union txname ld_name; int ld_idx = 0;
3247       ttld = 0;
3248         do {
3249           ld_name.tx_which = ld_idx++;
3250           ioctl(ttyfd, TXGETCD, &ld_name);
3251           if (!strncmp(ld_name.tx_name, "rts", 3))
3252             ttld |= 1;
3253         } while (*ld_name.tx_name);
3254         debug(F101,"AIX line discipline","",ttld);
3255       }
3256 #endif /* AIX41 */
3257 #endif /* AIXRS */
3258
3259 #ifdef BSD41
3260 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
3261     { int k;
3262       ioctl(ttyfd, TIOCGETD, &ttld);    /* Get and save line discipline */
3263       debug(F101,"4.1bsd line discipline","",ttld);
3264       k = OTTYDISC;                     /* Switch to "old" discipline */
3265       k = ioctl(ttyfd, TIOCSETD, &k);
3266       debug(F101,"4.1bsd tiocsetd","",k);
3267     }
3268 #endif /* BSD41 */
3269
3270 #ifdef aegis
3271     /* This was previously done before the last two TCGETA or gtty above,
3272      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
3273      * one copy if it here instead, give us a shout!
3274      */
3275     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
3276     if (xlocal) {       /* ignore breaks from local line */
3277         sio_$control((short)ttyfd, sio_$int_enable, false, st);
3278         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
3279     }
3280 #endif /* aegis */
3281
3282 #ifdef VXVE
3283     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
3284     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
3285     ioctl(ttyfd,TCSETA,&ttraw);
3286 #endif /* vxve */
3287
3288 /* If O_NDELAY was used during open(), then remove it now. */
3289
3290 #ifdef O_NDELAY
3291     debug(F100,"ttopen O_NDELAY","",0);
3292     if (xlocal > 0) {
3293       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
3294         debug(F100,"ttopen fcntl O_NDELAY","",0);
3295 #ifndef aegis
3296         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
3297             debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
3298             perror("Can't unset O_NDELAY");
3299         }
3300 #endif /* aegis */
3301         /* Some systems, notably Xenix (don't know how common this is in
3302          * other systems), need special treatment to get rid of the O_NDELAY
3303          * behaviour on read() with respect to carrier presence (i.e. read()
3304          * returning 0 when carrier absent), even though the above fcntl()
3305          * is enough to make read() wait for input when carrier is present.
3306          * This magic, in turn, requires CLOCAL for working when the carrier
3307          * is absent. But if xlocal == 0, presumably you already have CLOCAL
3308          * or you have a carrier, otherwise you wouldn't be running this.
3309          */
3310         debug(F101,"ttopen xlocal","",xlocal);
3311 #ifdef ATTSV
3312 #ifdef BSD44ORPOSIX
3313 #ifdef COMMENT                          /* 12 Aug 1997 */
3314 #ifdef __bsdi__
3315         if (xlocal)
3316           ttraw.c_cflag |= CLOCAL;
3317 #else
3318 #ifdef __FreeBSD__
3319         if (xlocal)
3320           ttraw.c_cflag |= CLOCAL;
3321 #endif /* __FreeBSD__ */
3322 #endif /* __bsdi__ */
3323 #else /* Not COMMENT */
3324 #ifdef CLOCAL
3325         if (xlocal)                     /* Unset this if it's defined. */
3326           ttraw.c_cflag |= CLOCAL;
3327 #endif /* CLOCAL */
3328 #endif /* COMMENT */
3329         debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
3330         if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
3331             debug(F100,"ttopen POSIX tcseattr fails","",0);
3332             perror("tcsetattr");
3333         }
3334 #else /* !BSD44ORPOSIX */
3335         if (xlocal) {
3336             ttraw.c_cflag |= CLOCAL;
3337             debug(F100,"ttopen calling ioctl(TCSETA)","",0);
3338             errno = 0;
3339             if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
3340                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
3341                 perror("ioctl(TCSETA)");
3342             }
3343         }
3344 #endif /* BSD44ORPOSIX */
3345 #endif /* ATTSV */
3346 #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
3347 /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
3348         debug(F100,"ttopen executing close/open","",0);
3349         close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
3350 #endif /* NOCOTFMC */
3351       }
3352     }
3353 #endif /* O_NDELAY */
3354
3355 /* Instruct the system how to treat the carrier, and set a few other tty
3356  * parameters.
3357  *
3358  * This also undoes the temporary setting of CLOCAL that may have been done
3359  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
3360  * prevent the other end of the line from sitting there talking to itself,
3361  * producing garbage when the user performs a connect.
3362  *
3363  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
3364  * Now it thinks CLOCAL is always on. It seems the only real solution for
3365  * Xenix is to switch between the lower and upper case device names.
3366  *
3367  * This section may at some future time expand into setting a complete
3368  * collection of tty parameters, or call a function shared with ttpkt()/
3369  * ttvt() that does so.  On the other hand, the initial parameters are not
3370  * that important, since ttpkt() or ttvt() should always fix that before
3371  * any communication is done.  Well, we'll see...
3372  */
3373     if (xlocal) {
3374         curcarr = -2;
3375         debug(F100,"ttopen calling carrctl","",0);
3376         carrctl(&ttraw, ttcarr == CAR_ON);
3377         debug(F100,"ttopen carrctl ok","",0);
3378
3379 #ifdef COHERENT
3380 #define SVORPOSIX
3381 #endif /* COHERENT */
3382
3383 #ifdef SVORPOSIX
3384         ttraw.c_lflag &= ~ECHO;
3385         ttold.c_lflag &= ~ECHO;
3386 #ifdef BSD44ORPOSIX
3387         y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
3388         debug(F101,"ttopen tcsetattr","",y);
3389 #else
3390         y = ioctl(ttyfd, TCSETA, &ttraw);
3391         debug(F100,"ttopen ioctl","",y);
3392 #endif /* BSD44ORPOSIX */
3393
3394 #else /* BSD, etc */
3395         ttraw.sg_flags &= ~ECHO;
3396         ttold.sg_flags &= ~ECHO;
3397 #ifdef BELLV10
3398         y = ioctl(ttyfd,TIOCSETP,&ttraw);
3399         debug(F100,"ttopen ioctl","",y);
3400 #else
3401         y = stty(ttyfd,&ttraw);
3402         debug(F100,"ttopen stty","",y);
3403 #endif /* BELLV10 */
3404 #endif /* SVORPOSIX */
3405
3406 #ifdef COHERENT
3407 #undef SVORPOSIX
3408 #endif /* COHERENT */
3409
3410         /* ttflui(); */  /*  This fails for some reason.  */
3411     }
3412
3413     /* Get current speed */
3414
3415 #ifndef BEBOX
3416     ttspeed = ttgspd();
3417 #else
3418     ttspeed = 19200;
3419 #endif /* !BEBOX */
3420     debug(F101,"ttopen ttspeed","",ttspeed);
3421
3422     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
3423
3424     debug(F101,"ttopen ttyfd","",ttyfd);
3425     debug(F101,"ttopen *lcl","",*lcl);
3426     debug(F111,"ttopen lock file",flfnam,lkf);
3427     signal(SIGINT,occt);
3428     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3429     gotsigs = 0;
3430     return(0);
3431 }
3432
3433
3434 /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
3435
3436 int
3437 do_open(ttname) char *ttname; {
3438     int flags;
3439
3440 #ifdef QNX6
3441     /* O_NONBLOCK on /dev/tty makes open() fail */
3442     return(priv_opn(ttname, O_RDWR |
3443                     (
3444                      ((int)strcmp(ttname,"/dev/tty") == 0) ?
3445                      0 :
3446                      (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
3447                     )
3448            ); 
3449 #else  /* !QNX6 */
3450
3451 #ifndef O_NDELAY                        /* O_NDELAY not defined */
3452     return(priv_opn(ttname,2));
3453 #else                                   /* O_NDELAY defined */
3454
3455 #ifdef ATT7300
3456 /*
3457  Open comms line without waiting for carrier so initial call does not hang
3458  because state of "modem" is likely unknown at the initial call  -jrd.
3459  If this is needed for the getty stuff to work, and the open would not work
3460  without O_NDELAY when getty is still on, then this special case is ok.
3461  Otherwise, get rid of it. -ske
3462 */
3463     return(priv_opn(ttname, O_RDWR | O_NDELAY));
3464
3465 #else   /* !ATT7300 */
3466
3467     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
3468     flags = O_RDWR;
3469     debug(F101,"do_open xlocal","",xlocal);
3470     debug(F111,"do_open flags A",ttname,flags);
3471     if (xlocal && (ttcarr != CAR_ON))
3472       flags |= O_NDELAY;
3473     debug(F111,"do_open flags B",ttname,flags);
3474     return(priv_opn(ttname, flags));
3475 #endif /* !ATT7300 */
3476 #endif /* O_NDELAY */
3477 #endif /* QNX6 */
3478 }
3479
3480 /*  T T C L O S  --  Close the TTY, releasing any lock.  */
3481
3482 static int ttc_state = 0;               /* ttclose() state */
3483 static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
3484
3485 int
3486 ttclos(foo) int foo; {                  /* Arg req'd for signal() prototype */
3487     int xx, x = 0;
3488     extern int exithangup;
3489
3490     debug(F101,"ttclos ttyfd","",ttyfd);
3491     debug(F101,"ttclos netconn","",netconn);
3492     debug(F101,"ttclos xlocal","",xlocal);
3493 #ifdef NOFDZERO
3494     debug(F100,"ttclos NOFDZERO","",0);
3495 #endif /* NOFDZERO */
3496
3497 #ifdef COMMENT
3498 #ifdef TTLEBUF
3499     le_init();                          /* No need for any of this */
3500 #endif /* TTLEBUF */
3501 #endif /* COMMENT */
3502
3503     if (ttyfd < 0)                      /* Wasn't open. */
3504       return(0);
3505
3506     if (ttfdflg)                        /* If we inherited ttyfd from */
3507       return(0);                        /* another process, don't close it. */
3508
3509     tvtflg = 0;                         /* (some day get rid of this...) */
3510     gotsigs = 0;
3511
3512 #ifdef IKSD
3513     if (inserver) {
3514 #ifdef TNCODE
3515           tn_push();                    /* Place any waiting data into input*/
3516           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
3517           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
3518           tn_reset();                   /* The Reset Telnet Option table.  */
3519 #endif /* TNCODE */
3520 #ifdef CK_SSL
3521           if (ssl_active_flag) {
3522               if (ssl_debug_flag)
3523                 BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
3524               SSL_shutdown(ssl_con);
3525               SSL_free(ssl_con);
3526               ssl_con = NULL;
3527               ssl_active_flag = 0;
3528           }
3529           if (tls_active_flag) {
3530               if (ssl_debug_flag)
3531                 BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
3532               SSL_shutdown(tls_con);
3533               SSL_free(tls_con);
3534               tls_con = NULL;
3535               tls_active_flag = 0;
3536           }
3537 #endif /* CK_SSL */
3538     }
3539 #endif /* IKSD */
3540 #ifdef NETCMD
3541     if (ttpipe) {                       /* We've been using a pipe */
3542         /* ttpipe = 0; */
3543         if (ttpid > 0) {
3544             int wstat;
3545             int statusp;
3546             close(fdin);                /* Close these. */
3547             close(fdout);
3548             fdin = fdout = -1;
3549             kill(ttpid,1);              /* Kill fork with SIGHUP */
3550             while (1) {
3551                 wstat = wait(&statusp);
3552                 if (wstat == ttpid || wstat == -1)
3553                   break;
3554                 pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
3555             }
3556             ttpid = 0;
3557         }
3558         netconn = 0;
3559         wasclosed = 1;
3560         ttyfd = -1;
3561         return(0);
3562     }
3563 #endif /* NETCMD */
3564 #ifdef NETPTY
3565     if (ttpty) {
3566 #ifndef NODOPTY
3567         end_pty();
3568 #endif /* NODOPTY */
3569         close(ttyfd);
3570         netconn = 0;
3571         wasclosed = 1;
3572         ttpty = 0;
3573         ttyfd = -1;
3574         return(0);
3575     }
3576 #endif /* NETPTY */
3577
3578 #ifdef  NETCONN
3579     if (netconn) {                      /* If it's a network connection. */
3580         debug(F100,"ttclos closing net","",0);
3581         netclos();                      /* Let the network module close it. */
3582         netconn = 0;                    /* No more network connection. */
3583         debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
3584         return(0);
3585     }
3586 #endif  /* NETCONN */
3587
3588     if (xlocal) {                       /* We're closing a SET LINE device */
3589 #ifdef FT21                             /* Fortune 2.1-specific items ... */
3590         ioctl(ttyfd,TIOCHPCL, NULL);
3591 #endif /* FT21 */
3592 #ifdef ultrix                           /* Ultrix-specific items ... */
3593 #ifdef TIOCSINUSE
3594         /* Unset the INUSE flag that we set in ttopen() */
3595         ioctl(ttyfd, TIOCSINUSE, NULL);
3596 #endif /* TIOCSINUSE */
3597         ioctl(ttyfd, TIOCNMODEM, &x);
3598 #ifdef COMMENT
3599         /* What was this? */
3600         ioctl(ttyfd, TIOCNCAR, NULL);
3601 #endif /* COMMENT */
3602 #endif /* ultrix */
3603     }
3604
3605     /* This is to prevent us from sticking in tthang() or close(). */
3606
3607 #ifdef O_NDELAY
3608 #ifndef aegis
3609     if (ttyfd > 0) {                    /* But skip it on stdin. */
3610         debug(F100,"ttclos setting O_NDELAY","",0);
3611         x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
3612 #ifdef DEBUG
3613         if (deblog && x == -1) {
3614             perror("Warning - Can't set O_NDELAY");
3615             debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
3616         }
3617 #endif /* DEBUG */
3618     }
3619 #endif /* aegis */
3620 #endif /* O_NDELAY */
3621
3622     x = 0;
3623     ttc_state = 0;
3624     if (xlocal
3625 #ifdef NOFDZERO
3626         || ttyfd > 0
3627 #endif /* NOFDZERO */
3628         ) {
3629         saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
3630         xx = alarm(8);                  /* Allow 8 seconds. */
3631         debug(F101,"ttclos alarm","",xx);
3632         if (
3633 #ifdef CK_POSIX_SIG
3634             sigsetjmp(sjbuf,1)
3635 #else
3636             setjmp(sjbuf)
3637 #endif /* CK_POSIX_SIG */
3638             ) {                         /* Timer went off? */
3639             x = -1;
3640 #ifdef DEBUG
3641             debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
3642             printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
3643 #endif /* DEBUG */
3644         }
3645         /* Hang up the device (drop DTR) */
3646
3647         errno = 0;
3648         debug(F111,"ttclos A",ckitoa(x),ttc_state);
3649         if (ttc_state < 1) {
3650             ttc_state = 1;
3651             debug(F101,"ttclos exithangup","",exithangup);
3652             if (exithangup) {
3653                 alarm(8);               /* Re-arm the timer */
3654                 debug(F101,"ttclos calling tthang()","",x);
3655                 x = tthang();           /* Hang up first, then... */
3656                 debug(F101,"ttclos tthang()","",x);
3657             }
3658 #ifndef CK_NOHUPCL
3659 /*
3660   Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
3661   Suggested by Soewono Effendi.
3662 */
3663 #ifdef HUPCL
3664             else {
3665                 ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
3666 #ifdef BSD44ORPOSIX
3667                 tcsetattr(ttyfd,TCSANOW,&ttold);
3668 #else /* !BSD44ORPOSIX */
3669 #ifdef ATTSV
3670                 ioctl(ttyfd,TCSETAW,&ttold);            
3671 #else  /* !ATTSV */
3672                 stty(ttyfd,&ttold);
3673 #endif  /* ATTSV */
3674 #endif  /* BSD44ORPOSIX */
3675             }
3676 #endif  /* HUPCL */
3677 #endif  /* CK_NOHUPCL */
3678         }
3679         /* Put back device modes as we found them */
3680
3681         errno = 0;
3682         debug(F111,"ttclos B",ckitoa(x),ttc_state);
3683         if (ttc_state < 2) {
3684             ttc_state = 2;
3685             /* Don't try to mess with tty modes if tthang failed() */
3686             /* since it probably won't work. */
3687             if (x > -1) {
3688                 debug(F101,"ttclos calling ttres()","",x);
3689                 signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
3690                 alarm(8);               /* Re-arm the timer */
3691                 x = ttres();            /* Reset device modes. */
3692                 debug(F101,"ttclos ttres()","",x);
3693                 alarm(0);
3694             }
3695         }
3696         /* Close the device */
3697
3698         errno = 0;
3699         debug(F101,"ttclos C","",ttc_state);
3700         if (ttc_state < 3) {
3701             ttc_state = 3;
3702             errno = 0;
3703             debug(F101,"ttclos calling close","",x);
3704             signal(SIGALRM,xtimerh);    /* Re-enable alarm. */
3705             alarm(8);                   /* Re-arm the timer */
3706             x = close(ttyfd);           /* Close the device. */
3707             debug(F101,"ttclos close()","",x);
3708             if (x > -1)
3709               ttc_state = 3;
3710         }
3711         debug(F101,"ttclos D","",ttc_state);
3712         ttimoff();                      /* Turn off timer. */
3713         if (x < 0) {
3714             printf("?WARNING - close failed: %s\n",ttnmsv);
3715 #ifdef DEBUG
3716             if (deblog) {
3717                 printf("errno = %d\n", errno);
3718                 debug(F101,"ttclos failed","",errno);
3719             }
3720 #endif /* DEBUG */
3721         }
3722         /* Unlock after closing but before any getty mumbo jumbo */
3723
3724         debug(F100,"ttclos about to call ttunlck","",0);
3725         if (ttunlck())                  /* Release uucp-style lock */
3726           fprintf(stderr,"Warning, problem releasing lock\r\n");
3727     }
3728
3729 /* For bidirectional lines, restore getty if it was there before. */
3730
3731 #ifdef ACUCNTRL                         /* 4.3BSD acucntrl() method. */
3732     if (xlocal) {
3733         debug(F100,"ttclos ACUCNTRL","",0);
3734         acucntrl("enable",ttnmsv);      /* Enable getty on the device. */
3735     }
3736 #else
3737 #ifdef ATT7300                          /* ATT UNIX PC (3B1, 7300) method. */
3738     if (xlocal) {
3739         debug(F100,"ttclos ATT7300 ongetty","",0);
3740         if (attmodem & DOGETY)          /* Was getty(1m) running before us? */
3741           ongetty(ttnmsv);              /* Yes, restart getty on tty line */
3742         attmodem &= ~DOGETY;            /* No phone in use, getty restored */
3743     }
3744 #endif /* ATT7300 */
3745 #endif /* System-dependent getty-restoring methods */
3746
3747 #ifdef sony_news
3748     km_ext = -1;                        /* Invalidate device's Kanji-mode */
3749 #endif /* sony_news */
3750
3751     ttyfd = -1;                         /* Invalidate the file descriptor. */
3752     wasclosed = 1;
3753     debug(F100,"ttclos done","",0);
3754     return(0);
3755 }
3756
3757 /*  T T H A N G  --  Hangup phone line or network connection.  */
3758 /*
3759   Returns:
3760   0 if it does nothing.
3761   1 if it believes that it hung up successfully.
3762  -1 if it believes that the hangup attempt failed.
3763 */
3764
3765 #define HUPTIME 500                     /* Milliseconds for hangup */
3766
3767 #ifdef COMMENT
3768 /* The following didn't work but TIOCSDTR does work */
3769 #ifdef UNIXWARE
3770 /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
3771 #ifndef POSIX                           /* Such as Unixware 1.x, 2.x */
3772 #ifndef HUP_POSIX
3773 #define HUP_POSIX
3774 #endif /* HUP_POSIX */
3775 #endif /* POSIX */
3776 #endif /* UNIXWARE */
3777 #endif /* COMMENT */
3778
3779 #ifndef USE_TIOCSDTR
3780 #ifdef __NetBSD__
3781 /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
3782 #ifdef TIOCSDTR
3783 #ifdef TIOCCDTR
3784 #define USE_TIOCSDTR
3785 #endif /* TIOCCDTR */
3786 #endif /* TIOCSDTR */
3787 #endif /* __NetBSD__ */
3788 #endif /* USE_TIOCSDTR */
3789
3790 #ifndef HUP_CLOSE_POSIX
3791 #ifdef OU8
3792 #define HUP_CLOSE_POSIX
3793 #else
3794 #ifdef CK_SCOV5
3795 #define HUP_CLOSE_POSIX
3796 #endif /* CK_SCOV5 */
3797 #endif /* OU8 */
3798 #endif /* HUP_CLOSE_POSIX */
3799
3800 #ifdef NO_HUP_CLOSE_POSIX
3801 #ifdef HUP_CLOSE_POSIX
3802 #undef HUP_CLOSE_POSIX
3803 #endif /* HUP_CLOSE_POSIX */
3804 #endif /* NO_HUP_CLOSE_POSIX */
3805
3806 int
3807 tthang() {
3808 #ifdef NOLOCAL
3809     return(0);
3810 #else
3811     int x = 0;                          /* Sometimes used as return code. */
3812 #ifndef POSIX
3813     int z;                              /* worker */
3814 #endif /* POSIX */
3815
3816 #ifdef COHERENT
3817 #define SVORPOSIX
3818 #endif /* COHERENT */
3819
3820 #ifdef SVORPOSIX                        /* AT&T, POSIX, HPUX declarations. */
3821     int spdsav;                         /* for saving speed */
3822 #ifdef HUP_POSIX
3823     int spdsavi;
3824 #else
3825 #ifdef BSD44ORPOSIX
3826     int spdsavi;
3827 #endif /* BSD44ORPOSIX */
3828 #endif /* HUP_POSIX */
3829 #ifdef HPUX
3830 /*
3831   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
3832   about it, just change it to long (or better still, unsigned long).
3833 */
3834     mflag
3835       dtr_down = 00000000000,
3836       modem_rtn,
3837       modem_sav;
3838     char modem_state[64];
3839 #endif /* HPUX */
3840     int flags;                          /* fcntl flags */
3841     unsigned short ttc_save;
3842 #endif /* SVORPOSIX */
3843
3844     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
3845     if (xlocal < 1) return(0);          /* Don't do this if not local */
3846
3847 #ifdef NETCMD
3848     if (ttpipe)
3849       return((ttclos(0) < 0) ? -1 : 1);
3850 #endif /* NETCMD */
3851 #ifdef NETPTY
3852     if (ttpty)
3853       return((ttclos(0) < 0) ? -1 : 1);
3854 #endif /* NETPTY */
3855 #ifdef NETCONN
3856     if (netconn) {                      /* Network connection. */
3857 #ifdef TN_COMPORT
3858         if (istncomport()) {
3859             int rc = tnc_set_dtr_state(0);
3860             if (rc >= 0) {
3861                 msleep(HUPTIME);
3862                 rc = tnc_set_dtr_state(1);
3863             }
3864             return(rc >= 0 ? 1 : -1);
3865         } else
3866 #endif /* TN_COMPORT */
3867           return((netclos() < 0) ? -1 : 1); /* Just close it. */
3868   }
3869 #endif /* NETCONN */
3870
3871 /* From here down, we handle real tty devices. */
3872 #ifdef HUP_POSIX
3873 /*
3874   e.g. for Unixware 2, where we don't have a full POSIX build, we
3875   still have to use POSIX-style hangup.  Thus the duplication of this
3876   and the next case, the only difference being we use a local termios
3877   struct here, since a different model is used elsewhere.
3878
3879   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
3880   even though it compiles and executes without error, doesn't actually
3881   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
3882 */
3883     {
3884         struct termios ttcur;
3885         int x;
3886         debug(F100,"tthang HUP_POSIX style","",0);
3887         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3888         debug(F111,"tthang tcgetattr",ckitoa(errno),x);
3889         if (x < 0) return(-1);
3890         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
3891         debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
3892         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
3893         debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
3894         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
3895         debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
3896         if (x < 0) return(-1);
3897         x = cfsetispeed(&ttcur,B0);
3898         debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
3899         if (x < 0) return(-1);
3900         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3901         debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
3902         if (x < 0) return(-1);
3903         msleep(HUPTIME);                /* Sleep 0.5 sec */
3904         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3905         if (x < 0) return(-1);
3906         debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
3907         x = cfsetispeed(&ttcur,spdsavi);
3908         debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
3909         if (x < 0) return(-1);
3910         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3911         debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
3912         if (x < 0) return(-1);
3913         return(1);
3914     }
3915 #else
3916 #ifdef BSD44ORPOSIX
3917 #ifdef QNX
3918     {
3919         int x;
3920         x = tcdropline(ttyfd,500);
3921         debug(F101,"tthang QNX tcdropline","",x);
3922         ttcur.c_cflag |= CLOCAL;
3923         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3924         debug(F101,"tthang QNX tcsetattr restore","",x);
3925         if (x < 0) {
3926             debug(F101,"tthang QNX tcsetattr restore errno","",errno);
3927             return(-1);
3928         }
3929         /* Fix flags - ensure O_NONBLOCK is off */
3930
3931         errno = 0;
3932         debug(F101,"tthang QNX iniflags","",iniflags);
3933         if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
3934             debug(F101,"tthang QNX F_SETFL errno","",errno);
3935             return(-1);
3936         }
3937         return(x);
3938     }
3939 #else  /* QNX */
3940     {
3941         int x;
3942 #ifdef USE_TIOCSDTR
3943         debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
3944         errno = 0;
3945         x = ioctl(ttyfd, TIOCCDTR, NULL);
3946         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
3947         if (x < 0) return(-1);
3948         msleep(HUPTIME);                /* Sleep 0.5 sec */
3949         errno = 0;
3950         x = ioctl(ttyfd, TIOCSDTR, NULL);
3951         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
3952         if (x < 0) return(-1);
3953 #else  /* USE_TIOCSDTR */
3954
3955 #ifdef HUP_CLOSE_POSIX
3956 /*
3957   In OSR5 versions where TIOCSDTR is not defined (up to and including at
3958   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
3959   don't work, and no other APIs are available that do work.  In this case
3960   we have to drop DTR by brute force: close and reopen the port.  This
3961   code actually works, but all the steps are crucial: setting CLOCAL, the
3962   O_NDELAY manipulations, etc.
3963 */
3964         debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
3965         debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
3966         debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
3967         errno = 0;
3968         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3969         debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
3970         if (x < 0) {
3971             debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
3972             return(-1);
3973         }
3974         errno = 0;
3975
3976         x = close(ttyfd);               /* Close without releasing lock */
3977         if (x < 0) {
3978             debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
3979             return(-1);
3980         }
3981         errno = 0;
3982         x = msleep(500);                /* Pause half a second */
3983         if (x < 0) {                    /* Or if that doesn't work, 1 sec */
3984             debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
3985             sleep(1);
3986         }
3987         errno = 0;
3988         ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
3989         debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
3990         if (ttyfd < 0) {
3991             debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
3992             return(-1);
3993         }
3994         debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
3995
3996         /* Restore previous attributes */
3997
3998         errno = 0;
3999         tvtflg = 0;
4000         ttcur.c_cflag |= CLOCAL;
4001         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4002         debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
4003         if (x < 0) {
4004             debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
4005                   "",errno);
4006             return(-1);
4007         }
4008         /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
4009
4010         errno = 0;
4011         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
4012             debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
4013             return(-1);
4014         }
4015         debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4016         errno = 0;
4017         x &= ~(O_NONBLOCK|O_NDELAY);
4018         debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
4019         debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
4020         if (fcntl(ttyfd, F_SETFL, x) == -1) {
4021             debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
4022             return(-1);
4023         }
4024 #ifdef DEBUG
4025         if (deblog) {
4026             if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
4027                 debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4028                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
4029                       "",x&O_NONBLOCK);
4030                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
4031                       "",x&O_NDELAY);
4032             }
4033         }
4034 #endif /* DEBUG */
4035
4036 #else  /* HUP_CLOSE_POSIX */
4037         
4038         /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
4039
4040         debug(F100,"tthang BSD44ORPOSIX B0","",0);
4041         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
4042         debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
4043         if (x < 0) return(-1);
4044         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
4045         debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
4046         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
4047         debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
4048         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
4049         debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
4050         if (x < 0) return(-1);
4051         x = cfsetispeed(&ttcur,B0);
4052         debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
4053         if (x < 0) return(-1);
4054         /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
4055         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4056         debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
4057         if (x < 0) return(-1);
4058         msleep(HUPTIME);                /* Sleep 0.5 sec */
4059         debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
4060         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
4061         debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
4062         if (x < 0) return(-1);
4063         debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
4064         x = cfsetispeed(&ttcur,spdsavi);
4065         debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
4066         if (x < 0) return(-1);
4067         ttcur.c_cflag |= CLOCAL;        /* Don't expect CD after hangup */
4068         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4069         debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
4070         if (x < 0) return(-1);
4071
4072 #endif /* HUP_CLOSE_POSIX */
4073 #endif /* USE_TIOCSDTR */
4074
4075         return(1);
4076     }
4077
4078 #endif /* QNX */
4079 #else /* BSD44ORPOSIX */
4080
4081 #ifdef aegis                            /* Apollo Aegis */
4082     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
4083     msleep(HUPTIME);                                    /* pause */
4084     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
4085     return(1);
4086 #endif /* aegis */
4087
4088 #ifdef ANYBSD                           /* Any BSD version. */
4089 #ifdef TIOCCDTR                         /* Except those that don't have this */
4090     debug(F100,"tthang BSD style","",0);
4091     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {  /* Clear DTR. */
4092         debug(F101,"tthang TIOCCDTR fails","",errno);
4093         return(-1);
4094     }
4095     msleep(HUPTIME);                    /* For about 1/2 sec */
4096     errno = 0;
4097     x = ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
4098     if (x < 0) {
4099         /*
4100           For some reason, this tends to fail with "no such device or address"
4101           but the operation still works, probably because of the close/open
4102           later on.  So let's not scare the user unnecessarily here.
4103         */
4104         debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
4105         x = 1;                          /* Pretend we succeeded */
4106     } else if (x == 0) x = 1;           /* Success */
4107 #ifdef COMMENT
4108 #ifdef FT21
4109     ioctl(ttyfd, TIOCSAVEMODES, 0);
4110     ioctl(ttyfd, TIOCHPCL, 0);
4111     close(ttyfd);                       /* Yes, must do this twice */
4112     if ((ttyfd = open(ttnmsv,2)) < 0)   /* on Fortune computers... */
4113       return(-1);                       /* (but why?) */
4114     else x = 1;
4115 #endif /* FT21 */
4116 #endif /* COMMENT */
4117 #endif /* TIOCCDTR */
4118     close(do_open(ttnmsv));             /* Clear i/o error condition */
4119     errno = 0;
4120 #ifdef COMMENT
4121 /* This is definitely dangerous.  Why was it here? */
4122     z = ttvt(ttspeed,ttflow);           /* Restore modes. */
4123     debug(F101,"tthang ttvt returns","",z);
4124     return(z < 0 ? -1 : 1);
4125 #else
4126     return(x);
4127 #endif /* COMMENT */
4128 #endif /* ANYBSD */
4129
4130 #ifdef ATTSV
4131 /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
4132
4133 #ifdef HPUX
4134 /* Hewlett Packard allows explicit manipulation of modem signals. */
4135
4136 #ifdef COMMENT
4137 /* Old way... */
4138     debug(F100,"tthang HP-UX style","",0);
4139     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
4140       return(-1);                                  /* oops, can't. */
4141     msleep(HUPTIME);                               /* Pause half a second. */
4142     x = 1;                                         /* Set return code */
4143     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
4144         if ((modem_rtn & MDCD) != 0)               /* Check if CD is low. */
4145           x = -1;                                  /* CD didn't drop, fail. */
4146     } else x = -1;
4147
4148     /* Even if above calls fail, RTS & DTR should be turned back on. */
4149     modem_rtn = MRTS | MDTR;
4150     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
4151     return(x);
4152 #else
4153 /* New way, from Hellmuth Michaelis */
4154     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
4155     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
4156         debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
4157         return(-1);
4158     }
4159     sprintf(modem_state,"%#lx",modem_rtn);
4160     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
4161     modem_sav = modem_rtn;              /* Save current modem signals */
4162     modem_rtn &= ~MDTR;                 /* Turn DTR bit off */
4163     sprintf(modem_state,"%#lx",modem_rtn);
4164     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
4165     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
4166         debug(F100,"tthang HP-UX: can't lower DTR!","",0);
4167         return(-1);                     /* oops, can't. */
4168     }
4169     msleep(HUPTIME);                    /* Pause half a second. */
4170     x = 1;                              /* Set return code */
4171     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
4172         sprintf(modem_state,"%#lx",modem_rtn);
4173         debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
4174         if ((modem_rtn & MDCD) != 0) {  /* Check if CD is low. */
4175             debug(F100,"tthang HP-UX: DCD not down","",0);
4176             x = -1;                     /* CD didn't drop, fail. */
4177         } else {
4178             debug(F100,"tthang HP-UX: DCD down","",0);
4179         }
4180     } else {
4181         x = -1;
4182         debug(F100,"tthang HP-UX: can't get DCD status !","",0);
4183     }
4184
4185     /* Even if above calls fail, DTR should be turned back on. */
4186
4187     modem_sav |= MDTR;
4188     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
4189         x = -1;
4190         debug(F100,"tthang HP-UX: can't set saved state","",0);
4191     } else {
4192         sprintf(modem_state,"%#lx",modem_sav);
4193         debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
4194     }
4195     return(x);
4196 #endif /* COMMENT */
4197
4198 #else /* AT&T but not HP-UX */
4199
4200 /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
4201 /* It is not known how many, if any, systems actually implement them, */
4202 /* so we include them here in ifdef's. */
4203
4204 /*
4205   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
4206   gives error 22 (invalid argument).
4207 */
4208 #ifndef _IBMR2
4209 /*
4210   No modem-signal twiddling for IBM RT PC or RS/6000.
4211   In AIX 3.1 and earlier, the ioctl() call is broken.
4212   This code could be activated for AIX 3.1 with PTF 2006 or later
4213   (e.g. AIX 3.2), but close/open does the job too, so why bother.
4214 */
4215 #ifdef TIOCMBIS                         /* Bit Set */
4216 #ifdef TIOCMBIC                         /* Bit Clear */
4217 #ifdef TIOCM_DTR                        /* DTR */
4218
4219 /* Clear DTR, sleep 300 msec, turn it back on. */
4220 /* If any of the ioctl's return failure, go on to the next section. */
4221
4222     z = TIOCM_DTR;                      /* Code for DTR. */
4223 #ifdef COMMENT
4224 /*
4225   This was the cause of the troubles with the Solaris Port Monitor.
4226   The problem is: RTS never comes back on.  Moral: Don't do it!
4227   (But why doesn't it come back on?  See the TIOCMBIS call...)
4228 */
4229 #ifdef TIOCM_RTS                        /* Lower RTS too if symbol is known. */
4230     z |= TIOCM_RTS;
4231 #endif /* TIOCM_RTS */
4232 #endif /* COMMENT */
4233
4234     debug(F101,"tthang TIOCM signal mask","",z);
4235     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
4236         debug(F100,"tthang TIOCMBIC ok","",0);
4237         msleep(HUPTIME);                   /* Pause half a second. */
4238         if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
4239             debug(F100,"tthang TIOCMBIS ok","",0);
4240 #ifndef CLSOPN
4241             return(1);                  /* Success, done. */
4242 #endif /* CLSOPN */
4243         } else {                        /* Couldn't raise, continue. */
4244             debug(F101,"tthang TIOCMBIS errno","",errno);
4245         }
4246     } else {                            /* Couldn't lower, continue. */
4247         debug(F101,"tthang TIOCMBIC errno","",errno);
4248     }
4249 #endif /* TIOCM_DTR */
4250 #endif /* TIOCMBIC */
4251 #endif /* TIOCMBIS */
4252 #endif /* _IBMR2 */
4253
4254 /*
4255   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
4256   two AT&T-based systems seem to do this the same way.  The object is simply
4257   to turn off DTR and then turn it back on.  SVID says the universal method
4258   for turning off DTR is to set the speed to zero, and this does seem to do
4259   the trick in all cases.  But neither SVID nor any known man pages say how to
4260   turn DTR back on again.  Some variants, like most Xenix implementations,
4261   raise DTR again when the speed is restored to a nonzero value.  Others
4262   require the device to be closed and opened again, but this is risky because
4263   getty could seize the device during the instant it is closed.
4264 */
4265
4266 /* Return code for ioctl failures... */
4267 #ifdef ATT6300
4268     x = 1;                              /* ATT6300 doesn't want to fail... */
4269 #else
4270     x = -1;
4271 #endif /* ATT6300 */
4272
4273     debug(F100,"tthang get settings","",0);
4274     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
4275       return(x);                        /* Fail if this doesn't work. */
4276     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
4277       return(x);
4278     ttc_save = ttcur.c_cflag;           /* Remember current speed. */
4279     spdsav = ttc_save & CBAUD;
4280     debug(F101,"tthang speed","",spdsav);
4281
4282 #ifdef O_NDELAY
4283     debug(F100,"tthang turning O_NDELAY on","",0);
4284     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
4285 #endif /* O_NDELAY */
4286
4287 #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
4288     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4289 #else
4290 #ifdef RTAIX
4291     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4292 #else          /* This way really works but may be dangerous */
4293 #ifdef u3b2
4294     ttcur.c_cflag = ~(CBAUD|CLOCAL);    /* Special for AT&T 3B2s */
4295                                         /* (CLOCAL must be OFF) */
4296 #else
4297 #ifdef SCO3R2                           /* SCO UNIX 3.2 */
4298 /*
4299   This is complete nonsense, but an SCO user claimed this change made
4300   hanging up work.  Comments from other SCO UNIX 3.2 users would be
4301   appreciated.
4302 */
4303     ttcur.c_cflag = CBAUD|B0;
4304 #else
4305 #ifdef AIXRS                            /* AIX on RS/6000 */
4306 /*
4307   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
4308   even though you can do it on the built-in port and the 8- and 16-port
4309   adapters.  (Untested on 128-port adapter.)
4310 */
4311     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
4312 #else                                   /* None of the above */
4313 /*
4314   Set everything, including the speed, to zero, except for the CLOCAL
4315   and HUPCL bits.
4316 */
4317     ttcur.c_cflag = CLOCAL|HUPCL;
4318 #endif /* AIXRS */
4319 #endif /* SCO3R2 */
4320 #endif /* u3b2 */
4321 #endif /* RTAIX */
4322 #endif /* ATT7300 */
4323
4324 #ifdef COMMENT
4325     /* and if none of those work, try one of these... */
4326     ttcur.c_cflag = 0;
4327     ttcur.c_cflag = CLOCAL;
4328     ttcur.c_cflag &= ~(CBAUD|HUPCL);
4329     ttcur.c_cflag &= ~(CBAUD|CREAD);
4330     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
4331     /* or other combinations */
4332 #endif /* COMMENT */
4333
4334 #ifdef TCXONC
4335     debug(F100,"tthang TCXONC","",0);
4336     if (ioctl(ttyfd, TCXONC, 1) < 0) {
4337         debug(F101,"tthang TCXONC failed","",errno);
4338     }
4339 #endif /* TCXONC */
4340
4341 #ifdef TIOCSTART
4342     debug(F100,"tthang TIOCSTART","",0);
4343     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
4344         debug(F101,"tthang TIOCSTART failed","",errno);
4345     }
4346 #endif /* TIOCSTART */
4347
4348     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
4349         debug(F101,"tthang TCSETAF failed","",errno);
4350         fcntl(ttyfd, F_SETFL, flags);   /* Restore flags */
4351         return(-1);                     /* before returning. */
4352     }
4353     msleep(300);                        /* Give modem time to notice. */
4354
4355 #ifndef NOCOTFMC
4356
4357 /* Now, even though it doesn't say this in SVID or any man page, we have */
4358 /* to close and reopen the device.  This is not necessary for all systems, */
4359 /* but it's impossible to predict which ones need it and which ones don't. */
4360
4361 #ifdef ATT7300
4362 /*
4363   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
4364   related ioctl's for their internal modems.  attmodem has getty status and
4365   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
4366   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
4367   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
4368   The only way to undo the damage is to close the fd and then reopen it.
4369 */
4370     if (attmodem & ISMODEM) {
4371         debug(F100,"tthang attmodem close/open","",0);
4372         ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
4373         ioctl(ttyfd,PIOCDISC,&dialer);  /* Disconnect phone. */
4374         close(ttyfd);                   /* Close and reopen the fd. */
4375         ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
4376         attmodem &= ~ISMODEM;           /* Phone no longer in use. */
4377     }
4378 #else /* !ATT7300 */
4379 /* It seems we have to close and open the device for other AT&T systems */
4380 /* too, and this is the place to do it.  The following code does the */
4381 /* famous close(open(...)) magic by default.  If that doesn't work for you, */
4382 /* then try uncommenting the following statement or putting -DCLSOPN in */
4383 /* the makefile CFLAGS. */
4384
4385 /* #define CLSOPN */
4386
4387 #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
4388
4389 #ifdef O_NDELAY
4390 #define OPENFLGS O_RDWR | O_NDELAY
4391 #else
4392 #define OPENFLGS O_RDWR
4393 #endif
4394
4395 #ifndef CLSOPN
4396 /* This method is used by default, i.e. unless CLSOPN is defined. */
4397 /* It is thought to be safer because there is no window where getty */
4398 /* can seize control of the device.  The drawback is that it might not work. */
4399
4400     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
4401     close(priv_opn(ttnmsv, OPENFLGS));
4402
4403 #else
4404 /* This method is used if you #define CLSOPN.  It is more likely to work */
4405 /* than the previous method, but it's also more dangerous. */
4406
4407     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
4408     close(ttyfd);
4409     msleep(10);
4410     ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
4411 #endif /* CLSOPN */
4412 #undef OPENFLGS
4413
4414 #endif /* SCO32 */
4415 #endif /* ATT7300 */
4416
4417 #endif /* NOCOTFMC */
4418
4419 /* Now put all flags & modes back the way we found them. */
4420 /* (Does the order of ioctl & fcntl matter ? ) */
4421
4422     debug(F100,"tthang restore settings","",0);
4423     ttcur.c_cflag = ttc_save;           /* Get old speed back. */
4424     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
4425       return(-1);
4426 #ifdef O_NDELAY
4427 /*
4428   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
4429   After closing a modem line, the modem will probably not be asserting
4430   carrier any more, so we should not require carrier any more.  If this
4431   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
4432   than O_NDELAY.
4433 */
4434     flags &= ~O_NDELAY;                 /* Don't require carrier on reopen */
4435 #endif /* O_NDELAY */
4436     if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
4437       return(-1);
4438
4439     return(1);
4440 #endif /* not HPUX */
4441 #endif /* ATTSV */
4442 #endif /* BSD44ORPOSIX */
4443 #endif /* HUP_POSIX */
4444 #endif /* NOLOCAL */
4445 }
4446
4447 /*
4448   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
4449   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
4450   LPASS8 business seems to have been causing trouble for everybody but me!
4451   For example, Annex terminal servers, commonly used with Encore computers,
4452   do not support LPASS8 even though the Encore itself does.  Ditto for many
4453   other terminal servers, TELNET connections, rlogin connections, etc etc.
4454   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
4455   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
4456   off for everybody.  That means we goes back to using raw mode, with no
4457   flow control.  Phooey.
4458
4459   NOTE: This must be done before the first reference to LPASS8 in this file,
4460   and after the last #include statment.
4461 */
4462 #ifdef LPASS8
4463 #undef LPASS8
4464 #endif /* LPASS8 */
4465
4466 /*  T T R E S  --  Restore terminal to "normal" mode.  */
4467
4468 /* ske@pkmab.se: There are two choices for what this function should do.
4469  * (1) Restore the tty to current "normal" mode, with carrier treatment
4470  * according to ttcarr, to be used after every kermit command. (2) Restore
4471  * the tty to the state it was in before kermit opened it. These choices
4472  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
4473  * is currently being called as in choice (1), but ttold basically holds
4474  * the initial parameters, as in (2), and the description at the beginning
4475  * of this file says (2).
4476  *
4477  * I don't think restoring tty parameters after all kermit commands makes
4478  * much of a difference.  Restoring them upon exit from kermit may be of
4479  * some use in some cases (when the line is not restored automatically on
4480  * close, by the operating system).
4481  *
4482  * I can't choose which one it should be, so I haven't changed it. It
4483  * probably works as it is, too. It would probably even work even with
4484  * ttres() entirely deleted...
4485  *
4486  * (from fdc: Actually, this function operates in remote mode too, so
4487  * it restores the console (command) terminal to whatever mode it was
4488  * in before packet operations began, so that commands work right again.)
4489  */
4490 int
4491 ttres() {                               /* Restore the tty to normal. */
4492     int x;
4493
4494     if (ttyfd < 0) return(-1);          /* Not open. */
4495
4496     if (ttfdflg) return(0);             /* Don't mess with terminal modes if */
4497                                         /* we got ttyfd from another process */
4498 #ifdef  NETCONN
4499     if (netconn) {                      /* Network connection */
4500         tvtflg = 0;
4501 #ifdef TCPSOCKET
4502 #ifdef TCP_NODELAY
4503         {
4504             extern int tcp_nodelay;     /* Just put this back if necessary */
4505             if (ttnet == NET_TCPB) {
4506                 if (nodelay_sav > -1) {
4507                     no_delay(ttyfd,nodelay_sav);
4508                     nodelay_sav = -1;
4509                 }
4510             }
4511         }
4512 #endif /* TCP_NODELAY */
4513 #ifdef TN_COMPORT
4514         if (istncomport()) {
4515             int rc = -1;
4516             if ((rc = tnsetflow(ttflow)) < 0)
4517               return(rc);
4518             if (ttspeed <= 0) 
4519               ttspeed = tnc_get_baud();
4520             else if ((rc = tnc_set_baud(ttspeed)) < 0)
4521               return(rc);
4522             tnc_set_datasize(8);
4523             tnc_set_stopsize(stopbits);
4524
4525 #ifdef HWPARITY
4526             if (hwparity) {
4527                 switch (hwparity) {
4528                   case 'e':                     /* Even */
4529                     debug(F100,"ttres 8 bits + even parity","",0);
4530                     tnc_set_parity(3);
4531                     break;
4532                   case 'o':                     /* Odd */
4533                     debug(F100,"ttres 8 bits + odd parity","",0);
4534                     tnc_set_parity(2);
4535                     break;
4536                   case 'm':                     /* Mark */
4537                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
4538                     tnc_set_parity(4);
4539                     break;
4540                   case 's':                     /* Space */
4541                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
4542                     tnc_set_parity(5);
4543                     break;
4544                 }
4545             } else
4546 #endif /* HWPARITY */
4547             {
4548                 tnc_set_parity(1);              /* None */
4549             }
4550             tvtflg = 0;
4551             return(0);
4552         }
4553 #endif /* TN_COMPORT */
4554 #endif /* TCPSOCKET */
4555         return(0);
4556     }
4557 #endif  /* NETCONN */
4558 #ifdef NETCMD
4559     if (ttpipe) return(0);
4560 #endif /* NETCMD */
4561 #ifdef NETPTY
4562     if (ttpty) return(0);
4563 #endif /* NETPTY */
4564
4565 /* Real terminal device, so restore its original modes */
4566
4567 #ifdef BSD44ORPOSIX                     /* For POSIX like this */
4568     debug(F100,"ttres BSD44ORPOSIX","",0);
4569     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
4570 #else                                   /* For all others... */
4571 #ifdef ATTSV                            /* For AT&T versions... */
4572     debug(F100,"ttres ATTSV","",0);
4573     x = ioctl(ttyfd,TCSETAW,&ttold);    /* Restore tty modes this way. */
4574 #else
4575 /* Here we restore the modes for BSD */
4576
4577 #ifdef LPASS8                           /* Undo "pass8" if it were done */
4578     if (lmodef) {
4579         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4580           debug(F100,"ttres TIOCLSET failed","",0);
4581         else
4582           debug(F100,"ttres TIOCLSET ok","",0);
4583     }
4584 #endif /* LPASS8 */
4585
4586 #ifdef CK_DTRCTS                   /* Undo hardware flow if it were done */
4587     if (lmodef) {
4588         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4589           debug(F100,"ttres TIOCLSET failed","",0);
4590         else
4591           debug(F100,"ttres TIOCLSET ok","",0);
4592     }
4593 #endif /* CK_DTRCTS */
4594
4595 #ifdef TIOCGETC                         /* Put back special characters */
4596     if (tcharf && (xlocal == 0)) {
4597         if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
4598           debug(F100,"ttres TIOCSETC failed","",0);
4599         else
4600           debug(F100,"ttres TIOCSETC ok","",0);
4601     }
4602 #endif /* TIOCGETC */
4603
4604 #ifdef TIOCGLTC                         /* Put back local special characters */
4605     if (ltcharf && (xlocal == 0)) {
4606         if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
4607           debug(F100,"ttres TIOCSLTC failed","",0);
4608         else
4609           debug(F100,"ttres TIOCSLTC ok","",0);
4610     }
4611 #endif /* TIOCGLTC */
4612
4613 #ifdef BELLV10
4614     debug(F100,"ttres BELLV10","",0);
4615     x = ioctl(ttyfd,TIOCSETP,&ttold);   /* Restore both structs */
4616     x = ioctl(ttyfd,TIOCSDEV,&tdold);
4617 #else
4618     debug(F100,"ttres stty","",0);
4619     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
4620 #endif /* BELLV10 */
4621
4622     if (!xlocal)
4623       msleep(100);                      /* This replaces sleep(1)... */
4624                                         /* Put back sleep(1) if tty is */
4625                                         /* messed up after close. */
4626 #endif /* ATTSV */
4627 #endif /* BSD44ORPOSIX */
4628
4629     debug(F101,"ttres result","",x);
4630 #ifndef QNX
4631     if (x < 0) debug(F101,"ttres errno","",errno);
4632 #endif /* QNX */
4633
4634 #ifdef AIXRS
4635 #ifndef AIX41
4636     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
4637     debug(F101,"ttres AIX line discipline rts restore","",x);
4638 #endif /* AIX41 */
4639 #endif /* AIXRS */
4640
4641 #ifdef BSD41
4642     if (ttld > -1) {                    /* Put back line discipline */
4643         x = ioctl(ttyfd, TIOCSETD, &ttld);
4644         debug(F101,"ttres BSD41 line discipline restore","",x);
4645         if (x < 0) debug(F101,"...ioctl errno","",errno);
4646         ttld = -1;
4647     }
4648 #endif /* BSD41 */
4649
4650 #ifdef sony_news
4651     x = xlocal ? km_ext : km_con;       /* Restore Kanji mode. */
4652     if (x != -1) {                      /* Make sure we know original modes. */
4653         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
4654             perror("ttres can't set Kanji mode");
4655             debug(F101,"ttres error setting Kanji mode","",x);
4656             return(-1);
4657         }
4658     }
4659     debug(F100,"ttres set Kanji mode ok","",0);
4660 #endif /* sony_news */
4661
4662     tvtflg = 0;                         /* Invalidate terminal mode settings */
4663     debug(F101,"ttres return code","",x);
4664     return(x);
4665 }
4666
4667 #ifndef NOUUCP
4668
4669 /*  T T C H K P I D  --  Check lockfile pid  */
4670 /*
4671   Read pid from lockfile named f, check that it's still valid.
4672   If so, return 1.
4673   On failure to read pid, return 1.
4674   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
4675 */
4676 static int
4677 ttchkpid(f) char *f; {
4678     int pid, mypid, x;
4679     pid = ttrpid(f);                    /* Read pid from file. */
4680     if (pid > -1) {                     /* If we were able to read the pid.. */
4681         debug(F101,"ttchkpid lock pid","",pid);
4682         errno = 0;                      /* See if process still exists. */
4683         mypid = (int)getpid();          /* Get my own pid. */
4684         debug(F101,"ttchkpid my pid","",mypid);
4685         if (pid == mypid) {             /* It's me! */
4686             x = -1;                     /* So I can delete it */
4687             errno = ESRCH;              /* pretend it's invalid */
4688         } else {                        /* It's not me */
4689             x = kill((PID_T)pid, 0);    /* See if it's a live process */
4690             debug(F101,"ttchkpid kill errno","",errno);
4691         }
4692         debug(F101,"ttchkpid pid test","",x);
4693         if (x < 0 && errno == ESRCH) { /* pid is invalid */
4694             debug(F111,"removing stale lock",f,pid);
4695             if (!backgrd)
4696               printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
4697             priv_on();
4698             x = unlink(f);              /* Remove the lockfile. */
4699             priv_off();
4700             debug(F111,"ttchkpid unlink",f,x);
4701             if (x > -1)
4702               return(0);                /* Device is not locked after all */
4703             else if (!backgrd)
4704               perror(f);
4705         }
4706         return(1);
4707     }
4708     return(1);                          /* Failure to read pid */
4709 }
4710
4711 #ifdef HPUX
4712
4713 /* Aliases (different drivers) for HP-UX dialout devices: */
4714
4715 static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
4716 static int ttydexists = 0;
4717
4718 #endif /* HPUX */
4719
4720 /*  T T R P I D  --  Read pid from lockfile "name" */
4721
4722 static int
4723 ttrpid(name) char *name; {
4724     long len;
4725     int x, fd, pid;
4726     short spid;
4727     char buf[32];
4728
4729     debug(F110,"ttrpid",name,0);
4730     if (!name) return(-1);
4731     if (!*name) return(-1);
4732     priv_on();
4733     len = zchki(name);                  /* Get file length */
4734     priv_off();
4735     debug(F101,"ttrpid zchki","",len);
4736     if (len < 0)
4737       return(-1);
4738     if (len > 31)
4739       return(-1);
4740     priv_on();
4741     fd = open(name,O_RDONLY);           /* Try to open lockfile. */
4742     priv_off();
4743     debug(F101,"ttrpid fd","",fd);
4744     if (fd <= 0)
4745       return(-1);
4746 /*
4747   Here we try to be flexible and allow for all different binary and string
4748   formats at runtime, rather than a specific format for each configuration
4749   hardwired at compile time.
4750 */
4751     pid = -1;
4752 #ifndef COHERENT
4753 /*
4754   COHERENT uses a string PID but without leading spaces or 0's, so there is
4755   no way to tell from the file's length whether it contains a string or binary
4756   pid.  So for COHERENT only, we only allow string pids.  For all others, we
4757   decide based on the size of the lockfile.
4758 */
4759     if (len > 4) {                      /* If file > 4 bytes it's a string */
4760 #endif /* COHERENT */
4761         x = read(fd,buf,(int)len);
4762         debug(F111,"ttrpid string read",buf,x);
4763         if (x < 0) {
4764             pid = -1;
4765         } else {
4766             buf[31] = '\0';
4767             x = sscanf(buf,"%d",&pid);  /* Get the integer pid from it. */
4768         }
4769 #ifndef COHERENT
4770     } else if (len == 4) {              /* 4 bytes so binary */
4771         x = read(fd, (char *)&pid, 4);  /* Read the bytes into an int */
4772         debug(F101,"ttrpid integer read","",x);
4773         if (x < 4)
4774           pid = -1;
4775     } else if (len == 2) {              /* 2 bytes binary */
4776         x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
4777         debug(F101,"ttrpid short read","",x);
4778         if (x < 2)
4779           pid = -1;
4780         else
4781           pid = spid;
4782     } else
4783       pid = -1;
4784 #endif /* COHERENT */
4785     close(fd);                          /* Close the lockfile */
4786     debug(F101,"ttrpid pid","",pid);
4787     return(pid);
4788 }
4789 #endif /* NOUUCP */
4790
4791 /*  T T L O C K  */
4792
4793 /*
4794   This function attempts to coordinate use of the communication device with
4795   other copies of Kermit and any other program that follows the UUCP
4796   device-locking conventions, which, unfortunately, vary among different UNIX
4797   implementations.  The idea is to look for a file of a certain name, the
4798   "lockfile", in a certain directory.  If such a file is found, then the line
4799   is presumed to be in use, and Kermit should not use it.  If no such file is
4800   found, Kermit attempts to create one so that other programs will not use the
4801   same line at the same time.  Because the lockfile and/or the directory it's
4802   in might lack write permission for the person running Kermit, Kermit could
4803   find itself running setuid to uucp or other user that does have the
4804   necessary permissions.  At startup, Kermit has changed its effective uid to
4805   the user's real uid, and so ttlock() must switch back to the original
4806   effective uid in order to create the lockfile, and then back again to the
4807   real uid to prevent unauthorized access to other directories or files owned
4808   by the user the program is setuid to.
4809
4810   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
4811   based on suggestions from Warren Tucker.  Call with pointer to name of
4812   tty device.  Returns:
4813
4814    0 on success
4815   -1 on failure
4816
4817   Note: Once privileges are turned on using priv_on(), it is essential that
4818   they are turned off again before this function returns.
4819 */
4820 #ifdef SVR4                             /* Lockfile uses device numbers. */
4821 /*
4822   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
4823   it is the behavior of the "reference version" of SVR4, i.e. the Intel
4824   port from UNIX Systems Laboratories, then called Univel UnixWare,
4825   then called Novell UnixWare, then called SCO Unixware, then called Caldera
4826   Open UNIX...  It also makes much more sense than device-name-based lockfiles
4827   since there can be multiple names for the same device, symlinks, etc.
4828 */
4829 #ifndef NOLFDEVNO
4830 #ifndef LFDEVNO                         /* Define this for SVR4 */
4831 #ifndef AIXRS                           /* But not for RS/6000 AIX 3.2, etc. */
4832 #ifndef BSD44                           /* If anybody else needs it... */
4833 #ifndef __386BSD__
4834 #ifndef __FreeBSD__
4835 #ifndef HPUX10
4836 #ifndef IRIX51                          /* SGI IRIX 5.1 or later */
4837 #ifndef CK_SCOV5                        /* SCO Open Server 5.0 */
4838 #define LFDEVNO
4839 #endif /* CK_SCOV5 */
4840 #endif /* IRIX51 */
4841 #endif /* HPUX10 */
4842 #endif /* __FreeBSD__ */
4843 #endif /* __386BSD__ */
4844 #endif /* BSD44 */
4845 #endif /* AIXRS */
4846 #endif /* LFDEVNO */                    /* ... define it here or on CC */
4847 #endif /* NOLFDEVNO */
4848 #endif /* SVR4 */                       /* command line. */
4849
4850 #ifdef COHERENT
4851 #define LFDEVNO
4852 #endif /* COHERENT */
4853
4854 /*
4855   For platforms where the lockfile name is made from device/major/minor
4856   device number, as in SVR4.  Which, if we must have lockfiles at all, is
4857   by far the best format, since it eliminates all the confusion that stems
4858   from multiple names (or drivers) for the same port, not to mention
4859   symlinks.  It might even be a good idea to start using this form even
4860   on platforms where it's not supported, alongside the normal forms for those
4861   platforms, in order to get people used to it...
4862 */
4863 #ifdef LFDEVNO
4864 #ifndef major                           /* If we didn't find it */
4865 #ifdef SVR4                             /* then for Sys V R4 */
4866 #include <sys/mkdev.h>                  /* look here */
4867 #else                                   /* or for SunOS versions */
4868 #ifdef SUNOS4                           /* ... */
4869 #include <sys/sysmacros.h>              /* look here */
4870 #else                                   /* Otherwise take a chance: */
4871 #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
4872 #define minor(dev) ( (int) ( (dev) & 0xff))
4873 #endif /* SUNOS4 */
4874 #endif /* SVR4 */
4875 #endif /* major */
4876 #endif /* LFDEVNO */
4877
4878 /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
4879
4880 #ifdef LOCKF
4881 #ifndef F_TLOCK
4882 #undef LOCKF
4883 #ifndef NOLOCKF
4884 #define NOLOCKF
4885 #endif /* NOLOCKF */
4886 #endif /* F_TLOCK */
4887 #endif /* LOCKF */
4888
4889 #ifdef LOCKF
4890 #ifndef F_ULOCK
4891 #undef LOCKF
4892 #ifndef NOLOCKF
4893 #define NOLOCKF
4894 #endif /* NOLOCKF */
4895 #endif /* F_ULOCK */
4896 #endif /* LOCKF */
4897
4898 static char linkto[DEVNAMLEN+1];
4899 static char * linkdev = NULL;
4900
4901 #ifndef NOUUCP
4902 #ifdef USETTYLOCK
4903 #ifdef LOCK_DIR
4904 char * uucplockdir = LOCK_DIR;
4905 #else
4906 char * uucplockdir = "";
4907 #endif /* LOCK_DIR */
4908 #else
4909 #ifdef LOCK_DIR
4910 char * uucplockdir = LOCK_DIR;
4911 #else
4912 char * uucplockdir = "";
4913 #endif /* LOCK_DIR */
4914 #endif /* USETTYLOCK */
4915 #else
4916 char * uucplockdir = "";
4917 #endif /* NOUUCP */
4918
4919 #ifdef QNX                              /* Only for QNX4 */
4920 int                                     /* Visible to outside world */
4921 qnxopencount() {                        /* Get QNX device open count */
4922     struct _dev_info_entry info;
4923     int x;
4924
4925     x = -1;                             /* Unknown */
4926     if (ttyfd > -1) {
4927         if (!dev_info(ttyfd, &info)) {
4928             debug(F101,"ttlock QNX open_count","",info.open_count);
4929             x = info.open_count;
4930         }
4931     }
4932     return(x);
4933 }
4934 #endif /* QNX */
4935
4936 char *
4937 ttglckdir() {                           /* Get Lockfile directory name */
4938 #ifdef __OpenBSD__
4939     return("/var/spool/lock");
4940 #else /* __OpenBSD__ */
4941 #ifdef __FreeBSD__
4942     return("/var/spool/lock");
4943 #else  /* __FreeBSD__ */
4944 #ifdef LOCK_DIR
4945     char * s = LOCK_DIR;
4946 #endif /* LOCK_DIR */
4947 #ifdef NOUUCP
4948     return("");
4949 #else  /* NOUUCP */
4950 #ifdef LOCK_DIR
4951     return(s);
4952 #else  /* LOCK_DIR */
4953     return("");
4954 #endif /* LOCK_DIR */
4955 #endif /* NOUUCP */
4956 #endif /* __FreeBSD__ */
4957 #endif /* __OpenBSD__ */
4958 }
4959
4960 static int
4961 ttlock(ttdev) char *ttdev; {
4962
4963     int x, n;
4964     int islink = 0;
4965
4966 #ifdef NOUUCP
4967     debug(F100,"ttlock NOUUCP","",0);
4968     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
4969     haslock = 1;
4970     return(0);
4971 #else /* !NOUUCP */
4972
4973 #ifdef USETTYLOCK
4974     haslock = 0;                        /* Not locked yet. */
4975     *flfnam = '\0';                     /* Lockfile name is empty. */
4976     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
4977       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
4978     else
4979       ckstrncpy(lockname,ttdev,DEVNAMLEN);
4980 /*
4981   This might be overkill, but it's not clear from the man pages whether
4982   ttylock() can be called without calling ttylocked() first, since the doc
4983   says that ttylocked() removes any stale lockfiles, but it does not say this
4984   about ttylock().  Also the docs don't say what ttylocked() returns in the
4985   case when it finds and removes a stale lockfile.  So one or both calls to
4986   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
4987   assuming that we have to do all the same ID swapping, etc, with these
4988   routines as we do without them.  Thus the priv_on/off() sandwich.
4989 */
4990 #ifdef USE_UU_LOCK
4991     priv_on();                          /* Turn on privs */
4992     x = uu_lock(lockname);              /* Try to set the lock */
4993     priv_off();                         /* Turn privs off */
4994     debug(F111,"ttlock uu_lock",lockname,x);
4995     switch (x) {
4996       case UU_LOCK_INUSE:
4997         return(-2);
4998       case UU_LOCK_OK:
4999 #ifdef BSD44
5000         ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
5001 #endif /* BSD44 */
5002         haslock = 1;
5003         return(0);
5004       default:
5005         return(-1);
5006     }
5007 #else  /* USE_UU_LOCK */
5008     priv_on();                          /* Turn on privs */
5009     if (ttylocked(lockname)) {          /* This should remove any stale lock */
5010         if (ttylocked(lockname)) {      /* so check again. */
5011             priv_off();
5012             return(-5);                 /* Still locked, fail. */
5013         }
5014     }
5015     x = ttylock(lockname);              /* Lock it. */
5016     priv_off();                         /* Turn off privs */
5017
5018     debug(F111,"ttlock lockname",lockname,x);
5019     if (x > -1) {
5020         /*
5021           We don't really know the name of the lockfile, but
5022           this is what the man page says it is.  In USETTYLOCK
5023           builds, it is used only for display by SHOW COMM.
5024         */
5025         ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
5026         haslock = 1;
5027     }
5028     return(x);
5029 #endif /* USE_UU_LOCK */
5030 #else  /* Systems that don't have ttylock()... */
5031
5032 #ifndef HPUX
5033
5034     int lockfd;                         /* File descriptor for lock file. */
5035     PID_T pid;                          /* Process id of this process. */
5036     int tries;                          /* How many times we've tried... */
5037     struct stat devbuf;                 /* For device numbers (SVR4). */
5038
5039 #ifdef PIDSTRING
5040     char pid_str[32];                   /* My pid in string format. */
5041 #endif /* PIDSTRING */
5042
5043     char *device, *devname;
5044
5045 #define LFNAML 256                      /* Max length for lock file name. */
5046     char lockfil[LFNAML];               /* Lock file name */
5047 #ifdef RTAIX
5048     char lklockf[LFNAML];               /* Name for link to lock file  */
5049 #endif /* RTAIX */
5050 #ifdef CKSYMLINK
5051     char symlock[LFNAML];               /* Name for symlink lockfile name */
5052 #endif /* CKSYMLINK */
5053     char tmpnam[LFNAML+30];             /* Temporary lockfile name. */
5054     char *lockdir = LOCK_DIR;           /* Defined near top of this file, */
5055                                         /* or on cc command line. */
5056     haslock = 0;                        /* Not locked yet. */
5057     *flfnam = '\0';                     /* Lockfile name is empty. */
5058     lock2[0] = '\0';                    /* Clear secondary lockfile name. */
5059     pid = getpid();                     /* Get id of this process. */
5060
5061 /*  Construct name of lockfile and temporary file */
5062
5063 /*  device  = name of tty device without the path, e.g. "ttyh8" */
5064 /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
5065
5066     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5067
5068     if (stat(ttdev,&devbuf) < 0)
5069       return(-1);
5070
5071 #ifdef CKSYMLINK
5072     islink = 1;                         /* Assume it's a symlink */
5073     linkto[0] = '\0';                   /* But we don't know to what */
5074 #ifdef COMMENT
5075 /*
5076   This is undependable.  If it worked it would save the readlink call if
5077   we knew the device name was not a link.
5078 */
5079 #ifdef S_ISLNK
5080     islink = S_ISLNK(devbuf.st_mode);
5081     debug(F101,"ttlock stat S_ISLNK","",islink);
5082 #endif /* S_ISLNK */
5083 #endif /* COMMENT */
5084     if (islink) {
5085         n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
5086         debug(F111,"ttlock readlink",ttdev,n);
5087         if (n > -1)                     /* It is */
5088           linkto[n] = '\0';
5089         else                            /* It's not */
5090           islink = 0;
5091         debug(F111,"ttlock link",linkto,islink);
5092     }
5093     if (islink) {
5094         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5095         debug(F110,"ttlock linkdev",linkdev,0);
5096     }
5097 #endif /* CKSYMLINK */
5098
5099 /*
5100   On SCO platforms, if we don't have a symlink, then let's pretend the
5101   name given for the device is a symlink, because later we will change
5102   the name if it contains any uppercase characters.
5103 */
5104 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5105     if (!islink) {
5106         islink = 1;
5107         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5108         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5109         debug(F110,"ttlock linkdev",linkdev,0);
5110     }
5111 #else
5112 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5113     if (!islink) {
5114         islink = 1;
5115         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5116         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5117         debug(F110,"ttlock linkdev",linkdev,0);
5118     }
5119 #endif /* M_XENIX */
5120 #endif /* CK_SCOV5 */
5121
5122 #ifdef ISIII                            /* Interactive System III, PC/IX */
5123     ckstrncpy(lockfil, device, DEVNAMLEN);
5124 #else  /* not ISIII */
5125 #ifdef LFDEVNO                          /* Lockfilename has device numbers. */
5126 #ifdef COHERENT
5127     sprintf(lockfil,"LCK..%d.%d",       /* SAFE */
5128             major(devbuf.st_rdev),         /* major device number */
5129             0x1f & minor(devbuf.st_rdev)); /* minor device number */
5130 #else
5131     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
5132     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
5133     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
5134             major(devbuf.st_dev),       /* device */
5135             major(devbuf.st_rdev),      /* major device number */
5136             minor(devbuf.st_rdev));     /* minor device number */
5137 #endif /* COHERENT */
5138 #else  /* Not LFDEVNO */
5139 #ifdef PTX                              /* Dynix PTX */
5140     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
5141         if ((int)strlen(device) + 8 < LFNAML)
5142           sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
5143         else
5144           ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5145     } else
5146 #endif /* PTX */
5147       if ((int)strlen(device) + 5 < LFNAML)
5148         sprintf(lockfil,"LCK..%s", device);
5149       else
5150         ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5151 #ifdef RTAIX
5152     ckstrncpy(lklockf,device,DEVNAMLEN);
5153 #endif /* RTAIX */
5154 #ifdef CKSYMLINK
5155     symlock[0] = '\0';
5156     if (islink)
5157       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
5158 #endif /* CKSYMLINK */
5159 #endif /* LFDEVNO */
5160 #endif /* ISIII */
5161
5162 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5163     {
5164         /* Lowercase the entire filename. */
5165         /* SCO says we must do this in V5.0 and later. */
5166         /* BUT... watch out for devices -- like Digiboard Portserver */
5167         /* That can have hundreds of ports... */
5168         char *p = (char *)(lockfil + 5);
5169         while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
5170     }
5171 #ifdef CKSYMLINK
5172     if (islink) {                       /* If no change */
5173         if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
5174             islink = 0;
5175             symlock[0] = '\0';
5176         }
5177     }
5178 #endif /* CKSYMLINK */
5179 #else
5180 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5181     {
5182         int x; char c;
5183         x = (int)strlen(lockfil) - 1;   /* Get last letter of device name. */
5184         if (x > 0) {                    /* If it's uppercase, lower it. */
5185             c = lockfil[x];
5186             if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
5187         }
5188     }
5189 #ifdef CKSYMLINK
5190     if (islink) {
5191         if (!strcmp(lockfil,symlock)) { /* No change */
5192             islink = 0;                 /* so no second lockfile */
5193             symlock[0] = '\0';
5194         }
5195     }
5196 #endif /* CKSYMLINK */
5197 #endif /* M_XENIX */
5198 #endif /* CK_SCOV5 */
5199
5200 /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
5201 /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
5202
5203     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
5204
5205 #ifdef RTAIX
5206     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
5207 #endif /* RTAIX */
5208
5209 #ifndef LFDEVNO
5210 #ifdef CKSYMLINK
5211     /* If it's a link then also make a lockfile for the real name */
5212     debug(F111,"ttlock link symlock",symlock,islink);
5213     if (islink && symlock[0]) {
5214         /* But only if the lockfile names would be different. */
5215         /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
5216         ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
5217         debug(F110,"ttlock lock2",lock2,0);
5218         if (!strcmp(lock2,flfnam)) {    /* Are lockfile names the same? */
5219             debug(F100,"ttlock lock2 cleared","",0);
5220             lock2[0] = '\0';            /* Clear secondary lockfile name. */
5221         }
5222     }
5223 #endif /* CKSYMLINK */
5224 #endif /* LFDEVNO */
5225
5226     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
5227     debug(F110,"ttlock flfnam",flfnam,0);
5228     debug(F110,"ttlock tmpnam",tmpnam,0);
5229
5230     priv_on();                          /* Turn on privileges if possible. */
5231     lockfd = creat(tmpnam, 0444);       /* Try to create temp lock file. */
5232     if (lockfd < 0) {                   /* Create failed. */
5233         debug(F111,"ttlock creat failed",tmpnam,errno);
5234         if (errno == ENOENT) {
5235             perror(lockdir);
5236             printf("UUCP not installed or Kermit misconfigured\n");
5237         } else {
5238             if (!quiet)
5239               perror(lockdir);
5240             unlink(tmpnam);             /* Get rid of the temporary file. */
5241         }
5242         priv_off();                     /* Turn off privileges!!! */
5243         return(-1);                     /* Return failure code. */
5244     }
5245 /* Now write the pid into the temp lockfile in the appropriate format */
5246
5247 #ifdef PIDSTRING                        /* For Honey DanBer UUCP, */
5248     sprintf(                            /* write PID as decimal string */
5249             pid_str,
5250 #ifdef LINUXFSSTND                      /* The "Linux File System Standard" */
5251 #ifdef FSSTND10                         /* Version 1.0 calls for */
5252             "%010d\n",                  /* leading zeros */
5253 #else                                   /* while version 1.2 calls for */
5254             "%10d\n",                   /* leading spaces */
5255 #endif /* FSSTND10 */
5256 #else
5257 #ifdef COHERENT
5258             "%d\n",                     /* with leading nothing */
5259 #else
5260             "%10d\n",                   /* with leading blanks */
5261 #endif /* COHERENT */
5262 #endif /* LINUXFSSTND */
5263             (int) pid
5264             );                          /* safe */
5265     write(lockfd, pid_str, 11);
5266     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
5267
5268 #else /* Not PIDSTRING, use integer PID */
5269
5270     write(lockfd, (char *)&pid, sizeof(pid) );
5271     debug(F101,"ttlock pid","",(int) pid);
5272
5273 #endif /* PIDSTRING */
5274
5275 /* Now try to rename the temp file to the real lock file name. */
5276 /* This will fail if a lock file of that name already exists.  */
5277
5278     close(lockfd);                      /* Close the temp lockfile. */
5279     chmod(tmpnam,0444);                 /* Permission for a valid lock. */
5280     tries = 0;
5281     while (!haslock && tries++ < 2) {
5282         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5283         if (haslock) {                        /* If we got the lockfile */
5284 #ifdef RTAIX
5285             link(flfnam,lkflfn);
5286 #endif /* RTAIX */
5287 #ifdef CKSYMLINK
5288 #ifndef LFDEVNO
5289             if (islink && lock2[0])
5290               link(flfnam,lock2);
5291 #endif /* LFDEVNO */
5292 #endif /* CKSYMLINK */
5293
5294 #ifdef COMMENT
5295 /* Can't do this any more because device is not open yet so no ttyfd. */
5296 #ifdef LOCKF
5297 /*
5298   Advisory file locking works on SVR4, so we use it.  In fact, it is
5299   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
5300   seem to prevent multiple users accessing the same device by different names.
5301 */
5302             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
5303                 debug(F111, "ttlock lockf returns errno", "", errno);
5304                 if ((++tries >= 3) || (errno != EAGAIN)) {
5305                     x = unlink(flfnam); /* remove the lockfile */
5306 #ifdef RTAIX
5307                     unlink(lkflfn);     /* And any links to it... */
5308 #endif /* RTAIX */
5309 #ifdef CKSYMLINK
5310 #ifndef LFDEVNO
5311                     if (islink && lock2[0])
5312                       unlink(lock2);    /* ditto... */
5313 #endif /* LFDEVNO */
5314 #endif /* CKSYMLINK */
5315                     debug(F111,"ttlock unlink",flfnam,x);
5316                     haslock = 0;
5317                     break;
5318                 }
5319                 sleep(2);
5320             }
5321             if (haslock)                /* If we got an advisory lock */
5322 #endif /* LOCKF */
5323 #endif /* COMMENT */
5324               break;                    /* We're done. */
5325
5326         } else {                        /* We didn't create a new lockfile. */
5327             priv_off();
5328             if (ttchkpid(flfnam)) {     /* Check existing lockfile */
5329                 priv_on();              /* cause ttchkpid turns priv_off... */
5330                 unlink(tmpnam);         /* Delete the tempfile */
5331                 debug(F100,"ttlock found tty locked","",0);
5332                 priv_off();             /* Turn off privs */
5333                 return(-2);             /* Code for device is in use. */
5334             }
5335             priv_on();
5336         }
5337     }
5338     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5339     priv_off();                         /* Turn off privs */
5340     return(haslock ? 0 : -1);           /* Return link's return code. */
5341
5342 #else /* HPUX */
5343
5344 /*
5345   HP-UX gets its own copy of this routine, modeled after the observed behavior
5346   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
5347   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
5348   designator which is a string of digits, possibly containing an imbedded
5349   letter "p".  Examples (for base name "tty"):
5350
5351      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
5352
5353   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
5354   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
5355   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
5356   However, we make and enforce no such distinctions; either notation is
5357   accepted on any model or HP-UX version as a valid unit designator.
5358
5359   If a valid unit is specified (as opposed to a designer name or symlink), we
5360   check for all aliases of the given unit according to the devprefix[] array.
5361   If no lockfiles are found for the given unit, we can have the device; we
5362   create a lockfile LCK..name in the lockfile directory appropriate for the
5363   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
5364   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
5365   created with the "ttyd" prefix.  This is exactly what cu does.
5366
5367   If the "set line" device does not have a valid unit designator, then it is
5368   used literally and no synomyms are searched for and only one lockfile is
5369   created.
5370
5371   -fdc, March 1998.
5372 */
5373 #define LFNAML 80                       /* Max length for lock file name. */
5374
5375     int lockfd;                         /* File descriptor for lock file. */
5376     PID_T pid;                          /* Process ID of this process. */
5377     int fpid;                           /* pid found in existing lockfile. */
5378     int tries;                          /* How many times we've tried... */
5379     int i, k;                           /* Workers */
5380
5381     char *device, *devname;             /* "/dev/xxx", "xxx" */
5382     char *unit, *p;                     /* <instance>p<port> part of xxx */
5383
5384     char lockfil[LFNAML];               /* Lockfile name (no path) */
5385     char tmpnam[LFNAML];                /* Temporary lockfile name. */
5386
5387 #ifdef HPUX10                           /* Lockfile directory */
5388     char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
5389 #else  /* HP-UX 9.xx and below */
5390 #ifdef LOCK_DIR
5391     char *lockdir = LOCK_DIR;           /* Defined near top of this file */
5392 #else
5393     char *lockdir = "/usr/spool/uucp";  /* or not... */
5394 #endif /* LOCK_DIR */
5395 #endif /* HPUX10 */
5396
5397     haslock = 0;                        /* Not locked yet. */
5398     *flfnam = '\0';                     /* Lockfile name is empty. */
5399     lock2[0] = '\0';                    /* Second one too. */
5400     pid = getpid();                     /* Get my process ID */
5401 /*
5402   Construct name of lockfile and temporary file...
5403   device  = name of tty device without the path, e.g. "tty0p0"
5404   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
5405 */
5406     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5407     debug(F110,"TTLOCK device",device,0);
5408     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
5409
5410     k = 0;                              /* Assume device is not locked */
5411     n = 0;                              /* Digit counter */
5412     unit = device;                      /* Unit = <instance>p<port> */
5413     while (*unit && !isdigit(*unit))    /* Search for digit... */
5414       unit++;
5415     p = unit;                           /* Verify <num>p<num> format... */
5416     debug(F110,"TTLOCK unit 1",unit,0);
5417 /*
5418   The unit number is recognized as:
5419   (a) any sequence of digits that runs to the end of the string.
5420   (b) any (a) that includes one and only one letter "p", with at least
5421       one digit before and after it.
5422 */
5423     while (isdigit(*p)) p++, n++;       /* Get a run of digits */
5424     if (*p && n > 0) {                  /* Have a "p"? */
5425         if (*p == 'p' && isdigit(*(p+1))) {
5426             p++;
5427             n = 0;
5428             while (isdigit(*p)) p++, n++;
5429         }
5430     }
5431     if (n == 0 || *p) unit = "";
5432     debug(F110,"TTLOCK unit 2",unit,0);
5433
5434     if (*unit) {                        /* Device name has unit number. */
5435         /* The following loop not only searches for the various lockfile    */
5436         /* synonyms, but also removes all -- not just one -- stale lockfile */
5437         /* for the device, should there be more than one.  See ttchkpid().  */
5438         ttydexists = 0;
5439         for (i = 0; *devprefix[i]; i++) { /* For each driver... */
5440             /* Make device name */
5441             ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
5442             priv_on();                  /* Privs on */
5443             k = zchki(lock2) != -1;     /* See if device exists */
5444             priv_off();                 /* Privs off */
5445             debug(F111,"TTLOCK exist",lock2,k);
5446             if (k) {
5447                 if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
5448                   ttydexists = 1;
5449                 /* Make lockfile name */
5450                 ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
5451                 debug(F110,"TTLOCK checking",lock2,0);
5452                 priv_on();              /* Privs on */
5453                 k = zchki(lock2) != -1; /* See if lockfile exists */
5454                 priv_off();             /* Privs off */
5455                 debug(F111,"TTLOCK check for lock A",lock2,k);
5456                 if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
5457                     ckstrncpy(flfnam,lock2,FLFNAML);
5458                     return(-2);
5459                 }
5460             }
5461         }
5462     } else {                            /* Some other device-name format */
5463         /* This takes care of symbolic links, etc... */
5464         /* But does not chase them down! */
5465         ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
5466         priv_on();
5467         k = zchki(lock2) != -1;         /* Check for existing lockfile */
5468         priv_off();
5469         debug(F111,"TTLOCK check for lock B",lock2,k);
5470         if (k) if (ttchkpid(lock2)) {   /* Check pid from lockfile */
5471             ckstrncpy(flfnam,lock2,FLFNAML);
5472             debug(F110,"TTLOCK in use",device,0);
5473             debug(F101,"TTLOCK returns","",-2);
5474             return(-2);
5475         }
5476     }
5477 /*
5478   Get here only if there is no (more) lockfile, so now we make one (or two)...
5479   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
5480   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
5481 */
5482     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
5483
5484     /* If dialout device, also make one for corresponding dialin device */
5485     lock2[0] = '\0';
5486     if (!strncmp(device,"cu",2) && *unit && ttydexists)
5487       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
5488
5489     if ((int)strlen(lockdir)+12 < LFNAML)
5490       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
5491 #ifdef DEBUG
5492     if (deblog) {
5493         debug(F110,"TTLOCK flfnam",flfnam,0);
5494         debug(F110,"TTLOCK lock2",lock2,0);
5495         debug(F110,"TTLOCK tmpnam",tmpnam,0);
5496     }
5497 #endif /* DEBUG */
5498 /*
5499    Lockfile permissions...
5500    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
5501    Kermit uses 444; the difference lets us tell whether Kermit created
5502    the lock file.
5503 */
5504     priv_on();                          /* Turn on privileges. */
5505     lockfd = creat(tmpnam, 0444);       /* Try to create temporary file. */
5506     if (lockfd < 0) {                   /* Create failed. */
5507         debug(F111,"TTLOCK creat failed",tmpnam,errno);
5508         if (errno == ENOENT) {
5509             perror(lockdir);
5510             printf("UUCP not installed or Kermit misconfigured\n");
5511         } else {
5512             if (!quiet)
5513               perror(lockdir);
5514             unlink(tmpnam);             /* Get rid of the temporary file. */
5515         }
5516         priv_off();                     /* Turn off privileges!!! */
5517         debug(F101,"TTLOCK returns","",-1);
5518         return(-1);                     /* Return failure code. */
5519     }
5520     debug(F110,"TTLOCK temp ok",tmpnam,0);
5521
5522 /* Now write our pid into the temp lockfile in integer format. */
5523
5524     i = write(lockfd, (char *)&pid, sizeof(pid));
5525
5526 #ifdef DEBUG
5527     if (deblog) {
5528         debug(F101,"TTLOCK pid","",pid);
5529         debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
5530         debug(F101,"TTLOCK write pid returns","",i);
5531     }
5532 #endif /* DEBUG */
5533
5534 /*
5535   Now try to rename the temporary file to the real lockfile name.
5536   This will fail if a lock file of that name already exists, which
5537   will catch race conditions with other users.
5538 */
5539     close(lockfd);                      /* Close the temp lockfile. */
5540     chmod(tmpnam,0444);
5541
5542     tries = 0;
5543     while (!haslock && tries++ < 2) {
5544         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5545         debug(F101,"TTLOCK link","",haslock);
5546         if (haslock) {                  /* If we made the lockfile... */
5547
5548 #ifdef COMMENT
5549 /* We can't do this any more because we don't have a file descriptor yet. */
5550 #ifdef LOCKF                            /* Can be canceled with -DNOLOCKF */
5551 /*
5552   Create an advisory lock on the device through its file descriptor.
5553   This code actually seems to work.  If it is executed, and then another
5554   process tries to open the same device under a different name to circumvent
5555   the lockfile, they get a "device busy" error.
5556 */
5557             debug(F100,"TTLOCK LOCKF code...","",0);
5558             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
5559                 debug(F111, "TTLOCK lockf error", "", errno);
5560                 if ((++tries >= 3) || (errno != EAGAIN)) {
5561                     x = unlink(flfnam); /* Remove the lockfile */
5562                     if (errno == EACCES && !quiet)
5563                       printf("Device already locked by another process\n");
5564                     haslock = 0;
5565                     break;
5566                 }
5567                 sleep(2);
5568             }
5569 #endif /* LOCKF */
5570 #endif /* COMMENT */
5571
5572             if (haslock) {              /* If we made the lockfile ... */
5573                 if (lock2[0]) {         /* if there is to be a 2nd lockfile */
5574                     lockfd = creat(lock2, 0444); /* Create it */
5575                     debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
5576                     if (lockfd > -1) {  /* Created OK, write pid. */
5577                         write(lockfd, (char *)&pid, sizeof(pid) );
5578                         close(lockfd);  /* Close and */
5579                         chmod(lock2, 0444); /* set permissions. */
5580                     } else {             /* Not OK, but don't fail. */
5581                         lock2[0] = '\0'; /* Just remember it's not there. */
5582                     }
5583                 }
5584                 break;                  /* and we're done. */
5585             }
5586         }
5587     }
5588     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5589     priv_off();                         /* Turn off privs */
5590     i = haslock ? 0 : -1;               /* Our return value */
5591     debug(F101,"TTLOCK returns","",i);
5592     return(i);
5593 #endif /* HPUX */
5594 #endif /* USETTYLOCK */
5595 #endif /* !NOUUCP */
5596 }
5597
5598 /*  T T U N L O C K  */
5599
5600 static int
5601 ttunlck() {                             /* Remove UUCP lockfile(s). */
5602 #ifndef NOUUCP
5603     int x;
5604
5605     debug(F111,"ttunlck",flfnam,haslock);
5606
5607 #ifdef USETTYLOCK
5608
5609     if (haslock && *flfnam) {
5610         int x;
5611         priv_on();                      /* Turn on privs */
5612 #ifdef USE_UU_LOCK
5613         x = uu_unlock(lockname);
5614 #else  /* USE_UU_LOCK */
5615         x = ttyunlock(lockname);        /* Try to unlock */
5616 #endif /* USE_UU_LOCK */
5617         priv_off();                     /* Turn off privs */
5618         if (x < 0 && !quiet)
5619           printf("Warning - Can't remove lockfile: %s\n", flfnam);
5620
5621         *flfnam = '\0';                 /* Erase the name. */
5622         haslock = 0;
5623         return(0);
5624     }
5625
5626 #else  /* No ttylock()... */
5627
5628     if (haslock && *flfnam) {
5629         /* Don't remove lockfile if we didn't make it ourselves */
5630         if ((x = ttrpid(flfnam)) != (int)getpid()) {
5631             debug(F111,"ttunlck lockfile seized",flfnam,x);
5632             printf("Warning - Lockfile %s seized by pid %d\n",
5633                    flfnam,
5634                    x
5635                    );
5636             return(0);
5637         }
5638         priv_on();                      /* Turn privileges on.  */
5639         errno = 0;
5640         x = unlink(flfnam);             /* Remove the lockfile. */
5641         debug(F111,"ttunlck unlink",flfnam,x);
5642         if (x < 0) {
5643             if (errno && !quiet)
5644               perror(ttnmsv);
5645             printf("Warning - Can't remove lockfile: %s\n", flfnam);
5646         }
5647         haslock = 0;
5648         *flfnam = '\0';                 /* Erase the name. */
5649
5650 #ifdef RTAIX
5651         errno = 0;
5652         x = unlink(lkflfn);             /* Remove link to lockfile */
5653         debug(F111,"ttunlck AIX link unlink",lkflfn,x);
5654         if (x < 0) {
5655             if (errno && !quiet)
5656               perror(ttnmsv);
5657             printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
5658         }
5659         *lkflfn = '\0';
5660 #else
5661         if (lock2[0]) {                 /* If there is a second lockfile, */
5662             errno = 0;
5663             x = unlink(lock2);          /*  remove it too. */
5664             debug(F111,"ttunlck lock2 unlink",lock2,x);
5665             if (x < 0) {
5666                 if (errno && !quiet)
5667                   perror(ttnmsv);
5668                 printf("Warning - Can't remove secondary lockfile: %s\n",
5669                        lock2
5670                        );
5671             }
5672             lock2[0] = '\0';            /* Forget its name. */
5673         }
5674 #endif /* RTAIX */
5675
5676 #ifdef COMMENT
5677 #ifdef LOCKF
5678         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
5679 #endif /* LOCKF */
5680 #endif /* COMMENT */
5681
5682         priv_off();                     /* Turn privileges off. */
5683     }
5684 #endif /* USETTYLOCK */
5685 #endif /* !NOUUCP */
5686     return(0);
5687 }
5688
5689 /*
5690   4.3BSD-style UUCP line direction control.
5691   (Stan Barber, Rice U, 1980-something...)
5692 */
5693 #ifndef NOUUCP
5694 #ifdef ACUCNTRL
5695 VOID
5696 acucntrl(flag,ttname) char *flag, *ttname; {
5697     char x[DEVNAMLEN+32], *device, *devname;
5698
5699     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
5700       return;                           /* just return. */
5701     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
5702     if (strncmp(device,"LCK..",4) == 0) device += 5;
5703     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
5704     debug(F110,"called ",x,0);
5705     zsyscmd(x);
5706 }
5707 #endif /* ACUCNTRL */
5708 #endif /* NOUUCP */
5709
5710 /*
5711   T T H F L O W  --  Set or Reset hardware flow control.
5712
5713   This is an attempt to collect all hardware-flow-control related code
5714   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
5715   help here.  Overview:
5716
5717   Hardware flow control is not supported in many UNIX implementions.  Even
5718   when it is supported, there is no (ha ha) "standard" for the programming
5719   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
5720   SunOS, AIX, etc, have totally different methods.  (And, not strictly
5721   relevant here, the programming interface often brings one only to a no-op
5722   in the device driver!)
5723
5724   Among all these, we have two major types of APIs: those in which hardware
5725   flow control is determined by bits in the same termio/termios/sgtty mode
5726   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
5727   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
5728   for changing terminal modes.  And those that use entirely different
5729   mechanisms.
5730
5731   In the first category, it is important that any change in the mode bits be
5732   reflected in the relevant termio(s)/sgtty structure, so that subsequent
5733   changes to that structure do not wipe out the effects of this routine.  That
5734   is why a pointer, attrs, to the appropriate structure is passed as a
5735   parameter to this routine.
5736
5737   The second category should give us no worries, since any changes to hardware
5738   flow control accomplished by this routine should not affect the termio(s)/
5739   sgtty structures, and therefore will not be undone by later changes to them.
5740
5741   The second argument, status, means to turn on hardware flow control if
5742   nonzero, and to turn it off if zero.
5743
5744   Returns: 0 on apparent success, -1 on probable failure.
5745 */
5746
5747 /*
5748   The following business is for BSDI, where it was discovered that two
5749   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
5750   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
5751   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
5752   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
5753   define CRTSCTS correctly.
5754 */
5755 #ifdef FIXCRTSCTS
5756 #ifdef CRTSCTS
5757 #ifdef CCTS_OFLOW
5758 #ifdef CRTS_IFLOW
5759 #undef CRTSCTS
5760 #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
5761 #endif /* CRTS_IFLOW */
5762 #endif /* CCTS_OFLOW */
5763 #endif /* CRTSCTS */
5764 #endif /* FIXCRTSCTS */
5765
5766 static int
5767 tthflow(flow, status, attrs)
5768     int flow,                           /* Type of flow control (ckcdeb.h) */
5769     status;                             /* Nonzero = turn it on */
5770                                         /* Zero = turn it off */
5771 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
5772     struct termios *attrs;
5773 #else                                   /* System V */
5774 #ifdef ATTSV
5775 #ifdef ATT7300
5776 #ifdef UNIX351M
5777 /* AT&T UNIX 3.51m can set but not test for hardware flow control */
5778 #define RTSFLOW CTSCD
5779 #define CTSFLOW CTSCD
5780 #endif /* ATT7300 */
5781 #endif /* UNIX351M */
5782     struct termio *attrs;
5783 #else                                   /* BSD, V7, etc */
5784     struct sgttyb *attrs;               /* sgtty info... */
5785 #endif /* ATTSV */
5786 #endif /* BSD44ORPOSIX */
5787 /* tthflow */ {
5788
5789     int x = 0;                          /* tthflow() return code */
5790
5791 #ifdef Plan9
5792     return p9tthflow(flow, status);
5793 #else
5794
5795 #ifndef OXOS                            /* NOT Olivetti X/OS... */
5796 /*
5797   For SunOS 4.0 and later in the BSD environment ...
5798
5799   The declarations are copied and interpreted from the System V header files,
5800   so we don't actually have to pull in all the System V junk when building
5801   C-Kermit for SunOS in the BSD environment, which would be dangerous because
5802   having those symbols defined would cause us to take the wrong paths through
5803   the code.  The code in this section is used in both the BSD and Sys V SunOS
5804   versions.
5805 */
5806 #ifdef SUNOS41
5807 /*
5808   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
5809   because GNU CC uses different formats for the _IOxxx macros than regular CC;
5810   the POSIX forms work for both.  But the POSIX calls are not available in
5811   SunOS 4.0.
5812 */
5813 #define CRTSCTS 0x80000000              /* RTS/CTS flow control */
5814 #define TCSANOW 0                       /* Do it now */
5815
5816     struct termios {
5817         unsigned long c_iflag;          /* Input modes */
5818         unsigned long c_oflag;          /* Output modes */
5819         unsigned long c_cflag;          /* Control modes */
5820         unsigned long c_lflag;          /* Line discipline modes */
5821         char c_line;
5822         CHAR c_cc[17];
5823     };
5824     struct termios temp;
5825
5826 _PROTOTYP( int tcgetattr, (int, struct termios *) );
5827 _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
5828 /*
5829   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
5830   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
5831   since we don't need RTS/CTS during dialing, and after dialing is complete,
5832   we should have CD.  If not, we still communicate, but without RTS/CTS.
5833 */
5834     int mflags;                         /* Modem signal flags */
5835
5836 #ifdef NETCMD
5837     if (ttpipe) return(0);
5838 #endif /* NETCMD */
5839 #ifdef NETPTY
5840     if (ttpty) return(0);
5841 #endif /* NETPTY */
5842
5843     debug(F101,"tthflow SUNOS41 entry status","",status);
5844     if (!status) {                      /* Turn hard flow off */
5845         if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5846             (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5847             temp.c_cflag &= ~CRTSCTS;   /* It's there, remove it */
5848             x = tcsetattr(ttyfd,TCSANOW,&temp);
5849         }
5850     } else {                            /* Turn hard flow on */
5851         if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
5852             (mflags & TIOCM_CAR)) {             /* Check for CD */
5853             debug(F100,"tthflow SunOS has CD","",0);
5854             if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5855                 !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5856                 temp.c_cflag |= CRTSCTS;        /* Not there, add it */
5857                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5858             }
5859         } else {
5860             x = -1;
5861             debug(F100,"tthflow SunOS no CD","",0);
5862         }
5863     }
5864 #else
5865 #ifdef QNX
5866     struct termios temp;
5867 #ifdef NETCMD
5868     if (ttpipe) return(0);
5869 #endif /* NETCMD */
5870 #ifdef NETPTY
5871     if (ttpty) return(0);
5872 #endif /* NETPTY */
5873     debug(F101,"tthflow QNX entry status","",status);
5874     if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
5875         if (!status) {                  /* Turn hard flow off */
5876             if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
5877                 temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
5878                 attrs->c_cflag &= ~(IHFLOW|OHFLOW);
5879                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5880             }
5881         } else {                        /* Turn hard flow on */
5882             if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
5883                 temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
5884                 temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
5885                 ttraw.c_lflag |= IEXTEN;         /* Must be on */
5886                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5887                 attrs->c_cflag |= (IHFLOW|OHFLOW);
5888                 attrs->c_iflag &= ~(IXON|IXOFF);
5889             }
5890         }
5891     } else {
5892         x = -1;
5893         debug(F100, "tthflow QNX getattr fails", "", 0);
5894     }
5895 #else
5896 #ifdef POSIX_CRTSCTS
5897 /*
5898   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
5899   Note: Do not assume CRTSCTS is a one-bit field!
5900 */
5901     struct termios temp;
5902 #ifdef NETCMD
5903     if (ttpipe) return(0);
5904 #endif /* NETCMD */
5905 #ifdef NETPTY
5906     if (ttpty) return(0);
5907 #endif /* NETPTY */
5908     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
5909     errno = 0;
5910     x = tcgetattr(ttyfd, &temp);
5911     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
5912     errno = 0;
5913     if (x < 0) {
5914         x = -1;
5915     } else {
5916         if (!status) {                  /* Turn hard flow off */
5917             if (
5918 #ifdef COMMENT
5919                 /* This can fail because of sign extension */
5920                 /* e.g. in Linux where it's Bit 31 */
5921                 (temp.c_cflag & CRTSCTS) == CRTSCTS
5922 #else
5923                 (temp.c_cflag & CRTSCTS) != 0
5924 #endif /* COMMENT */
5925                 ) {
5926                 temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
5927                 attrs->c_cflag &= ~CRTSCTS;
5928                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5929                 debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
5930                       ckitoa(x),errno);
5931             } else {                    /* John Dunlap 2010-01-26 */
5932                 debug(F001,
5933                       "tthflow before forcing off attrs CRTSCTS",
5934                       "",
5935                       attrs->c_cflag&CRTSCTS
5936                       );
5937                 attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
5938                 debug(F001,
5939                       "tthflow after forcing off attrs CRTSCTS",
5940                       "",
5941                       attrs->c_cflag&CRTSCTS
5942                       );
5943                 }
5944         } else {                        /* Turn hard flow on */
5945             if (
5946 #ifdef COMMENT
5947                 /* This can fail because of sign extension */
5948                 (temp.c_cflag & CRTSCTS) != CRTSCTS
5949 #else
5950                 (temp.c_cflag & CRTSCTS) == 0
5951 #endif /* COMMENT */
5952                 ) {
5953                 temp.c_cflag |= CRTSCTS; /* Not there, add it */
5954                 temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
5955                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5956                 debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
5957                       ckitoa(x),errno);
5958                 attrs->c_cflag |= CRTSCTS;
5959                 attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5960             }
5961         }
5962     }
5963 #else
5964 #ifdef SUNOS4
5965 /*
5966   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
5967   prevents compilation with GNU gcc, which uses different formats for the
5968   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
5969   routines above, which work for both cc and gcc.
5970 */
5971 #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
5972 #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
5973 #define CRTSCTS 0x80000000                /* RTS/CTS flow control */
5974
5975     struct termios {
5976         unsigned long c_iflag;          /* Input modes */
5977         unsigned long c_oflag;          /* Output modes */
5978         unsigned long c_cflag;          /* Control modes */
5979         unsigned long c_lflag;          /* Line discipline modes */
5980         char c_line;
5981         CHAR c_cc[17];
5982     };
5983     struct termios temp;
5984 #ifdef NETCMD
5985     if (ttpipe) return(0);
5986 #endif /* NETCMD */
5987 #ifdef NETPTY
5988     if (ttpty) return(0);
5989 #endif /* NETPTY */
5990     debug(F101,"tthflow entry status","",status);
5991     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
5992         if (status) {                   /* Turn hard flow on */
5993             temp.c_cflag |= CRTSCTS;    /* Add RTS/CTS to them. */
5994             x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
5995             attrs->c_cflag |= CRTSCTS;  /* Add to global info. */
5996         } else {                        /* Turn hard flow off */
5997             temp.c_cflag &= ~CRTSCTS;
5998             x = ioctl(ttyfd,TCSETS,&temp);
5999             attrs->c_cflag &= ~CRTSCTS;
6000         }
6001     }
6002 #else                                   /* Not SunOS 4.0 or later */
6003 #ifdef AIXRS                            /* IBM AIX RS/6000 */
6004 #ifndef AIX41                           /* But only pre-4.x == SVR4 */
6005 #ifdef NETCMD
6006     if (ttpipe) return(0);
6007 #endif /* NETCMD */
6008 #ifdef NETPTY
6009     if (ttpty) return(0);
6010 #endif /* NETPTY */
6011     if (status) {
6012         if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
6013           debug(F100,"hardflow TXADDCD (rts) error", "", 0);
6014     } else {
6015         if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
6016           debug(F100,"hardflow TXDELCD (rts) error", "", 0);
6017     }
6018 #endif /* AIX41 */
6019 #else                                   /* Not AIX RS/6000 */
6020
6021 #ifdef ATTSV                            /* System V... */
6022
6023 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
6024 #define CK_SCOUNIX
6025 #else
6026 #ifdef M_UNIX                           /* SCO UNIX 3.2v4.x or earlier */
6027 #define CK_SCOUNIX
6028 #endif /* M_UNIX */
6029 #endif /* CK_SCOV5 */
6030
6031 #ifdef SCO_FORCE_RTSXOFF
6032 #ifdef CK_SCOUNIX                       /* But not SCO OpenServer 5.0.4 */
6033 #ifdef SCO_OSR504                       /* or later... */
6034 #undef CK_SCOUNIX
6035 #endif /* SCO_OSR504 */
6036 #endif /* CK_SCOUNIX */
6037 #endif /* SCO_FORCE_RTSXOFF */
6038
6039 #ifdef CK_SCOUNIX
6040 #ifdef POSIX
6041     struct termios temp;
6042 #ifdef NETCMD
6043     if (ttpipe) return(0);
6044 #endif /* NETCMD */
6045 #ifdef NETPTY
6046     if (ttpty) return(0);
6047 #endif /* NETPTY */
6048     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
6049     errno = 0;
6050     x = tcgetattr(ttyfd, &temp);
6051     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
6052 #else /* POSIX */
6053     struct termio temp;
6054 #ifdef NETCMD
6055     if (ttpipe) return(0);
6056 #endif /* NETCMD */
6057 #ifdef NETPTY
6058     if (ttpty) return(0);
6059 #endif /* NETPTY */
6060     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
6061     x = ioctl(ttyfd, TCGETA, &temp);
6062     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
6063 #endif /* POSIX */
6064 /*
6065   This is not really POSIX, since POSIX does not deal with hardware flow
6066   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
6067   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
6068   let's try forcing their definitions here.
6069 */
6070 #ifndef CTSFLOW
6071 #define CTSFLOW 0020000
6072     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
6073 #else
6074     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
6075 #endif /* CTSFLOW */
6076 #ifndef RTSFLOW
6077 #define RTSFLOW 0040000
6078     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
6079 #else
6080     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
6081 #endif /* RTSFLOW */
6082 #ifndef ORTSFL
6083 #define ORTSFL 0100000
6084     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
6085 #else
6086     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
6087 #endif /* ORTSFL */
6088
6089     if (x != -1) {
6090         if (status) {                   /* Turn it ON */
6091             temp.c_cflag |= RTSFLOW|CTSFLOW;
6092             attrs->c_cflag |= RTSFLOW|CTSFLOW;
6093 #ifdef ORTSFL
6094             temp.c_cflag &= ~ORTSFL;
6095             attrs->c_cflag &= ~ORTSFL;
6096 #endif /* ORTSFL */
6097             temp.c_iflag &= ~(IXON|IXOFF|IXANY);
6098             attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
6099         } else {                        /* Turn it OFF */
6100 #ifdef ORTSFL
6101             temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6102             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6103 #else  /* ORTSFL */
6104             temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
6105             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
6106 #endif /* ORTSFL */
6107         }
6108 #ifdef POSIX
6109         x = tcsetattr(ttyfd, TCSADRAIN, &temp);
6110 #else
6111         x = ioctl(ttyfd, TCSETA, &temp);
6112 #endif /* POSIX */
6113         debug(F101,"tthflow SCO set modes","",x);
6114     }
6115 #else /* Not SCO UNIX */
6116 #ifdef NETCMD
6117     if (ttpipe) return(0);
6118 #endif /* NETCMD */
6119 #ifdef NETPTY
6120     if (ttpty) return(0);
6121 #endif /* NETPTY */
6122     if (!status) {                      /* Turn it OFF */
6123 #ifdef RTSXOFF
6124         debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
6125         rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
6126 #ifdef TCSETX
6127         x = ioctl(ttyfd,TCSETX,&rctsx);
6128         debug(F101,"tthflow ATTSV TCSETX OFF","",x);
6129 #else
6130         x = -1
6131         debug(F100,"tthflow TCSETX not defined","",0);
6132 #endif /* TCSETX */
6133 #else
6134         debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
6135 #endif /* RTSXOFF */
6136 #ifdef DTRXOFF
6137         debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
6138         rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6139         x = ioctl(ttyfd,TCSETX,&rctsx);
6140         debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
6141 #else
6142         debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6143 #endif /* DTRXOFF */
6144     } else {                            /* Turn it ON. */
6145         if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
6146             debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
6147 #ifdef RTSXOFF
6148             /* This is the preferred way, according to SVID3 */
6149 #ifdef TCGETX
6150             x = ioctl(ttyfd,TCGETX,&rctsx);
6151             debug(F101,"tthflow TCGETX","",x);
6152             if (x > -1) {
6153                 rctsx.x_hflag |= RTSXOFF | CTSXON;
6154                 x = ioctl(ttyfd,TCSETX,&rctsx);
6155                 debug(F100,"tthflow ATTSV ioctl","",x);
6156             }
6157 #else
6158             debug(F100,"tthflow TCGETX not defined","",0);
6159             x = -1
6160 #endif /* TCGETX */
6161 #else
6162             debug(F100,"tthflow RTSXOFF not defined","",0);
6163             x = -1;
6164 #endif /* RTSXOFF */
6165         } else if (flow == FLO_DTRC) {  /* DTR/CD Flow control... */
6166             debug(F100,"tthflow ATTSV DTR/CD ON","",0);
6167 #ifdef DTRXOFF
6168             /* This is straight out of SVID R4 */
6169             if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
6170                 rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6171                 x = ioctl(ttyfd,TCSETX,&rctsx);
6172             }
6173 #else
6174             debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6175             x = -1;
6176 #endif /* DTRXOFF */
6177         }
6178     }
6179 #endif /* CK_SCOUNIX */
6180
6181 #else /* not System V... */
6182
6183 #ifdef CK_DTRCTS
6184 #ifdef LDODTR
6185 #ifdef LDOCTS
6186 #ifdef NETCMD
6187     if (ttpipe) return(0);
6188 #endif /* NETCMD */
6189 #ifdef NETPTY
6190     if (ttpty) return(0);
6191 #endif /* NETPTY */
6192     x = LDODTR | LDOCTS;                /* Found only on UTEK? */
6193     if (flow == FLO_DTRT && status) {   /* Use hardware flow control */
6194         if (lmodef) {
6195             x = ioctl(ttyfd,TIOCLBIS,&x);
6196             if (x < 0) {
6197                 debug(F100,"hardflow TIOCLBIS error","",0);
6198             } else {
6199                 lmodef++;
6200                 debug(F100,"hardflow TIOCLBIS ok","",0);
6201             }
6202         }
6203     } else {
6204         if (lmodef) {
6205             x = ioctl(ttyfd,TIOCLBIC,&x);
6206             if (x < 0) {
6207                 debug(F100,"hardflow TIOCLBIC error","",0);
6208             } else {
6209                 lmodef++;
6210                 debug(F100,"hardflow TIOCLBIC ok","",0);
6211             }
6212         }
6213     }
6214 #endif /* LDODTR */
6215 #endif /* LDOCTS */
6216 #endif /* CK_DTRCTS */
6217 #endif /* ATTSV */
6218 #endif /* AIXRS */
6219 #endif /* SUNOS4 */
6220 #endif /* QNX */
6221 #endif /* POSIX_CRTSCTS */
6222 #endif /* SUNOS41 */
6223
6224 #else /* OXOS */
6225
6226     struct termios temp;                /* Olivetti X/OS ... */
6227
6228 #ifdef NETCMD
6229     if (ttpipe) return(0);
6230 #endif /* NETCMD */
6231 #ifdef NETPTY
6232     if (ttpty) return(0);
6233 #endif /* NETPTY */
6234     x = ioctl(ttyfd,TCGETS,&temp);
6235     if (x == 0) {
6236         temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
6237         if (status) {
6238             switch (flow) {
6239               case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
6240                 break;
6241               case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
6242                 break;
6243             }
6244         }
6245         x = ioctl(ttyfd,TCSETS,&temp);
6246     }
6247 #endif /* OXOS */
6248     return(x);
6249
6250 #endif /* Plan9 */
6251 }
6252
6253 /*  T T P K T  --  Condition the communication line for packets */
6254 /*                 or for modem dialing */
6255
6256 /*
6257   If called with speed > -1, also set the speed.
6258   Returns 0 on success, -1 on failure.
6259
6260   NOTE: the "xflow" parameter is supposed to be the currently selected
6261   type of flow control, but for historical reasons, this parameter is also
6262   used to indicate that we are dialing.  Therefore, when the true flow
6263   control setting is needed, we access the external variable "flow", rather
6264   than trusting our "xflow" argument.
6265 */
6266 int
6267 #ifdef CK_ANSIC
6268 ttpkt(long speed, int xflow, int parity)
6269 #else
6270 ttpkt(speed,xflow,parity) long speed; int xflow, parity;
6271 #endif /* CK_ANSIC */
6272 /* ttpkt */ {
6273 #ifndef NOLOCAL
6274     int s2;
6275     int s = -1;
6276 #endif /* NOLOCAL */
6277     int x;
6278     extern int flow;                    /* REAL flow-control setting */
6279
6280     if (ttyfd < 0) return(-1);          /* Not open. */
6281
6282     debug(F101,"ttpkt parity","",parity);
6283     debug(F101,"ttpkt xflow","",xflow);
6284     debug(F101,"ttpkt speed","",(int) speed);
6285
6286     ttprty = parity;                    /* Let other tt functions see these. */
6287     ttspeed = speed;                    /* Make global copy for this module */
6288     ttpmsk = ttprty ? 0177 : 0377;      /* Parity stripping mask */
6289 #ifdef PARSENSE
6290     needpchk = ttprty ? 0 : 1;          /* Parity check needed? */
6291 #else
6292     needpchk = 0;
6293 #endif /* PARSENSE */
6294
6295     debug(F101,"ttpkt ttpmsk","",ttpmsk);
6296     debug(F101,"ttpkt netconn","",netconn);
6297
6298 #ifdef NETCONN                          /* No mode-changing for telnet */
6299     if (netconn) {
6300 #ifdef TCPSOCKET
6301 #ifdef TCP_NODELAY
6302         if (ttnet == NET_TCPB) {        /* But turn off Nagle */
6303             extern int tcp_nodelay;
6304             nodelay_sav = tcp_nodelay;
6305             no_delay(ttyfd,1);
6306         }
6307 #endif /* TCP_NODELAY */
6308 #ifdef TN_COMPORT
6309         if (istncomport()) {
6310             int rc = -1;
6311             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
6312                  /* && ttcarr == curcarr */ ) {
6313                 debug(F100,"ttpkt modes already set, skipping...","",0);
6314                 return(0);              /* Already been called. */
6315             }
6316             if (flow != ttflow) {
6317                 if ((rc = tnsetflow(flow)) < 0)
6318                   return(rc);
6319                 ttflow = flow;
6320             }
6321             if (speed != ttspeed) {
6322                 if (speed <= 0) 
6323                   speed = tnc_get_baud();
6324                 else if ((rc = tnc_set_baud(speed)) < 0)
6325                   return(rc);
6326                 ttspeed = speed;
6327             }
6328             tnc_set_datasize(8);
6329             tnc_set_stopsize(stopbits);
6330
6331 #ifdef HWPARITY
6332             if (hwparity) {
6333                 switch (hwparity) {
6334                   case 'e':                     /* Even */
6335                     debug(F100,"ttres 8 bits + even parity","",0);
6336                     tnc_set_parity(3);
6337                     break;
6338                   case 'o':                     /* Odd */
6339                     debug(F100,"ttres 8 bits + odd parity","",0);
6340                     tnc_set_parity(2);
6341                     break;
6342                   case 'm':                     /* Mark */
6343                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6344                     tnc_set_parity(4);
6345                     break;
6346                   case 's':                     /* Space */
6347                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6348                     tnc_set_parity(5);
6349                     break;
6350                 }
6351             } else 
6352 #endif /* HWPARITY */
6353             {
6354                 tnc_set_parity(1);              /* None */
6355             }
6356             tvtflg = 0;
6357             return(0);
6358         }
6359 #endif /* TN_COMPORT */
6360 #endif /* TCPSOCKET */
6361         tvtflg = 0;
6362         return(0);
6363     }
6364 #endif /* NETCONN */
6365 #ifdef NETCMD
6366     if (ttpipe) return(0);
6367 #endif /* NETCMD */
6368 #ifdef NETPTY
6369     if (ttpty) return(0);
6370 #endif /* NETPTY */
6371
6372 #ifndef Plan9
6373     if (ttfdflg && !isatty(ttyfd)) return(0);
6374 #endif /* Plan9 */
6375
6376 #ifdef COHERENT
6377 #define SVORPOSIX
6378 #endif /* COHERENT */
6379
6380 #ifndef SVORPOSIX                       /* Berkeley, V7, etc. */
6381 #ifdef LPASS8
6382 /*
6383  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
6384  after having previously set it to NONE without closing and reopening the
6385  device.  Unless there's something I overlooked below...
6386 */
6387     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
6388         debug(F101,"ttpkt executing horrible flow kludge","",0);
6389         ttclos(0);                      /* Close it */
6390         x = 0;
6391         ttopen(ttnmsv,&x,ttmdm,0);      /* Open it again */
6392     }
6393 #endif /* LPASS8 */
6394 #endif /* SVORPOSIX */
6395
6396 #ifdef COHERENT                         /* This must be vestigial since we */
6397 #undef SVORPOSIX                        /* reverse it a few lines below... */
6398 #endif /* COHERENT */
6399
6400     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
6401       ttflow = xflow;                   /* Now make this available too. */
6402
6403 #ifndef NOLOCAL
6404     if (xlocal) {
6405         s2 = (int) (speed / 10L);       /* Convert bps to cps */
6406         debug(F101,"ttpkt calling ttsspd","",s2);
6407         s = ttsspd(s2);                 /* Check and set the speed */
6408         debug(F101,"ttpkt ttsspd result","",s);
6409         carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
6410                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6411         tvtflg = 0;                     /* So ttvt() will work next time */
6412     }
6413 #endif /* NOLOCAL */
6414
6415 #ifdef COHERENT
6416 #define SVORPOSIX
6417 #endif /* COHERENT */
6418
6419 #ifndef SVORPOSIX                       /* BSD section */
6420     if (flow == FLO_RTSC ||             /* Hardware flow control */
6421         flow == FLO_DTRC ||
6422         flow == FLO_DTRT) {
6423         tthflow(flow, 1, &ttraw);
6424         debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
6425         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6426         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6427     } else if (flow == FLO_NONE) {      /* No flow control */
6428         debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
6429         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6430         tthflow(flow, 0, &ttraw);       /* Turn off any hardware f/c too */
6431         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6432     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
6433         debug(F100,"ttpkt keeping original TANDEM","",0);
6434         ttraw.sg_flags &= ~TANDEM;
6435         ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
6436         /* NOTE: We should also handle hardware flow control here! */
6437     }
6438
6439 /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
6440
6441     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
6442         debug(F100,"ttpkt turning on TANDEM","",0);
6443         ttraw.sg_flags |= TANDEM;       /* So ask for it. */
6444
6445 #ifdef LPASS8                           /* Can pass 8-bit data through? */
6446 /* If the LPASS8 local mode is available, then flow control can always  */
6447 /* be used, even if parity is none and we are transferring 8-bit data.  */
6448 /* But we only need to do all this if Xon/Xoff is requested. */
6449 /* BUT... this tends not to work through IP or LAT connections, terminal */
6450 /* servers, telnet, rlogin, etc, so it is currently disabled. */
6451         x = LPASS8;                     /* If LPASS8 defined, then */
6452         debug(F100,"ttpkt executing LPASS8 code","",0);
6453         if (lmodef) {                   /* TIOCLBIS must be too. */
6454             x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
6455             if (x < 0) {
6456                 debug(F100,"ttpkt TIOCLBIS error","",0);
6457             } else {
6458                 lmodef++;
6459                 debug(F100,"ttpkt TIOCLBIS ok","",0);
6460             }
6461         }
6462 /*
6463  But if we use LPASS8 mode, we must explicitly turn off
6464  terminal interrupts of all kinds.
6465 */
6466 #ifdef TIOCGETC                         /* Not rawmode, */
6467         if (tcharf && (xlocal == 0)) {  /* must turn off */
6468             tchnoi.t_intrc = -1;        /* interrupt character */
6469             tchnoi.t_quitc = -1;        /* and quit character. */
6470             tchnoi.t_startc = 17;       /* Make sure xon */
6471             tchnoi.t_stopc = 19;        /* and xoff not ignored. */
6472 #ifndef NOBRKC
6473             tchnoi.t_eofc = -1;         /* eof character. */
6474             tchnoi.t_brkc = -1;         /* brk character. */
6475 #endif /* NOBRKC */
6476             if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6477                 debug(F100,"ttpkt TIOCSETC failed","",0);
6478             } else {
6479                 tcharf = 1;
6480                 debug(F100,"ttpkt TIOCSETC ok","",0);
6481             }
6482 #ifdef COMMENT
6483 /* only for paranoid debugging */
6484             if (tcharf) {
6485                 struct tchars foo;
6486                 char tchbuf[100];
6487                 ioctl(0,TIOCGETC,&foo);
6488                 sprintf(tchbuf,
6489                     "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
6490                     foo.t_intrc, foo.t_quitc, foo.t_startc,
6491                     foo.t_stopc, foo.t_eofc,  foo.t_brkc);
6492                 debug(F110,"ttpkt chars",tchbuf,0);
6493             }
6494 #endif /* COMMENT */
6495         }
6496         ttraw.sg_flags |= CBREAK;       /* Needed for unknown reason */
6497 #endif /* TIOCGETC */
6498
6499 /* Prevent suspend during packet mode */
6500 #ifdef TIOCGLTC                         /* Not rawmode, */
6501         if (ltcharf && (xlocal == 0)) { /* must turn off */
6502             ltchnoi.t_suspc = -1;       /* suspend character */
6503             ltchnoi.t_dsuspc = -1;      /* and delayed suspend character */
6504             if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6505                 debug(F100,"ttpkt TIOCSLTC failed","",0);
6506             } else {
6507                 ltcharf = 1;
6508                 debug(F100,"ttpkt TIOCSLTC ok","",0);
6509             }
6510         }
6511 #endif /* TIOCGLTC */
6512
6513 #else /* LPASS8 not defined */
6514
6515 /* Previously, BSD-based implementations always */
6516 /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
6517 /* This allows the flow control requested above to actually work, but only */
6518 /* if the user asks for parity (which also means they get 8th-bit quoting). */
6519
6520         if (parity) {                   /* If parity, */
6521             ttraw.sg_flags &= ~RAW;     /* use cooked mode */
6522 #ifdef COMMENT
6523 /* WHY??? */
6524             if (xlocal)
6525 #endif /* COMMENT */
6526               ttraw.sg_flags |= CBREAK;
6527             debug(F101,"ttpkt cooked, cbreak, parity","",parity);
6528 #ifdef TIOCGETC                         /* Not rawmode, */
6529             if (tcharf && (xlocal == 0)) { /* must turn off */
6530                 tchnoi.t_intrc = -1;    /* interrupt character */
6531                 tchnoi.t_quitc = -1;    /* and quit character. */
6532                 tchnoi.t_startc = 17;   /* Make sure xon */
6533                 tchnoi.t_stopc = 19;    /* and xoff not ignored. */
6534 #ifndef NOBRKC
6535                 tchnoi.t_eofc = -1;     /* eof character. */
6536                 tchnoi.t_brkc = -1;     /* brk character. */
6537 #endif /* NOBRKC */
6538                 if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6539                     debug(F100,"ttpkt TIOCSETC failed","",0);
6540                 } else {
6541                     tcharf = 1;
6542                     debug(F100,"ttpkt TIOCSETC ok","",0);
6543                 }
6544             }
6545 #endif /* TIOCGETC */
6546 #ifdef TIOCGLTC                         /* Not rawmode, */
6547 /* Prevent suspend during packet mode */
6548             if (ltcharf && (xlocal == 0)) { /* must turn off */
6549                 ltchnoi.t_suspc = -1;   /* suspend character */
6550                 ltchnoi.t_dsuspc = -1;  /* and delayed suspend character */
6551                 if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6552                     debug(F100,"ttpkt TIOCSLTC failed","",0);
6553                 } else {
6554                     ltcharf = 1;
6555                     debug(F100,"ttpkt TIOCSLTC ok","",0);
6556                 }
6557             }
6558 #endif /* TIOCGLTC */
6559         } else {                        /* If no parity, */
6560             ttraw.sg_flags |= RAW;      /* must use 8-bit raw mode. */
6561             debug(F101,"ttpkt setting rawmode, parity","",parity);
6562         }
6563 #endif /* LPASS8 */
6564     } /* End of Xon/Xoff section */
6565
6566     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
6567 #ifdef LCASE
6568     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
6569 #else
6570     ttraw.sg_flags &= ~(ECHO|CRMOD);
6571 #endif /* LCASE */
6572
6573 #ifdef TOWER1
6574     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
6575 #endif /* TOWER1 */
6576
6577 #ifdef BELLV10
6578     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
6579       return(-1);
6580 #else
6581     errno = 0;
6582     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
6583         debug(F101,"ttpkt stty failed","",errno);
6584         return(-1);
6585     }
6586 #endif /* BELLV10 */
6587     debug(F100,"ttpkt stty ok","",0);
6588
6589 #ifdef sony_news
6590     x = xlocal ? km_ext : km_con;       /* Put line in ASCII mode. */
6591     if (x != -1) {                      /* Make sure we know original modes. */
6592         x &= ~KM_TTYPE;
6593         x |= KM_ASCII;
6594         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
6595             perror("ttpkt can't set ASCII mode");
6596             debug(F101,"ttpkt error setting ASCII mode","",x);
6597             return(-1);
6598         }
6599     }
6600     debug(F100,"ttpkt set ASCII mode ok","",0);
6601 #endif /* sony_news */
6602
6603     if (xlocal == 0) {                  /* Turn this off so we can read */
6604         signal(SIGINT,SIG_IGN);         /* Ctrl-C chars typed at console */
6605         sigint_ign = 1;
6606     }
6607     tvtflg = 0;                         /* So ttvt() will work next time */
6608     debug(F100,"ttpkt success","",0);
6609     return(0);
6610
6611 #endif /* Not ATTSV or POSIX */
6612
6613 /* AT&T UNIX and POSIX */
6614
6615 #ifdef COHERENT
6616 #define SVORPOSIX
6617 #endif /* COHERENT */
6618
6619 #ifdef SVORPOSIX
6620     if (flow == FLO_XONX) {             /* Xon/Xoff */
6621         ttraw.c_iflag |= (IXON|IXOFF);
6622         tthflow(flow, 0, &ttraw);
6623     } else if (flow == FLO_NONE) {      /* None */
6624         /* NOTE: We should also turn off hardware flow control here! */
6625         ttraw.c_iflag &= ~(IXON|IXOFF);
6626         tthflow(flow, 0, &ttraw);
6627     } else if (flow == FLO_KEEP) {      /* Keep */
6628         ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
6629         ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6630         /* NOTE: We should also handle hardware flow control here! */
6631 #ifdef POSIX_CRTSCTS
6632 /* In Linux case, we do this, which is unlikely to be portable */
6633         ttraw.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
6634         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6635 #endif /* POSIX_CRTSCTS */
6636     } else if (flow == FLO_RTSC ||      /* Hardware */
6637                flow == FLO_DTRC ||
6638                flow == FLO_DTRT) {
6639         ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
6640         tthflow(flow, 1, &ttraw);
6641     }
6642     ttraw.c_lflag &= ~(ICANON|ECHO);
6643     ttraw.c_lflag &= ~ISIG;             /* Do NOT check for interrupt chars */
6644
6645 #ifndef OXOS
6646 #ifdef QNX
6647     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
6648 #endif /* QNX */
6649 #ifndef COHERENT
6650       ttraw.c_lflag &= ~IEXTEN;         /* Turn off ^O/^V processing */
6651 #endif /* COHERENT */
6652 #else /* OXOS */
6653     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
6654 #endif /* OXOS */
6655     ttraw.c_lflag |= NOFLSH;            /* Don't flush */
6656     ttraw.c_iflag |= IGNPAR;            /* Ignore parity errors */
6657 #ifdef ATTSV
6658 #ifdef BSD44
6659     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
6660 #else
6661     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
6662 #endif /* BSD44 */
6663 #else /* POSIX */
6664     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
6665 #endif /* ATTSV */
6666     ttraw.c_oflag &= ~OPOST;
6667     ttraw.c_cflag &= ~(CSIZE);
6668     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
6669
6670 #ifdef CSTOPB
6671     if (xlocal) {
6672         if (stopbits == 2) {
6673             ttraw.c_cflag |= CSTOPB;    /* 2 stop bits */
6674             debug(F100,"ttpkt 2 stopbits","",0);
6675         } else if (stopbits == 1) {
6676             ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
6677             debug(F100,"ttpkt 1 stopbit","",0);
6678         }
6679     }
6680 #endif /* CSTOPB */
6681
6682 #ifdef HWPARITY
6683     if (hwparity && xlocal) {           /* Hardware parity */
6684         ttraw.c_cflag |= PARENB;        /* Enable parity */
6685 #ifdef COMMENT
6686 /* Uncomment this only if needed -- I don't think it is */
6687         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
6688         ttraw.c_cflag |= CS8;           /* And set it to 8 */
6689 #endif /* COMMENT */
6690 #ifdef IGNPAR
6691         ttraw.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
6692         debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
6693 #endif /* IGNPAR */
6694         switch (hwparity) {
6695           case 'e':                     /* Even */
6696             ttraw.c_cflag &= ~(PARODD);
6697             debug(F100,"ttpkt 8 bits + even parity","",0);
6698             break;
6699           case 'o':                     /* Odd */
6700             ttraw.c_cflag |= PARODD;
6701             debug(F100,"ttpkt 8 bits + odd parity","",0);
6702             break;
6703           case 'm':                     /* Mark */
6704           case 's':                     /* Space */
6705             /* PAREXT is mentioned in SVID but the details are not given. */
6706             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
6707             debug(F100,"ttpkt 8 bits + invalid parity","",0);
6708             break;
6709         }
6710     } else {                            /* We handle parity ourselves */
6711 #endif /* HWPARITY */
6712         ttraw.c_cflag &= ~(PARENB);     /* Don't enable parity */
6713 #ifdef HWPARITY
6714     }
6715 #endif /* HWPARITY */
6716
6717 #ifdef IX370
6718     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
6719     ttraw.c_cc[5] = 1;
6720 #else
6721 #ifndef VEOF                            /* for DGUX this is VEOF, not VMIN */
6722     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
6723 #else
6724 #ifndef OXOS
6725 #ifdef VMIN
6726     ttraw.c_cc[VMIN] = 1;
6727 #endif /* VMIN */
6728 #else /* OXOS */
6729     ttraw.c_min = 1;
6730 #endif /* OXOS */
6731 #endif /* VEOF */
6732 #ifndef VEOL                            /* for DGUX this is VEOL, not VTIME */
6733     ttraw.c_cc[5] = 0;   /* [VTIME] when this many secs/10 expire w/no input */
6734 #else
6735 #ifndef OXOS
6736 #ifdef VTIME
6737     ttraw.c_cc[VTIME] = 0;
6738 #endif /* VTIME */
6739 #else /* OXOS */
6740     ttraw.c_time = 0;
6741 #endif /* OXOS */
6742 #endif /* VEOL */
6743 #endif /* IX370 */
6744
6745 #ifdef VINTR                            /* Turn off interrupt character */
6746     if (xlocal == 0)                    /* so ^C^C can break us out of */
6747       ttraw.c_cc[VINTR] = 0;            /* packet mode. */
6748 #endif /* VINTR */
6749
6750 #ifdef Plan9
6751     if (p9ttyparity('n') < 0)
6752         return -1;
6753 #else
6754 #ifdef BSD44ORPOSIX
6755     errno = 0;
6756 #ifdef BEOSORBEBOX
6757     ttraw.c_cc[VMIN] = 0;               /* DR7 can only poll. */
6758 #endif /* BEOSORBEBOX */
6759
6760 #define TESTING234
6761 #ifdef TESTING234
6762     if (1) {
6763         debug(F100,"ttpkt TESTING234 rawmode","",0);
6764
6765         /* iflags */
6766         ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
6767         ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
6768         ttraw.c_iflag |= IGNBRK;
6769 #ifdef IMAXBEL
6770         ttraw.c_iflag &= ~IMAXBEL;
6771 #endif  /* IMAXBEL */
6772 #ifdef IXANY
6773         ttraw.c_iflag &= ~IXANY;
6774 #endif  /* IXANY */
6775 #ifdef IUCLC
6776         ttraw.c_iflag &= ~IUCLC;
6777 #endif /* IUCLC */
6778
6779         /* oflags */
6780         ttraw.c_oflag &= ~OPOST;
6781 #ifdef OXTABS
6782         ttraw.c_oflag &= ~OXTABS;
6783 #endif /* OXTABS */
6784 #ifdef ONOCR
6785         ttraw.c_oflag &= ~ONOCR;
6786 #endif /* ONOCR */
6787 #ifdef ONLRET
6788         ttraw.c_oflag &= ~ONLRET;
6789 #endif /* ONLRET */
6790 #ifdef ONLCR
6791         ttraw.c_oflag &= ~ONLCR;
6792 #endif /* ONLCR */
6793
6794         /* lflags */
6795         ttraw.c_lflag &= ~ECHO;
6796 #ifdef ECHOE
6797         ttraw.c_lflag &= ~ECHOE;
6798 #endif /* ECHOE */
6799 #ifdef ECHONL
6800         ttraw.c_lflag &= ~ECHONL;
6801 #endif /* ECHONL */
6802 #ifdef ECHOPRT
6803         ttraw.c_lflag &= ~ECHOPRT;
6804 #endif /* ECHOPRT */
6805 #ifdef ECHOKE
6806         ttraw.c_lflag &= ~ECHOKE;
6807 #endif /* ECHOKE */
6808 #ifdef ECHOCTL
6809         ttraw.c_lflag &= ~ECHOCTL;
6810 #endif /* ECHOCTL */
6811 #ifdef ALTWERASE
6812         ttraw.c_lflag &= ~ALTWERASE;
6813 #endif /* ALTWERASE */
6814 #ifdef EXTPROC
6815         ttraw.c_lflag &= ~EXTPROC;
6816 #endif /* EXTPROC */
6817         ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
6818 #ifdef NOKERNINFO
6819         ttraw.c_lflag |= NOKERNINFO;
6820 #endif  /* NOKERNINFO */
6821         /* ttraw.c_lflag |= NOFLSH; */
6822         ttraw.c_lflag &= ~NOFLSH;
6823
6824         /* cflags */
6825         ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
6826         ttraw.c_cflag |= CS8|CREAD;
6827 #ifdef VMIN
6828         ttraw.c_cc[VMIN] = 1;           /* Supposedly needed for AIX */
6829 #endif  /* VMIN */
6830
6831     }
6832 #endif /* TESTING234 */
6833
6834     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
6835     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
6836     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
6837     if (x < 0) {
6838         debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
6839         return(-1);
6840     }
6841 #else /* BSD44ORPOSIX */
6842     x = ioctl(ttyfd,TCSETAW,&ttraw);
6843     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
6844     if (x < 0) {  /* set new modes . */
6845         debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
6846         return(-1);
6847     }
6848 #endif /* BSD44ORPOSIX */
6849 #endif /* Plan9 */
6850     tvtflg = 0;
6851     debug(F100,"ttpkt ok","",0);
6852     return(0);
6853 #endif /* ATTSV */
6854
6855 #ifdef COHERENT
6856 #undef SVORPOSIX
6857 #endif /* COHERENT */
6858
6859 }
6860
6861 /*  T T S E T F L O W  --  Set flow control immediately.  */
6862
6863 #ifdef COHERENT
6864 #define SVORPOSIX
6865 #endif /* COHERENT */
6866
6867 int
6868 ttsetflow(flow) int flow; {
6869     if (ttyfd < 0)                      /* A channel must be open */
6870       return(-1);
6871
6872     debug(F101,"ttsetflow flow","",flow);
6873
6874 #ifdef TN_COMPORT
6875     if (netconn && istncomport()) {
6876         debug(F101,"ttsetflow net modem","",ttmdm);
6877         return(tnsetflow(flow));
6878     }
6879 #endif /* TN_COMPORT */
6880 #ifdef NETCMD
6881     if (ttpipe) return(0);
6882 #endif /* NETCMD */
6883 #ifdef NETPTY
6884     if (ttpty) return(0);
6885 #endif /* NETPTY */
6886
6887 #ifdef COMMENT
6888     /* This seems to hurt... */
6889     if (flow == FLO_KEEP)
6890       return(0);
6891 #endif /* COMMENT */
6892
6893     if (flow == FLO_RTSC ||             /* Hardware flow control... */
6894         flow == FLO_DTRC ||
6895         flow == FLO_DTRT) {
6896         tthflow(flow, 1, &ttraw);
6897 #ifndef SVORPOSIX
6898         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6899 #else
6900         ttraw.c_iflag &= ~(IXON|IXOFF);
6901 #endif /* SVORPOSIX */
6902
6903     } else if (flow == FLO_XONX) {      /* Xon/Xoff... */
6904
6905 #ifndef SVORPOSIX
6906         ttraw.sg_flags |= TANDEM;
6907 #else
6908         ttraw.c_iflag |= (IXON|IXOFF);
6909 #endif /* SVORPOSIX */
6910         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off hardware flow control */
6911
6912     } else if (flow == FLO_NONE) {      /* No flow control */
6913
6914 #ifndef SVORPOSIX
6915         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6916 #else
6917         ttraw.c_iflag &= ~(IXON|IXOFF);
6918 #endif /* SVORPOSIX */
6919         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off any hardware f/c too */
6920     }
6921
6922 /* Set the new modes... */
6923
6924 #ifndef SVORPOSIX                       /* BSD and friends */
6925 #ifdef BELLV10
6926     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
6927       return(-1);
6928 #else
6929 #ifndef MINIX2
6930     if (stty(ttyfd,&ttraw) < 0)
6931       return(-1);
6932 #endif /* MINIX2 */
6933 #endif /* BELLV10 */
6934 #else
6935 #ifdef BSD44ORPOSIX                     /* POSIX */
6936     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
6937       return(-1);
6938 #else                                   /* System V */
6939     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
6940       return(-1);
6941 #endif /* BSD44ORPOSIX */
6942 #endif /* SVORPOSIX */
6943     return(0);
6944 }
6945 #ifdef COHERENT
6946 #undef SVORPOSIX
6947 #endif /* COHERENT */
6948
6949 /*  T T V T -- Condition communication device for use as virtual terminal. */
6950
6951 int
6952 #ifdef CK_ANSIC
6953 ttvt(long speed, int flow)
6954 #else
6955 ttvt(speed,flow) long speed; int flow;
6956 #endif /* CK_ANSIC */
6957 /* ttvt */ {
6958     int s, s2, x;
6959
6960     debug(F101,"ttvt ttyfd","",ttyfd);
6961     debug(F101,"ttvt tvtflg","",tvtflg);
6962     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
6963     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
6964     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
6965
6966 /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
6967 /* Maybe it would be simpler to use it... */
6968
6969     ttpmsk = 0xff;
6970 #ifdef NOLOCAL
6971     return(conbin((char)escchr));
6972 #else
6973     if (ttyfd < 0) {                    /* Not open. */
6974         if (ttchk() < 0)
6975           return(-1);
6976         else                            /* But maybe something buffered. */
6977           return(0);
6978     }
6979 #ifdef NETCMD
6980     if (ttpipe) return(0);
6981 #endif /* NETCMD */
6982 #ifdef NETPTY
6983     if (ttpty) return(0);
6984 #endif /* NETPTY */
6985 #ifdef NETCONN
6986     if (netconn) {
6987 #ifdef TCPSOCKET
6988 #ifdef TCP_NODELAY
6989         {
6990             extern int tcp_nodelay;
6991             if (ttnet == NET_TCPB) {
6992                 if (nodelay_sav > -1) {
6993                     no_delay(ttyfd,nodelay_sav);
6994                     nodelay_sav = -1;
6995                 }
6996             }
6997         }
6998 #endif /* TCP_NODELAY */
6999 #ifdef TN_COMPORT
7000         if (istncomport()) {
7001             int rc = -1;
7002             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7003                  /* && ttcarr == curcarr */ ) {
7004                 debug(F100,"ttvt modes already set, skipping...","",0);
7005                 return(0);                      /* Already been called. */
7006             }
7007             if (flow != ttflow) {
7008                 if ((rc = tnsetflow(flow)) < 0)
7009                   return(rc);
7010                 ttflow = flow;
7011             }
7012             if (speed != ttspeed) {
7013                 if (speed <= 0) 
7014                   speed = tnc_get_baud();
7015                 else if ((rc = tnc_set_baud(speed)) < 0)
7016                   return(rc);
7017                 ttspeed = speed;
7018             }
7019             tnc_set_datasize(8);
7020             tnc_set_stopsize(stopbits);
7021
7022 #ifdef HWPARITY
7023             if (hwparity) {
7024                 switch (hwparity) {
7025                   case 'e':             /* Even */
7026                     debug(F100,"ttres 8 bits + even parity","",0);
7027                     tnc_set_parity(3);
7028                     break;
7029                   case 'o':             /* Odd */
7030                     debug(F100,"ttres 8 bits + odd parity","",0);
7031                     tnc_set_parity(2);
7032                     break;
7033                   case 'm':             /* Mark */
7034                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
7035                     tnc_set_parity(4);
7036                     break;
7037                   case 's':             /* Space */
7038                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
7039                     tnc_set_parity(5);
7040                     break;
7041                 }
7042             } else
7043 #endif /* HWPARITY */
7044             {
7045                 tnc_set_parity(1);      /* None */
7046             }
7047             tvtflg = 1;
7048             return(0);
7049         }
7050 #endif /* TN_COMPORT */
7051 #endif /* TCPSOCKET */
7052         tvtflg = 1;                     /* Network connections... */
7053         debug(F100,"ttvt network connection, skipping...","",0);
7054         return(0);                      /* ... require no special setup */
7055     }
7056 #endif /* NETCONN */
7057
7058     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7059         /* && ttcarr == curcarr */ )
7060       {
7061           debug(F100,"ttvt modes already set, skipping...","",0);
7062           return(0);                    /* Already been called. */
7063       }
7064
7065     if (ttfdflg
7066 #ifndef Plan9
7067         && !isatty(ttyfd)
7068 #endif /* Plan9 */
7069         ) {
7070         debug(F100,"ttvt using external fd, skipping...","",0);
7071         return(0);
7072     }
7073
7074     debug(F100,"ttvt setting modes...","",0);
7075
7076     if (xlocal) {                       /* For external lines... */
7077         s2 = (int) (speed / 10L);
7078         s = ttsspd(s2);                 /* Check/set the speed */
7079         carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
7080                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
7081     } else
7082       s = s2 = -1;
7083
7084 #ifdef COHERENT
7085 #define SVORPOSIX
7086 #endif /* COHERENT */
7087
7088 #ifndef SVORPOSIX
7089     /* Berkeley, V7, etc */
7090     if (flow == FLO_RTSC ||             /* Hardware flow control */
7091         flow == FLO_DTRC ||
7092         flow == FLO_DTRT) {
7093         tthflow(flow, 1, &tttvt);
7094         debug(F100,"ttvt hard flow, TANDEM off","",0);
7095         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7096     } else if (flow == FLO_XONX) {      /* Xon/Xoff flow control */
7097         debug(F100,"ttvt TANDEM on","",0);
7098         tttvt.sg_flags |= TANDEM;       /* Ask for it. */
7099         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7100     } else if (flow == FLO_NONE) {
7101         debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
7102         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7103         tthflow(flow, 0, &tttvt);       /* Turn off any hardware f/c too */
7104         tttvt.sg_flags |= RAW;          /* Enter raw mode */
7105     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
7106         debug(F100,"ttvt keeping original TANDEM","",0);
7107         tttvt.sg_flags &= ~TANDEM;
7108         tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
7109         /* NOTE: We should also handle hardware flow control here! */
7110     }
7111     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
7112 #ifdef TOWER1
7113     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
7114 #else
7115     tttvt.sg_flags &= ~ECHO;            /* No echo */
7116 #endif /* TOWER1 */
7117
7118 #ifdef BELLV10
7119     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
7120       return(-1);
7121 #else
7122     if (stty(ttyfd,&tttvt) < 0)         /* Set the new modes */
7123       return(-1);
7124 #endif /* BELLV10 */
7125
7126 #else /* It is ATTSV or POSIX */
7127
7128     if (flow == FLO_XONX) {             /* Software flow control */
7129         tttvt.c_iflag |= (IXON|IXOFF);  /* On if requested. */
7130         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7131         debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
7132     } else if (flow == FLO_NONE) {      /* NONE */
7133         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
7134         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7135         debug(F100,"ttvt SVORPOSIX flow NONE","",0);
7136     } else if (flow == FLO_KEEP) {
7137         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
7138         tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
7139 #ifdef POSIX_CRTSCTS
7140         tttvt.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
7141         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
7142 #endif /* POSIX_CRTSCTS */
7143         debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
7144     } else if (flow == FLO_RTSC ||      /* Hardware flow control */
7145                flow == FLO_DTRC ||
7146                flow == FLO_DTRT) {
7147         tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
7148         tthflow(flow, 1, &tttvt);
7149         debug(F100,"ttvt SVORPOSIX flow HARD","",0);
7150     }
7151 #ifndef OXOS
7152 #ifdef COHERENT
7153     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7154 #else
7155     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
7156 #endif /* COHERENT */
7157 #ifdef QNX
7158     /* Needed for hwfc */
7159     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
7160       tttvt.c_lflag |= IEXTEN;
7161 #endif /* QNX */
7162 #else /* OXOS */
7163     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7164     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
7165 #endif /* OXOS */
7166
7167     tttvt.c_iflag |= (IGNBRK|IGNPAR);
7168
7169 /* Stop bits */
7170
7171 #ifdef CSTOPB
7172     if (xlocal) {
7173         if (stopbits == 2) {
7174             tttvt.c_cflag |= CSTOPB;    /* 2 stop bits */
7175             debug(F100,"ttvt 2 stopbits","",0);
7176         } else if (stopbits == 1) {
7177             tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
7178             debug(F100,"ttvt 1 stopbit","",0);
7179         }
7180     }
7181 #endif /* CSTOPB */
7182
7183 /* Parity */
7184
7185 #ifdef HWPARITY
7186     if (hwparity && xlocal) {           /* Hardware parity */
7187 #ifdef COMMENT
7188 /* Uncomment this only if needed -- I don't think it is */
7189         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
7190         ttraw.c_cflag |= CS8;           /* And set it to 8 */
7191 #endif /* COMMENT */
7192 #ifdef IGNPAR
7193         debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
7194         tttvt.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
7195 #endif /* IGNPAR */
7196         tttvt.c_cflag |= PARENB;        /* Enable parity */
7197
7198         switch (hwparity) {
7199           case 'e':                     /* Even */
7200             tttvt.c_cflag &= ~(PARODD);
7201             debug(F100,"ttvt 8 bits + even parity","",0);
7202             break;
7203           case 'o':                     /* Odd */
7204             tttvt.c_cflag |= PARODD;
7205             debug(F100,"ttvt 8 bits + odd parity","",0);
7206             break;
7207           case 'm':                     /* Mark */
7208           case 's':                     /* Space */
7209             /* PAREXT is mentioned in SVID but the details are not given. */
7210             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
7211             debug(F100,"ttvt 8 bits + invalid parity","",0);
7212             break;
7213         }
7214     } else {                            /* We handle parity ourselves */
7215 #endif /* HWPARITY */
7216         tttvt.c_cflag &= ~(PARENB);     /* Don't enable parity */
7217 #ifdef HWPARITY
7218     }
7219 #endif /* HWPARITY */
7220
7221 #ifdef ATTSV
7222 #ifdef BSD44
7223     /* Things not to do... */
7224     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
7225 #else
7226     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
7227 #endif /* BSD44 */
7228 #else /* POSIX */
7229     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
7230 #endif /* ATTSV */
7231     tttvt.c_cflag &= ~(CSIZE);          /* Zero out the char size field */
7232     tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
7233     tttvt.c_oflag &= ~OPOST;            /* Don't postprocess output */
7234 #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
7235     tttvt.c_cc[4] = 1;
7236 #else
7237 #ifndef OXOS
7238 #ifdef VMIN
7239     tttvt.c_cc[VMIN] = 1;
7240 #endif /* VMIN */
7241 #else /* OXOS */
7242     tttvt.c_min = 1;
7243 #endif /* OXOS */
7244 #endif /* VEOF */
7245 #ifndef VEOL    /* DGUX termio has VEOL at entry 5, see comment above */
7246     tttvt.c_cc[5] = 0;
7247 #else
7248 #ifndef OXOS
7249 #ifdef VTIME
7250     tttvt.c_cc[VTIME] = 0;
7251 #endif /* VTIME */
7252 #else /* OXOS */
7253     tttvt.c_time = 0;
7254 #endif /* OXOS */
7255 #endif /* VEOL */
7256
7257 #ifdef Plan9
7258     if (p9ttyparity('n') < 0)
7259       return -1;
7260 #else
7261 #ifdef BSD44ORPOSIX
7262     errno = 0;
7263 #ifdef BEOSORBEBOX
7264     tttvt.c_cc[VMIN] = 0;               /* DR7 can only poll. */
7265 #endif /* BEOSORBEBOX */
7266
7267     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
7268     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
7269     if (x < 0) {
7270         debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
7271         return(-1);
7272     }
7273 #else /* ATTSV */
7274     x = ioctl(ttyfd,TCSETAW,&tttvt);
7275     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
7276     if (x < 0) {                        /* set new modes . */
7277         debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
7278         return(-1);     
7279     }
7280 #endif /* BSD44ORPOSIX */
7281 #endif /* Plan9 */
7282 #endif /* ATTSV */
7283
7284     ttspeed = speed;                    /* Done, remember how we were */
7285     ttflow = flow;                      /* called, so we can decide how to */
7286     tvtflg = 1;                         /* respond next time. */
7287     debug(F100,"ttvt ok","",0);
7288     return(0);
7289
7290 #ifdef COHERENT
7291 #undef SVORPOSIX
7292 #endif /* COHERENT */
7293
7294 #endif /* NOLOCAL */
7295 }
7296
7297 #ifndef NOLOCAL
7298
7299 /* Serial speed department . . . */
7300
7301 /*
7302   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
7303   defined in the header files but they are supported (e.g. when building with
7304   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
7305   was the first release that came with high serial speeds standard, releases
7306   back to 5.0.0 could use them if certain patches (or "supplements") were
7307   applied to the SIO driver.  Plus a lot of SCO installations run third-party
7308   drivers.
7309 */
7310 #ifdef CK_SCOV5
7311 #ifndef B38400
7312 #define B38400  0000017
7313 #endif /* B38400 */
7314 #ifndef B57600
7315 #define B57600  0000021
7316 #endif /* B57600 */
7317 #ifndef B76800
7318 #define B76800  0000022
7319 #endif /* B76800 */
7320 #ifndef B115200
7321 #define B115200 0000023
7322 #endif /* B115200 */
7323 #ifndef B230400
7324 #define B230400 0000024
7325 #endif /* B230400 */
7326 #ifndef B460800
7327 #define B460800 0000025
7328 #endif /* B460800 */
7329 #ifndef B921600
7330 #define B921600 0000026
7331 #endif /* B921600 */
7332 #endif /* CK_SCOV5 */
7333 /*
7334   Plan 9's native speed setting interface lets you set anything you like,
7335   but will fail if the hardware doesn't like it, so we allow all the common
7336   speeds.
7337 */
7338 #ifdef Plan9
7339 #ifndef B50
7340 #define B50 50
7341 #endif /* B50 */
7342 #ifndef B75
7343 #define B75 75
7344 #endif /* B75 */
7345 #ifndef B110
7346 #define B110 110
7347 #endif /* B110 */
7348 #ifndef B134
7349 #define B134 134
7350 #endif /* B134 */
7351 #ifndef B200
7352 #define B200 200
7353 #endif /* B200 */
7354 #ifndef B300
7355 #define B300 300
7356 #endif /* B300 */
7357 #ifndef B1200
7358 #define B1200 1200
7359 #endif /* B1200 */
7360 #ifndef B1800
7361 #define B1800 1800
7362 #endif /* B1800 */
7363 #ifndef B2400
7364 #define B2400 2400
7365 #endif /* B2400 */
7366 #ifndef B4800
7367 #define B4800 4800
7368 #endif /* B4800 */
7369 #ifndef B9600
7370 #define B9600 9600
7371 #endif /* B9600 */
7372 #ifndef B14400
7373 #define B14400 14400
7374 #endif /* B14400 */
7375 #ifndef B19200
7376 #define B19200 19200
7377 #endif /* B19200 */
7378 #ifndef B28800
7379 #define B28800 28800
7380 #endif /* B28800 */
7381 #ifndef B38400
7382 #define B38400 38400
7383 #endif /* B38400 */
7384 #ifndef B57600
7385 #define B57600 57600
7386 #endif /* B57600 */
7387 #ifndef B76800
7388 #define B76800 76800
7389 #endif /* B76800 */
7390 #ifndef B115200
7391 #define B115200 115200
7392 #endif /* B115200 */
7393 #ifndef B230400
7394 #define B230400 230400
7395 #endif /* B230400 */
7396 #ifndef B460800
7397 #define B460800 460800
7398 #endif /* B460800 */
7399 #ifndef B921600
7400 #define B921600 921600
7401 #endif /* B921600 */
7402 #endif /* Plan9 */
7403
7404 /*  T T S S P D  --  Checks and sets transmission rate.  */
7405
7406 /*  Call with speed in characters (not bits!) per second. */
7407 /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
7408
7409 #ifdef USETCSETSPEED
7410 /*
7411   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
7412   to be used as a speed to be set, rather than forcing a choice from a
7413   predefined list.  It seems to be peculiar to UnixWare 7.
7414
7415   These are the function codes to be passed to tc[gs]etspeed(),
7416   but for some reason they don't seem to be picked up from termios.h.
7417 */
7418 #ifndef TCS_ALL
7419 #define TCS_ALL 0
7420 #endif /* TCS_ALL */
7421 #ifndef TCS_IN
7422 #define TCS_IN 1
7423 #endif /* TCS_IN */
7424 #ifndef TCS_OUT
7425 #define TCS_OUT 2
7426 #endif /* TCS_OUT */
7427 #endif /* USETCSETSPEED */
7428
7429 int
7430 ttsspd(cps) int cps; {
7431     int x;
7432 #ifdef POSIX
7433 /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
7434     speed_t
7435 #else
7436     int
7437 #endif /* POSIX */
7438       s, s2;
7439     int ok = 1;                         /* Speed check result, assume ok */
7440
7441 #ifdef OLINUXHISPEED
7442     unsigned int spd_flags = 0;
7443     struct serial_struct serinfo;
7444 #endif /* OLINUXHISPEED */
7445
7446     debug(F101,"ttsspd cps","",cps);
7447     debug(F101,"ttsspd ttyfd","",ttyfd);
7448     debug(F101,"ttsspd xlocal","",xlocal);
7449
7450     if (ttyfd < 0 || xlocal == 0)       /* Don't set speed on console */
7451       return(0);
7452
7453 #ifdef  NETCONN
7454     if (netconn) {
7455 #ifdef TN_COMPORT
7456         if (istncomport())
7457           return(tnc_set_baud(cps * 10));
7458         else
7459 #endif /* TN_COMPORT */
7460         return(0);
7461   }
7462 #endif  /* NETCONN */
7463 #ifdef NETCMD
7464     if (ttpipe) return(0);
7465 #endif /* NETCMD */
7466 #ifdef NETPTY
7467     if (ttpty) return(0);
7468 #endif /* NETPTY */
7469
7470     if (cps < 0) return(-1);
7471     s = s2 = 0;                         /* NB: s and s2 might be unsigned */
7472
7473 #ifdef USETCSETSPEED
7474
7475     s = cps * 10L;
7476
7477     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7478     debug(F101,"ttsspd tcgetattr","",x);
7479     if (x < 0)
7480       return(-1);
7481     debug(F101,"ttsspd TCSETSPEED speed","",s);
7482
7483     errno = 0;
7484     if (s == 8880L) {                   /* 75/1200 split speed requested */
7485         tcsetspeed(TCS_IN, &ttcur, 1200L);
7486         tcsetspeed(TCS_OUT, &ttcur, 75L);
7487     } else
7488       tcsetspeed(TCS_ALL, &ttcur, s);   /* Put new speed in structs */
7489 #ifdef DEBUG
7490     if (errno & deblog) {
7491         debug(F101,"ttsspd TCSETSPEED errno","",errno);
7492     }
7493 #endif /* DEBUG */
7494
7495 #ifdef COMMENT
7496     tcsetspeed(TCS_ALL, &ttraw, s);
7497     tcsetspeed(TCS_ALL, &tttvt, s);
7498     tcsetspeed(TCS_ALL, &ttold, s);
7499 #else
7500     if (s == 8880L) {                   /* 75/1200 split speed requested */
7501         tcsetspeed(TCS_IN, &ttraw, 1200L);
7502         tcsetspeed(TCS_OUT, &ttraw, 75L);
7503         tcsetspeed(TCS_IN, &tttvt, 1200L);
7504         tcsetspeed(TCS_OUT, &tttvt, 75L);
7505         tcsetspeed(TCS_IN, &ttold, 1200L);
7506         tcsetspeed(TCS_OUT, &ttold, 75L);
7507     } else {
7508         tcsetspeed(TCS_ALL, &ttraw, s);
7509         tcsetspeed(TCS_ALL, &tttvt, s);
7510         tcsetspeed(TCS_ALL, &ttold, s);
7511     }
7512 #endif /* COMMENT */
7513
7514     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
7515     debug(F101,"ttsspd tcsetattr","",x);
7516     if (x < 0)
7517       return(-1);
7518
7519 #else  /* Not USETCSETSPEED */
7520
7521     /* First check that the given speed is valid. */
7522
7523     switch (cps) {
7524 #ifndef MINIX
7525       case 0:   s = B0;    break;
7526       case 5:   s = B50;   break;
7527       case 7:   s = B75;   break;
7528 #endif /* MINIX */
7529       case 11:  s = B110;  break;
7530 #ifndef MINIX
7531       case 13:  s = B134;  break;
7532       case 15:  s = B150;  break;
7533       case 20:  s = B200;  break;
7534 #endif /* MINIX */
7535       case 30:  s = B300;  break;
7536 #ifndef MINIX
7537       case 60:  s = B600;  break;
7538 #endif /* MINIX */
7539       case 120: s = B1200; break;
7540 #ifndef MINIX
7541       case 180: s = B1800; break;
7542 #endif /* MINIX */
7543       case 240: s = B2400; break;
7544       case 480: s = B4800; break;
7545 #ifndef MINIX
7546       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
7547 #endif /* MINIX */
7548 #ifdef B7200
7549       case 720: s = B7200; break;
7550 #endif /* B7200 */
7551       case 960: s = B9600; break;
7552 #ifdef B14400
7553       case 1440: s = B14400; break;
7554 #endif /* B14400 */
7555 #ifdef B19200
7556       case 1920: s = B19200; break;
7557 #else
7558 #ifdef EXTA
7559       case 1920: s = EXTA; break;
7560 #endif /* EXTA */
7561 #endif /* B19200 */
7562 #ifdef B28800
7563       case 2880: s = B28800; break;
7564 #endif /* B28800 */
7565 #ifdef B38400
7566       case 3840: s = B38400;
7567 #ifdef OLINUXHISPEED
7568         spd_flags = ~ASYNC_SPD_MASK;    /* Nonzero, but zero flags */
7569 #endif /* OLINUXHISPEED */
7570         break;
7571 #else /* B38400 not defined... */
7572 #ifdef EXTB
7573       case 3840: s = EXTB; break;
7574 #endif /* EXTB */
7575 #endif /* B38400 */
7576
7577 #ifdef HPUX
7578 #ifdef _B57600
7579       case 5760: s = _B57600; break;
7580 #endif /* _B57600 */
7581 #ifdef _B115200
7582       case 11520: s = _B115200; break;
7583 #endif /* _B115200 */
7584 #else
7585 #ifdef OLINUXHISPEED
7586 /*
7587   This bit from <carlo@sg.tn.tudelft.nl>:
7588   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
7589   setting the speed to 38400 will set the custom speed (and ttgspd returns
7590   38400), but speeds 57600 and 115200 won't work any more because I didn't
7591   want to mess up the speed flags when someone is doing sophisticated stuff
7592   like custom speeds..."
7593 */
7594       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
7595       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
7596 #else
7597 #ifdef B57600
7598       case 5760: s = B57600; break;
7599 #endif /* B57600 */
7600 #ifdef B76800
7601       case 7680: s = B76800; break;
7602 #endif /* B76800 */
7603 #ifdef B115200
7604       case 11520: s = B115200; break;
7605 #endif /* B115200 */
7606 #endif /* OLINUXHISPEED */
7607 #ifdef B153600
7608       case 15360: s = B153600; break;
7609 #endif /* B153600 */
7610 #ifdef B230400
7611       case 23040: s = B230400; break;
7612 #endif /* B230400 */
7613 #ifdef B307200
7614       case 30720: s = B307200; break;
7615 #endif /* B307200 */
7616 #ifdef B460800
7617       case 46080: s = B460800; break;
7618 #endif /* 460800 */
7619 #ifdef B921600
7620       case 92160: s = B921600; break;
7621 #endif /* B921600 */
7622 #endif /* HPUX */
7623       default:
7624         ok = 0;                         /* Good speed not found, so not ok */
7625         break;
7626     }
7627     debug(F101,"ttsspd ok","",ok);
7628     debug(F101,"ttsspd s","",s);
7629
7630     if (!ok) {
7631         debug(F100,"ttsspd fails","",0);
7632         return(-1);
7633     } else {
7634         if (!s2) s2 = s;                /* Set input speed */
7635 #ifdef Plan9
7636         if (p9ttsspd(cps) < 0)
7637           return(-1);
7638 #else
7639 #ifdef BSD44ORPOSIX
7640         x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
7641         debug(F101,"ttsspd tcgetattr","",x);
7642         if (x < 0)
7643           return(-1);
7644 #ifdef OLINUXHISPEED
7645         debug(F101,"ttsspd spd_flags","",spd_flags);
7646         if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
7647             if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
7648                 debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
7649                 return(-1);
7650             } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
7651             serinfo.flags &= ~ASYNC_SPD_MASK;
7652             serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
7653             if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
7654               return(-1);
7655         }
7656 #endif /* OLINUXHISPEED */
7657         cfsetospeed(&ttcur,s);
7658         cfsetispeed(&ttcur,s2);
7659         cfsetospeed(&ttraw,s);
7660         cfsetispeed(&ttraw,s2);
7661         cfsetospeed(&tttvt,s);
7662         cfsetispeed(&tttvt,s2);
7663         cfsetospeed(&ttold,s);
7664         cfsetispeed(&ttold,s2);
7665         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
7666         debug(F101,"ttsspd tcsetattr","",x);
7667         if (x < 0) return(-1);
7668 #else
7669 #ifdef ATTSV
7670         if (cps == 888) return(-1);     /* No split speeds, sorry. */
7671         x = ioctl(ttyfd,TCGETA,&ttcur);
7672         debug(F101,"ttsspd TCGETA ioctl","",x);
7673         if (x < 0) return(-1);
7674         ttcur.c_cflag &= ~CBAUD;
7675         ttcur.c_cflag |= s;
7676         tttvt.c_cflag &= ~CBAUD;
7677         tttvt.c_cflag |= s;
7678         ttraw.c_cflag &= ~CBAUD;
7679         ttraw.c_cflag |= s;
7680         ttold.c_cflag &= ~CBAUD;
7681         ttold.c_cflag |= s;
7682         x = ioctl(ttyfd,TCSETAW,&ttcur);
7683         debug(F101,"ttsspd TCSETAW ioctl","",x);
7684         if (x < 0) return(-1);
7685 #else
7686 #ifdef BELLV10
7687         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7688         debug(F101,"ttsspd TIOCGDEV ioctl","",x);
7689         if (x < 0) return(-1);
7690         tdcur.ispeed = s2;
7691         tdcur.ospeed = s;
7692         errno = 0;
7693         ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
7694         debug(F101,"ttsspd BELLV10 ioctl","",ok);
7695         if (ok < 0) {
7696             perror(ttnmsv);
7697             debug(F101,"ttsspd BELLV10 errno","",ok);
7698             return(-1);
7699         }
7700 #else
7701         x = gtty(ttyfd,&ttcur);
7702         debug(F101,"ttsspd gtty","",x);
7703         if (x < 0) return(-1);
7704         ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
7705         tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
7706         ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
7707         ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
7708         x = stty(ttyfd,&ttcur);
7709         debug(F101,"ttsspd stty","",x);
7710         if (x < 0) return(-1);
7711 #endif /* BELLV10 */
7712 #endif /* ATTSV */
7713 #endif /* BSD44ORPOSIX */
7714 #endif /* Plan9 */
7715     }
7716     return(1);                          /* Return 1 = success. */
7717 #endif /* USETCSETSPEED */
7718 }
7719
7720 #endif /* NOLOCAL */
7721
7722 /* C O N G S P D  -  Get speed of console terminal  */
7723
7724 long
7725 congspd() {
7726 /*
7727   This is a disgusting hack.  The right way to do this would be to pass an
7728   argument to ttgspd(), but then we'd need to change the Kermit API and
7729   all of the ck?tio.c modules.  (Currently used only for rlogin.)
7730 */
7731     int t1;
7732     long spd;
7733 #ifdef NETCONN
7734     int t2 = netconn;
7735     netconn = 0;
7736 #endif /* NETCONN */
7737     t1 = ttyfd;
7738     ttyfd = -1;
7739     spd = ttgspd();
7740     debug(F101,"congspd","",spd);
7741 #ifdef NETCONN
7742     netconn = t2;
7743 #endif /* NETCONN */
7744     ttyfd = t1;
7745     return(spd);
7746 }
7747
7748 /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
7749
7750 #define NSPDLIST 64
7751 static long spdlist[NSPDLIST];
7752 /*
7753   As written, this picks up the speeds known at compile time, and thus
7754   apply to the system where C-Kermit was built, rather than to the one where
7755   it is running.  Suggestions for improvement are always welcome.
7756 */
7757 long *
7758 ttspdlist() {
7759     int i;
7760     for (i = 0; i < NSPDLIST; i++)      /* Initialize the list */
7761       spdlist[i] = -1L;
7762     i = 1;
7763
7764 #ifdef USETCSETSPEED                    /* No way to find out what's legal */
7765     debug(F100,"ttspdlist USETCSETSPEED","",0);
7766     spdlist[i++] = 50L;
7767 #ifndef UW7
7768     spdlist[i++] = 75L;
7769 #endif /* UW7 */
7770     spdlist[i++] = 110L;
7771 #ifndef UW7
7772     spdlist[i++] = 134L;
7773 #endif /* UW7 */
7774     spdlist[i++] = 150L;
7775     spdlist[i++] = 200L;
7776     spdlist[i++] = 300L;
7777     spdlist[i++] = 600L;
7778     spdlist[i++] = 1200L;
7779     spdlist[i++] = 1800L;
7780     spdlist[i++] = 2400L;
7781     spdlist[i++] = 4800L;
7782     spdlist[i++] = 8880L;
7783     spdlist[i++] = 9600L;
7784     spdlist[i++] = 14400L;
7785     spdlist[i++] = 19200L;
7786     spdlist[i++] = 28800L;
7787 #ifndef UW7
7788     spdlist[i++] = 33600L;
7789 #endif /* UW7 */
7790     spdlist[i++] = 38400L;
7791     spdlist[i++] = 57600L;
7792     spdlist[i++] = 76800L;
7793     spdlist[i++] = 115200L;
7794 #ifndef UW7
7795     spdlist[i++] = 153600L;
7796     spdlist[i++] = 230400L;
7797     spdlist[i++] = 307200L;
7798     spdlist[i++] = 460800L;
7799     spdlist[i++] = 921600L;
7800 #endif /* UW7 */
7801
7802 #else  /* USETCSETSPEED */
7803
7804     debug(F100,"ttspdlist no USETCSETSPEED","",0);
7805
7806 #ifdef B50
7807     debug(F101,"ttspdlist B50","",B50);
7808     spdlist[i++] = 50L;
7809 #endif /* B50 */
7810 #ifdef B75
7811     debug(F101,"ttspdlist B75","",B75);
7812     spdlist[i++] = 75L;
7813 #endif /* B75 */
7814 #ifdef B110
7815     debug(F101,"ttspdlist B110","",B110);
7816     spdlist[i++] = 110L;
7817 #endif /* B110 */
7818 #ifdef B134
7819     debug(F101,"ttspdlist B134","",B134);
7820     spdlist[i++] = 134L;
7821 #endif /* B134 */
7822 #ifdef B150
7823     debug(F101,"ttspdlist B150","",B150);
7824     spdlist[i++] = 150L;
7825 #endif /* B150 */
7826 #ifdef B200
7827     debug(F101,"ttspdlist B200","",B200);
7828     spdlist[i++] = 200L;
7829 #endif /* B200 */
7830 #ifdef B300
7831     debug(F101,"ttspdlist B300","",B300);
7832     spdlist[i++] = 300L;
7833 #endif /* B300 */
7834 #ifdef B600
7835     debug(F101,"ttspdlist B600","",B600);
7836     spdlist[i++] = 600L;
7837 #endif /* B600 */
7838 #ifdef B1200
7839     debug(F101,"ttspdlist B1200","",B1200);
7840     spdlist[i++] = 1200L;
7841 #endif /* B1200 */
7842 #ifdef B1800
7843     debug(F101,"ttspdlist B1800","",B1800);
7844     spdlist[i++] = 1800L;
7845 #endif /* B1800 */
7846 #ifdef B2400
7847     debug(F101,"ttspdlist B2400","",B2400);
7848     spdlist[i++] = 2400L;
7849 #endif /* B2400 */
7850 #ifdef B4800
7851     debug(F101,"ttspdlist B4800","",B4800);
7852     spdlist[i++] = 4800L;
7853 #endif /* B4800 */
7854 #ifdef B9600
7855     debug(F101,"ttspdlist B9600","",B9600);
7856     spdlist[i++] = 9600L;
7857 #endif /* B9600 */
7858 #ifdef B14400
7859     debug(F101,"ttspdlist B14400","",B14400);
7860     spdlist[i++] = 14400L;
7861 #endif /* B14400 */
7862 #ifdef B19200
7863     debug(F101,"ttspdlist B19200","",B19200);
7864     spdlist[i++] = 19200L;
7865 #else
7866 #ifdef EXTA
7867     debug(F101,"ttspdlist EXTA","",EXTA);
7868     spdlist[i++] = 19200L;
7869 #endif /* EXTA */
7870 #endif /* B19200 */
7871 #ifdef B28800
7872     debug(F101,"ttspdlist B28800","",B28800);
7873     spdlist[i++] = 28800L;
7874 #endif /* B28800 */
7875 #ifdef B33600
7876     debug(F101,"ttspdlist B33600","",B33600);
7877     spdlist[i++] = 33600L;
7878 #endif /* B33600 */
7879 #ifdef B38400
7880     debug(F101,"ttspdlist B38400","",B38400);
7881     spdlist[i++] = 38400L;
7882 #else
7883 #ifdef EXTB
7884     debug(F101,"ttspdlist EXTB","",EXTB);
7885     spdlist[i++] = 38400L;
7886 #endif /* EXTB */
7887 #endif /* B38400 */
7888 #ifdef _B57600
7889     debug(F101,"ttspdlist _B57600","",_B57600);
7890     spdlist[i++] = 57600L;
7891 #else
7892 #ifdef B57600
7893     debug(F101,"ttspdlist B57600","",B57600);
7894     spdlist[i++] = 57600L;
7895 #endif /* B57600 */
7896 #endif /* _B57600 */
7897 #ifdef B76800
7898     debug(F101,"ttspdlist B76800","",B76800);
7899     spdlist[i++] = 76800L;
7900 #endif /* B76800 */
7901 #ifdef _B115200
7902     debug(F101,"ttspdlist _B115200","",_B115200);
7903     spdlist[i++] = 115200L;
7904 #else
7905 #ifdef B115200
7906     debug(F101,"ttspdlist B115200","",B115200);
7907     spdlist[i++] = 115200L;
7908 #endif /* B115200 */
7909 #endif /* _B115200 */
7910 #ifdef B153600
7911     debug(F101,"ttspdlist B153600","",B153600);
7912     spdlist[i++] = 153600L;
7913 #endif /* B153600 */
7914 #ifdef B230400
7915     debug(F101,"ttspdlist B230400","",B230400);
7916     spdlist[i++] = 230400L;
7917 #endif /* B230400 */
7918 #ifdef B307200
7919     debug(F101,"ttspdlist B307200","",B307200);
7920     spdlist[i++] = 307200L;
7921 #endif /* B307200 */
7922 #ifdef B460800
7923     debug(F101,"ttspdlist B460800","",B460800);
7924     spdlist[i++] = 460800L;
7925 #endif /* B460800 */
7926 #ifdef B921600
7927     debug(F101,"ttspdlist B921600","",B921600);
7928     spdlist[i++] = 921600L;
7929 #endif /* B921600 */
7930 #endif /* USETCSETSPEED */
7931     spdlist[0] = i - 1;                 /* Return count in 0th element */
7932     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
7933     return((long *)spdlist);
7934 }
7935
7936 /* T T G S P D  -  Get speed of currently selected tty line  */
7937
7938 /*
7939   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
7940   the real speed.  On some systems, it returns the line's nominal speed, from
7941   /etc/ttytab.  Even if you SET SPEED to something else, this function might
7942   not notice.
7943 */
7944 long
7945 ttgspd() {                              /* Get current serial device speed */
7946 #ifdef NOLOCAL
7947     return(-1L);
7948 #else
7949 #ifdef POSIX
7950     speed_t                             /* Should be unsigned */
7951 #else
7952     int                                 /* Isn't unsigned */
7953 #endif /* POSIX */
7954       s;
7955     int x;
7956     long ss;
7957 #ifdef OLINUXHISPEED
7958     unsigned int spd_flags = 0;
7959     struct serial_struct serinfo;
7960 #endif /* OLINUXHISPEED */
7961
7962 #ifdef NETCONN
7963     if (netconn) {
7964 #ifdef TN_COMPORT
7965         if (istncomport())
7966           return(tnc_get_baud());
7967         else
7968 #endif /* TN_COMPORT */
7969           return(-1);                   /* -1 if network connection */
7970     }
7971 #endif /* NETCONN */
7972 #ifdef NETCMD
7973     if (ttpipe) return(-1);
7974 #endif /* NETCMD */
7975 #ifdef NETPTY
7976     if (ttpty) return(-1);
7977 #endif /* NETPTY */
7978
7979     debug(F101,"ttgspd ttyfd","",ttyfd);
7980
7981 #ifdef USETCSETSPEED
7982
7983     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7984     debug(F101,"ttgspd tcgetattr","",x);
7985     if (x < 0)
7986       return(-1);
7987     errno = 0;
7988     s = tcgetspeed(TCS_ALL, &ttcur);
7989     debug(F101,"ttsspd TCGETSPEED speed","",s);
7990     if (s == 0) {
7991         long s1, s2;
7992         s1 = tcgetspeed(TCS_IN, &ttcur);
7993         s2 = tcgetspeed(TCS_OUT, &ttcur);
7994         if (s1 == 1200L && s2 == 75L)
7995           return(8880L);
7996     }
7997 #ifdef DEBUG
7998     if (errno & deblog) {
7999         debug(F101,"ttsspd TCGETSPEED errno","",errno);
8000     }
8001 #endif /* DEBUG */
8002     return(s);
8003
8004 #else  /* Not USETCSETSPEED */
8005
8006 #ifdef Plan9
8007     if (ttyfd < 0)
8008       ss = -1;
8009     else
8010       ss = ttylastspeed;
8011 #else
8012 #ifdef OLINUXHISPEED
8013     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
8014 #endif /* OLINUXHISPEED */
8015
8016     if (ttyfd < 0) {
8017 #ifdef BSD44ORPOSIX
8018         s = cfgetospeed(&ccold);
8019         debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
8020 #else
8021 #ifdef ATTSV
8022         s = ccold.c_cflag & CBAUD;
8023         debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
8024 #else
8025         s = ccold.sg_ospeed;            /* (obtained by congm()) */
8026         debug(F101,"ttgspd sg_ospeed 1","",s);
8027 #endif /* ATTSV */
8028 #endif /* BSD44POSIX */
8029
8030     } else {
8031 #ifdef BSD44ORPOSIX
8032         if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
8033         s = cfgetospeed(&ttcur);
8034         debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
8035 #ifdef OLINUXHISPEED
8036         if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
8037           spd_flags = serinfo.flags & ASYNC_SPD_MASK;
8038         debug(F101,"ttgspd spd_flags","",spd_flags);
8039 #endif /* OLINUXHISPEED */
8040 #else
8041 #ifdef ATTSV
8042         x = ioctl(ttyfd,TCGETA,&ttcur);
8043         debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
8044         debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
8045         if (x < 0) return(-1);
8046         s = ttcur.c_cflag & CBAUD;
8047         debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
8048 #else
8049 #ifdef BELLV10
8050         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
8051         debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
8052         if (x < 0) return(-1);
8053         s = tdcur.ospeed;
8054         debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
8055 #else
8056         x = gtty(ttyfd,&ttcur);
8057         debug(F101,"ttgspd gtty 2 x","",x);
8058         debug(F101,"ttgspd gtty 2 errno","",errno);
8059         if (x < 0) return(-1);
8060         s = ttcur.sg_ospeed;
8061         debug(F101,"ttgspd gtty 2 speed","",s);
8062 #endif /* BELLV10 */
8063 #endif /* ATTSV */
8064 #endif /* BSD44ORPOSIX */
8065     }
8066     debug(F101,"ttgspd code","",s);
8067 #ifdef OLINUXHISPEED
8068     debug(F101,"ttgspd spd_flags","",spd_flags);
8069 #endif /* OLINUXHISPEED */
8070     switch (s) {
8071 #ifdef B0
8072       case B0:    ss = 0L; break;
8073 #endif /* B0 */
8074
8075 #ifndef MINIX
8076 /*
8077  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
8078  etc, making for many "duplicate case in switch" errors, which are fatal.
8079 */
8080 #ifdef B50
8081       case B50:   ss = 50L; break;
8082 #endif /* B50 */
8083 #ifdef B75
8084       case B75:   ss = 75L; break;
8085 #endif /* B75 */
8086 #endif /* MINIX */
8087
8088 #ifdef B110
8089       case B110:  ss = 110L; break;
8090 #endif /* B110 */
8091
8092 #ifndef MINIX
8093 #ifdef B134
8094       case B134:  ss = 134L; break;
8095 #endif /* B134 */
8096 #ifdef B150
8097       case B150:  ss = 150L; break;
8098 #endif /* B150 */
8099 #endif /* MINIX */
8100
8101 #ifdef B200
8102       case B200:  ss = 200L; break;
8103 #endif /* B200 */
8104
8105 #ifdef B300
8106       case B300:  ss = 300L; break;
8107 #endif /* B300 */
8108
8109 #ifdef B600
8110       case B600:  ss = 600L; break;
8111 #endif /* B600 */
8112
8113 #ifdef B1200
8114       case B1200: ss = 1200L; break;
8115 #endif /* B1200 */
8116
8117 #ifdef B1800
8118       case B1800: ss = 1800L; break;
8119 #endif /* B1800 */
8120
8121 #ifdef B2400
8122       case B2400: ss = 2400L; break;
8123 #endif /* B2400 */
8124
8125 #ifdef B4800
8126       case B4800: ss = 4800L; break;
8127 #endif /* B4800 */
8128
8129 #ifdef B7200
8130       case B7200: ss = 7200L; break;
8131 #endif /* B7200 */
8132
8133 #ifdef B9600
8134       case B9600: ss = 9600L; break;
8135 #endif /* B9600 */
8136
8137 #ifdef B19200
8138       case B19200: ss = 19200L; break;
8139 #else
8140 #ifdef EXTA
8141       case EXTA: ss = 19200L; break;
8142 #endif /* EXTA */
8143 #endif /* B19200 */
8144
8145 #ifndef MINIX
8146 #ifdef B38400
8147       case B38400:
8148         ss = 38400L;
8149 #ifdef OLINUXHISPEED
8150         switch(spd_flags) {
8151           case ASYNC_SPD_HI:  ss =  57600L; break;
8152           case ASYNC_SPD_VHI: ss = 115200L; break;
8153         }
8154 #endif /* OLINUXHISPEED */
8155         break;
8156 #else
8157 #ifdef EXTB
8158       case EXTB: ss = 38400L; break;
8159 #endif /* EXTB */
8160 #endif /* B38400 */
8161 #endif /* MINIX */
8162
8163 #ifdef HPUX
8164 #ifdef _B57600
8165       case _B57600: ss = 57600L; break;
8166 #endif /* _B57600 */
8167 #ifdef _B115200
8168       case _B115200: ss = 115200L; break;
8169 #endif /* _B115200 */
8170 #else
8171 #ifdef B57600
8172       case B57600: ss = 57600L; break;
8173 #endif /* B57600 */
8174 #ifdef B76800
8175       case B76800: ss = 76800L; break;
8176 #endif /* B76800 */
8177 #ifdef B115200
8178       case B115200: ss = 115200L; break;
8179 #endif /* B115200 */
8180 #ifdef B153600
8181       case B153600: ss = 153600L; break;
8182 #endif /* B153600 */
8183 #ifdef B230400
8184       case B230400: ss = 230400L; break;
8185 #endif /* B230400 */
8186 #ifdef B307200
8187       case B307200: ss = 307200L; break;
8188 #endif /* B307200 */
8189 #ifdef B460800
8190       case B460800: ss = 460800L; break;
8191 #endif /* B460800 */
8192 #endif /* HPUX */
8193 #ifdef B921600
8194       case B921600: ss = 921600L; break;
8195 #endif /* B921600 */
8196       default:
8197         ss = -1; break;
8198     }
8199 #endif /* Plan9 */
8200     debug(F101,"ttgspd speed","",ss);
8201     return(ss);
8202
8203 #endif /* USETCSETSPEED */
8204 #endif /* NOLOCAL */
8205 }
8206 #ifdef MINIX2                           /* Another hack alert */
8207 #define MINIX
8208 #endif /* MINIX2 */
8209
8210 /*
8211   FIONREAD data type...  This has been defined as "long" for many, many
8212   years, and it worked OK until 64-bit platforms appeared.  Thus we use
8213   int for 64-bit platforms, but keep long for the others.  If we changed
8214   the default PEEKTYPE to int, this would probably break 16-bit builds
8215   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
8216   of which we have no way of testing any more.  Therefore, do not change
8217   the default definition of PEEKTYPE -- only add exceptions to it as needed.
8218 */
8219 #ifdef COHERENT
8220 #ifdef FIONREAD
8221 #undef FIONREAD
8222 #endif /* FIONREAD */
8223 /* #define FIONREAD TIOCQUERY */
8224 /* #define PEEKTYPE int */
8225 #else  /* Not COHERENT... */
8226
8227 #ifdef OSF32                            /* Digital UNIX 3.2 or higher */
8228 #define PEEKTYPE int
8229 #else
8230 #define PEEKTYPE long                   /* Elsewhere (see notes above) */
8231 #endif /* OSF32 */
8232 #endif /* COHERENT */
8233
8234 /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
8235
8236 #ifdef MYREAD
8237
8238 /* Private buffer for myread() and its companions.  Not for use by anything
8239  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
8240  * allowed to read my_count.
8241  *
8242  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
8243  *
8244  * A global parity mask variable could be useful too.  We could use it to
8245  * let myread() strip the parity on its own, instead of stripping sign
8246  * bits as it does now.
8247  */
8248 #ifdef BIGBUFOK
8249 #define MYBUFLEN 32768
8250 #else
8251 #ifdef pdp11
8252 #define MYBUFLEN 256
8253 #else
8254 #define MYBUFLEN 1024
8255 #endif /* pdp11 */
8256 #endif /* BIGBUFOK */
8257
8258 #ifdef ANYX25
8259 #undef MYBUFLEN
8260 #define MYBUFLEN 256
8261 /*
8262   On X.25 connections, there is an extra control byte at the beginning.
8263 */
8264 static CHAR x25buf[MYBUFLEN+1];         /* Communication device input buffer */
8265 static CHAR  *mybuf = x25buf+1;
8266 #else
8267 static CHAR mybuf[MYBUFLEN];
8268 #endif /* ANYX25 */
8269
8270 static int my_count = 0;                /* Number of chars still in mybuf */
8271 static int my_item = -1;                /* Last index read from mybuf[]   */
8272
8273 /*  T T P E E K  --  Peek into our internal communications input buffers. */
8274
8275 /*
8276   NOTE: This routine is peculiar to UNIX, and is used only by the
8277   select()-based CONNECT module, ckucns.c.  It need not be replicated in
8278   the ck?tio.c of other platforms.
8279 */
8280 int
8281 ttpeek() {
8282 #ifdef TTLEBUF
8283     int rc = 0;
8284     if (ttpush >= 0)
8285       rc++;
8286     rc += le_inbuf();
8287     if (rc > 0)
8288       return(rc);
8289     else
8290 #endif /* TTLEBUF */
8291
8292 #ifdef MYREAD
8293     return(my_count);
8294 #else
8295     return(0);
8296 #endif /* MYREAD */
8297 }
8298
8299 /* myread() -- Efficient read of one character from communications line.
8300  *
8301  * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
8302  * bytes from connection, so when the connection is encrypted, these bytes
8303  * must be decrypted.
8304  *
8305  * Uses a private buffer to minimize the number of expensive read() system
8306  * calls.  Essentially performs the equivalent of read() of 1 character, which
8307  * is then returned.  By reading all available input from the system buffers
8308  * to the private buffer in one chunk, and then working from this buffer, the
8309  * number of system calls is reduced in any case where more than one character
8310  * arrives during the processing of the previous chunk, for instance high
8311  * baud rates or network type connections where input arrives in packets.
8312  * If the time needed for a read() system call approaches the time for more
8313  * than one character to arrive, then this mechanism automatically compensates
8314  * for that by performing bigger read()s less frequently.  If the system load
8315  * is high, the same mechanism compensates for that too.
8316  *
8317  * myread() is a macro that returns the next character from the buffer.  If the
8318  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
8319  * returns.
8320  *
8321  * This should be efficient enough for any one-character-at-a-time loops.
8322  * For even better efficiency you might use memcpy()/bcopy() or such between
8323  * buffers (since they are often better optimized for copying), but it may not
8324  * be worth it if you have to take an extra pass over the buffer to strip
8325  * parity and check for CTRL-C anyway.
8326  *
8327  * Note that if you have been using myread() from another program module, you
8328  * may have some trouble accessing this macro version and the private variables
8329  * it uses.  In that case, just add a function in this module, that invokes the
8330  * macro.
8331  */
8332 #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
8333
8334 /* Specification: Push back up to one character onto myread()'s queue.
8335  *
8336  * This implementation: Push back characters into mybuf. At least one character
8337  * must have been read through myread() before myunrd() may be used.  After
8338  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
8339  * one character can be pushed back, but only one character is guaranteed.
8340  * Since a previous myread() must have read its character out of mybuf[],
8341  * that guarantees that there is space for at least one character.  If push
8342  * back was really needed after EOF, a small addition could provide that.
8343  *
8344  * As of 02/2007 myunrd() is used by ttinl().
8345  */
8346 VOID
8347 #ifdef CK_ANSIC
8348 myunrd(CHAR ch)
8349 #else
8350 myunrd(ch) CHAR ch;
8351 #endif  /* CK_ANSIC */
8352 {
8353     if (my_item >= 0) {
8354         mybuf[my_item--] = ch;
8355         ++my_count;
8356     }
8357 }
8358
8359 /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
8360
8361 static CHAR * pushbuf = NULL;
8362 /* static int pushed = 0; */
8363
8364 int
8365 ttpushback(s,n) CHAR * s; int n; {
8366     debug(F101,"ttpushback n","",n);
8367     if (pushbuf || n > MYBUFLEN || n < 1)
8368       return(-1);
8369     debug(F101,"ttpushback my_count","",my_count);
8370     if (my_count > 0) {
8371         if (!(pushbuf = (CHAR *)malloc(n+1)))
8372           return(-1);
8373         memcpy(pushbuf,mybuf,my_count);
8374         /* pushed = my_count; */ /* (set but never used) */
8375     }
8376     memcpy(mybuf,s,n);
8377     my_count = n;
8378     my_item = -1;
8379     return(0);
8380 }
8381
8382 /* mygetbuf() -- Fill buffer for myread() and return first character.
8383  *
8384  * This function is what myread() uses when it can't get the next character
8385  * directly from its buffer.  First, it calls a system dependent myfillbuf()
8386  * to read at least one new character into the buffer, and then it returns
8387  * the first character just as myread() would have done.  This function also
8388  * is responsible for all error conditions that myread() can indicate.
8389  *
8390  * Returns: When OK     => a positive character, 0 or greater.
8391  *          When EOF    => -2.
8392  *          When error  => -3, error code in errno.
8393  *
8394  * Older myread()s additionally returned -1 to indicate that there was nothing
8395  * to read, upon which the caller would call myread() again until it got
8396  * something.  The new myread()/mygetbuf() always gets something.  If it
8397  * doesn't, then make it do so!  Any program that actually depends on the old
8398  * behaviour will break.
8399  *
8400  * The older version also used to return -2 both for EOF and other errors,
8401  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
8402  * other errors now return different results, although Kermit currently never
8403  * checks to see which it was.  It just disconnects in both cases.
8404  *
8405  * Kermit lets the user use the quit key to perform some special commands
8406  * during file transfer.  This causes read(), and thus also mygetbuf(), to
8407  * finish without reading anything and return the EINTR error.  This should
8408  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
8409  * but if there is nothing to read, this could delay Kermit's reaction to
8410  * the command, and make Kermit appear unresponsive.
8411  *
8412  * The debug() call should be removed for optimum performance.
8413  */
8414 int
8415 mygetbuf() {
8416     int x;
8417     errno = 0;
8418 #ifdef DEBUG
8419     if (deblog && my_count > 0)
8420       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
8421 #endif /* DEBUG */
8422     if (my_count <= 0)
8423       my_count = myfillbuf();
8424
8425 #ifdef DEBUG
8426 #ifdef COMMENT
8427     if (deblog) debug(F101, "mygetbuf read", "", my_count);
8428 #else /* COMMENT */
8429     ckhexdump("mygetbuf read", mybuf, my_count);
8430 #endif /* COMMENT */
8431 #endif /* DEBUG */
8432     x = my_count;
8433     if (my_count <= 0) {
8434         my_count = 0;
8435         my_item = -1;
8436         debug(F101,"mygetbuf errno","",errno);
8437 #ifdef TCPSOCKET
8438         if (netconn && ttnet == NET_TCPB && errno != 0) {
8439             if (errno != EINTR) {
8440                 debug(F101,"mygetbuf TCP error","",errno);
8441                 ttclos(0);              /* Close the connection. */
8442             }
8443             return(-3);
8444         }
8445 #endif /* TCPSOCKET */
8446         if (!netconn && xlocal && errno) {
8447             if (errno != EINTR) {
8448                 debug(F101,"mygetbuf SERIAL error","",errno);
8449                 x = -3;
8450                 ttclos(0);              /* Close the connection. */
8451             }
8452         }
8453         return((x < 0) ? -3 : -2);
8454     }
8455     --my_count;
8456     return((unsigned)(0xff & mybuf[my_item = 0]));
8457 }
8458
8459 /* myfillbuf():
8460  * System-dependent read() into mybuf[], as many characters as possible.
8461  *
8462  * Returns: OK => number of characters read, always more than zero.
8463  *          EOF => 0
8464  *          Error => -1, error code in errno.
8465  *
8466  * If there is input available in the system's buffers, all of it should be
8467  * read into mybuf[] and the function return immediately.  If no input is
8468  * available, it should wait for a character to arrive, and return with that
8469  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
8470  * character, but be aware that any such delay lengthens the packet turnaround
8471  * time during kermit file transfers.  Should never return with zero characters
8472  * unless EOF or irrecoverable read error.
8473  *
8474  * Correct functioning depends on the correct tty parameters being used.
8475  * Better control of current parameters is required than may have been the
8476  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
8477  * no longer be sometimes off and sometimes on like it used to, unless a
8478  * special myfillbuf() is written to handle that.  Otherwise the ordinary
8479  * myfillbuf()s may think they have come to EOF.
8480  *
8481  * If your system has a facility to directly perform the functioning of
8482  * myfillbuf(), then use it.  If the system can tell you how many characters
8483  * are available in its buffers, then read that amount (but not less than 1).
8484  * If the system can return a special indication when you try to read without
8485  * anything to read, while allowing you to read all there is when there is
8486  * something, you may loop until there is something to read, but probably that
8487  * is not good for the system load.
8488  */
8489
8490 #ifdef SVORPOSIX
8491         /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
8492          * and CLOCAL set any way you like.  This way, read() will do exactly
8493          * what is required by myfillbuf(): If there is data in the buffers
8494          * of the O.S., all available data is read into mybuf, up to the size
8495          * of mybuf.  If there is none, the first character to arrive is
8496          * awaited and returned.
8497          */
8498 int
8499 myfillbuf() {
8500     int fd, n;
8501 #ifdef NETCMD
8502     if (ttpipe)
8503       fd = fdin;
8504     else
8505 #endif /* NETCMD */
8506       fd = ttyfd;
8507
8508 #ifdef sxaE50
8509     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
8510     /* necessary for the sxa E50, but it is. */
8511     return read(fd, mybuf, 255);
8512 #else
8513 #ifdef BEOSORBEBOX
8514     while (1) {
8515 #ifdef NETCONN
8516         if (netconn) {
8517             n = netxin(sizeof(mybuf), (char *)mybuf);
8518             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
8519         }
8520         else
8521 #endif /* NETCONN */
8522           n = read(fd, mybuf, sizeof(mybuf));
8523         debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
8524         if (n > 0)
8525           return(n);
8526         snooze(1000.0);
8527     }
8528 #else /* BEOSORBEBOX */
8529     errno = 0;
8530     /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
8531 #ifdef IBMX25
8532     if (netconn && (nettype == NET_IX25)) {
8533         /* can't use sizeof because mybuf is a pointer, and not an array! */
8534         n = x25xin( MYBUFLEN, mybuf );
8535     } else
8536 #endif /* IBMX25 */
8537
8538 #ifdef CK_SSL
8539       if (ssl_active_flag || tls_active_flag) {
8540           int error, n = 0;
8541           debug(F100,"myfillbuf calling SSL_read() fd","",0);
8542           while (n == 0) {
8543               if (ssl_active_flag)
8544                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8545               else if (tls_active_flag)
8546                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8547               else
8548                 break;
8549               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8550                 case SSL_ERROR_NONE:
8551                   if (n > 0)
8552                     return(n);
8553                   if (n < 0)
8554                     return(-2);
8555                   msleep(50);
8556                   break;
8557                 case SSL_ERROR_WANT_WRITE:
8558                 case SSL_ERROR_WANT_READ:
8559                   return(-1);
8560                 case SSL_ERROR_SYSCALL:
8561                   if (n != 0)
8562                     return(-1);
8563                 case SSL_ERROR_WANT_X509_LOOKUP:
8564                 case SSL_ERROR_SSL:
8565                 case SSL_ERROR_ZERO_RETURN:
8566                 default:
8567                   ttclos(0);
8568                   return(-3);
8569             }
8570         }
8571     }
8572 #endif /* CK_SSL */
8573 #ifdef CK_KERBEROS
8574 #ifdef KRB4
8575 #ifdef RLOGCODE
8576     if (ttnproto == NP_EK4LOGIN) {
8577         debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
8578         if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8579           return(-3);
8580         else
8581           return(n);
8582     }
8583 #endif /* RLOGCODE */
8584 #endif /* KRB4 */
8585 #ifdef KRB5
8586 #ifdef RLOGCODE
8587     if (ttnproto == NP_EK5LOGIN) {
8588         debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
8589         if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
8590           return(-3);
8591         else
8592           return(n);
8593     }
8594 #endif /* RLOGCODE */
8595 #ifdef KRB5_U2U
8596     if (ttnproto == NP_K5U2U) {
8597         debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
8598         if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8599           return(-3);
8600         else
8601           return(n);
8602     }
8603 #endif /* KRB5_U2U */
8604 #endif /* KRB5 */
8605 #endif /* CK_KERBEROS */
8606
8607 #ifdef NETPTY
8608 #ifdef HAVE_PTYTRAP
8609     /* Special handling for HP-UX pty i/o */
8610   ptyread:
8611     if (ttpty && pty_trap_pending(ttyfd) > 0) {
8612         debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
8613         if (pty_trap_handler(ttyfd) > 0) {
8614             ttclos(0);
8615             return(-3);
8616         }
8617     }
8618 #endif /* HAVE_PTYTRAP */
8619 #endif /* NETPTY */
8620     debug(F101,"myfillbuf calling read() fd","",ttyfd);
8621     n = read(fd, mybuf, sizeof(mybuf));
8622     debug(F101,"SVORPOSIX myfillbuf read","",n);
8623     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
8624     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
8625     if (n < 1) {
8626 #ifdef NETPTY
8627 #ifdef HAVE_PTYTRAP
8628         /* When we have a PTY trap in place the connection cannot */
8629         /* be closed until the trap receives a close indication.  */
8630         if (n == 0 && ttpty)
8631             goto ptyread;
8632 #endif /* HAVE_PTYTRAP */
8633 #endif /* NETPTY */
8634         return(-3);
8635     }
8636     return(n);
8637 #endif /* BEOSORBEBOX */
8638 #endif /* sxaE50 */
8639 }
8640
8641 #else /* not AT&T or POSIX */
8642
8643 #ifdef aegis
8644         /* This is quoted from the old myread().  The semantics seem to be
8645          * alright, but maybe errno would not need to be set even when
8646          * there is no error?  I don't know aegis.
8647          */
8648 int
8649 myfillbuf() {
8650     int count;
8651 #ifdef NETCMD
8652     if (ttpipe)
8653       fd = fdin;
8654     else
8655 #endif /* NETCMD */
8656       fd = ttyfd;
8657
8658     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
8659     errno = EIO;
8660     if (st.all == ios_$get_conditional_failed) /* get at least one */
8661       count = ios_$get((short)fd, 0, mybuf, 1L, st);
8662     if (st.all == ios_$end_of_file)
8663       return(-3);
8664     else if (st.all != status_$ok) {
8665         errno = EIO;
8666         return(-1);
8667     }
8668     return(count > 0 ? count : -3);
8669 }
8670 #else /* !aegis */
8671
8672 #ifdef FIONREAD
8673         /* This is for systems with FIONREAD.  FIONREAD returns the number
8674          * of characters available for reading. If none are available, wait
8675          * until something arrives, otherwise return all there is.
8676          */
8677 int
8678 myfillbuf() {
8679     PEEKTYPE avail = 0;
8680     int x, fd;
8681 #ifdef NETCMD
8682     if (ttpipe)
8683       fd = fdin;
8684     else
8685 #endif /* NETCMD */
8686       fd = ttyfd;
8687
8688 #ifdef SUNX25
8689 /*
8690   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
8691   Depends on SunOS having FIONREAD, not because we use it, but just so this
8692   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
8693
8694   We call x25xin() instead of read() so that Q-Bit packets, which contain
8695   X.25 service-level information (e.g. PAD parameter changes), can be processed
8696   transparently to the upper-level code.  This is a blocking read, and so
8697   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
8698 */
8699     extern int nettype;
8700     if (netconn && nettype == NET_SX25) {
8701         while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
8702         return(x - 1);          /* "-1" compensates for extra status byte */
8703     }
8704 #endif /* SUNX25 */
8705
8706 #ifdef CK_SSL
8707     if (ssl_active_flag || tls_active_flag) {
8708         int error, n = 0;
8709         while (n == 0) {
8710             if (ssl_active_flag)
8711               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8712             else
8713               n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8714             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8715               case SSL_ERROR_NONE:
8716                 if (n > 0)
8717                   return(n);
8718                 if (n < 0)
8719                   return(-2);
8720                 msleep(50);
8721                 break;
8722               case SSL_ERROR_WANT_WRITE:
8723               case SSL_ERROR_WANT_READ:
8724                 return(-1);
8725               case SSL_ERROR_SYSCALL:
8726                 if (n != 0)
8727                   return(-1);
8728               case SSL_ERROR_WANT_X509_LOOKUP:
8729               case SSL_ERROR_SSL:
8730               case SSL_ERROR_ZERO_RETURN:
8731               default:
8732                 ttclos(0);
8733                 return(-2);
8734             }
8735         }
8736     }
8737 #endif /* CK_SSL */
8738 #ifdef CK_KERBEROS
8739 #ifdef KRB4
8740 #ifdef RLOGCODE
8741     if (ttnproto == NP_EK4LOGIN) {
8742         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8743           return(-1);
8744         else
8745           return(x);
8746     }
8747 #endif /* RLOGCODE */
8748 #endif /* KRB4 */
8749 #ifdef KRB5
8750 #ifdef RLOGCODE
8751     if (ttnproto == NP_EK5LOGIN) {
8752         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8753           return(-1);
8754         else
8755           return(x);
8756     }
8757 #endif /* RLOGCODE */
8758 #ifdef KRB5_U2U
8759     if (ttnproto == NP_K5U2U) {
8760         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8761           return(-1);
8762         else
8763           return(x);
8764     }
8765 #endif /* KRB5_U2U */
8766 #endif /* KRB5 */
8767 #endif /* CK_KERBEROS */
8768
8769     errno = 0;
8770     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
8771     x = ioctl(fd, FIONREAD, &avail);
8772 #ifdef DEBUG
8773     if (deblog) {
8774         debug(F101,"myfillbuf FIONREAD","",x);
8775         debug(F101,"myfillbuf FIONREAD avail","",avail);
8776         debug(F101,"myfillbuf FIONREAD errno","",errno);
8777     }
8778 #endif /* DEBUG */
8779     if (x < 0 || avail == 0)
8780       avail = 1;
8781
8782     if (avail > MYBUFLEN)
8783       avail = MYBUFLEN;
8784
8785     errno = 0;
8786
8787     x = read(fd, mybuf, (int) avail);
8788 #ifdef DEBUG
8789     if (deblog) {
8790         debug(F101,"myfillbuf avail","",avail);
8791         debug(F101,"myfillbuf read","",x);
8792         debug(F101,"myfillbuf read errno","",errno);
8793         if (x > 0)
8794           ckhexdump("myfillbuf mybuf",mybuf,x);
8795     }
8796 #endif /* DEBUG */
8797     if (x < 1) x = -3;                  /* read 0 == connection loss */
8798     return(x);
8799 }
8800
8801 #else /* !FIONREAD */
8802 /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
8803 /* When there is no other possibility, read 1 character at a time. */
8804 int
8805 myfillbuf() {
8806     int x;
8807
8808 #ifdef CK_SSL
8809     if (ssl_active_flag || tls_active_flag) {
8810         int error, n = 0;
8811         while (n == 0) {
8812             if (ssl_active_flag)
8813               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8814             else
8815               count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8816             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8817               case SSL_ERROR_NONE:
8818                 if (n > 0)
8819                   return(n);
8820                 if (n < 0)
8821                   return(-2);
8822                 msleep(50);
8823                 break;
8824               case SSL_ERROR_WANT_WRITE:
8825               case SSL_ERROR_WANT_READ:
8826                 return(-1);
8827               case SSL_ERROR_SYSCALL:
8828                 if (n != 0)
8829                   return(-1);
8830               case SSL_ERROR_WANT_X509_LOOKUP:
8831               case SSL_ERROR_SSL:
8832               case SSL_ERROR_ZERO_RETURN:
8833               default:
8834                 ttclos(0);
8835                 return(-2);
8836             }
8837         }
8838     }
8839 #endif /* CK_SSL */
8840 #ifdef CK_KERBEROS
8841 #ifdef KRB4
8842 #ifdef RLOGCODE
8843     if (ttnproto == NP_EK4LOGIN) {
8844         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8845           return(-1);
8846         else
8847           return(len);
8848     }
8849 #endif /* RLOGCODE */
8850 #endif /* KRB4 */
8851 #ifdef KRB5
8852 #ifdef RLOGCODE
8853     if (ttnproto == NP_EK5LOGIN) {
8854         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8855           return(-1);
8856         else
8857           return(len);
8858     }
8859 #endif /* RLOGCODE */
8860 #ifdef KRB5_U2U
8861     if (ttnproto == NP_K5U2U) {
8862         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8863           return(-1);
8864         else
8865           return(len);
8866     }
8867 #endif /* KRB5_U2U */
8868 #endif /* KRB5 */
8869 #endif /* CK_KERBEROS */
8870
8871 #ifdef NETCMD
8872     if (ttpipe)
8873       fd = fdin;
8874     else
8875 #endif /* NETCMD */
8876       fd = ttyfd;
8877     x = read(fd, mybuf, 1);
8878     return(x > 0 ? x : -3);
8879 }
8880
8881 #endif /* !FIONREAD */
8882 #endif /* !aegis */
8883 #endif /* !ATTSV */
8884
8885 #endif /* MYREAD */
8886
8887 /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
8888 /*
8889   Call with the IAC that was encountered.
8890   Returns:
8891    -3: If connection has dropped or gone bad.
8892    -2: On Telnet protocol error resulting in inconsistent states.
8893     0: If negotiation OK and caller has nothing to do.
8894     1: If packet start character has changed (new value is in global stchr).
8895   255: If there was a quoted IAC as data.
8896    or: Not at all if we got a legitimate Telnet Logout request.
8897 */
8898 #ifdef TCPSOCKET
8899 static int
8900 tt_tnopt(n) int n; {                    /* Handle Telnet options */
8901     /* In case caller did not already check these conditions...  */
8902     if (n == IAC &&
8903         ((xlocal && netconn && IS_TELNET()) ||
8904          (!xlocal && sstelnet))) {
8905         extern int server;
8906         int tx = 0;
8907         debug(F100,"ttinl calling tn_doop()","",0);
8908         tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
8909         debug(F111,"ttinl tn_doop() returned","tx",tx);
8910         switch (tx) {
8911           case 0:
8912             return(0);
8913           case -1:                      /* I/O error */
8914             ttimoff();                  /* Turn off timer */
8915             return(-3);
8916           case -2:                      /* Connection failed. */
8917           case -3:
8918             ttimoff();                  /* Turn off timer */
8919             ttclos(0);
8920             return(-3);
8921           case 1:                       /* ECHO change */
8922             duplex = 1;
8923             return(0);
8924           case 2:                       /* ECHO change */
8925             duplex = 0;
8926             return(0);
8927           case 3:                       /* Quoted IAC */
8928             n = 255;
8929             return((unsigned)255);
8930 #ifdef IKS_OPTION
8931           case 4: {
8932               if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
8933 #ifdef IKSD
8934                   && !inserver
8935 #endif /* IKSD */
8936                   ) {                   /* Remote in Server mode */
8937                   ttimoff();            /* Turn off timer */
8938                   debug(F100,"u_start and !inserver","",0);
8939                   return(-2);           /* End server mode */
8940               } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
8941                          server
8942                          ) {            /* I'm no longer in Server Mode */
8943                   debug(F100,"me_start and server","",0);
8944                   ttimoff();
8945                   return(-2);
8946               }
8947               return(0);
8948           }
8949           case 5: {                     /* Start character change */
8950               /* extern CHAR stchr; */
8951               /* start = stchr; */
8952               return(1);
8953           }
8954 #endif /* IKS_OPTION */
8955           case 6:                       /* Remote Logout */
8956             ttimoff();
8957             ttclos(0);
8958 #ifdef IKSD
8959             if (inserver && !local)
8960               doexit(GOOD_EXIT,0);
8961             else
8962 #endif /* IKSD */
8963               return(-2);
8964           default:
8965             return(0);
8966         }
8967     } else
8968       return(0);
8969 }
8970 #endif /* TCPSOCKET */
8971
8972 /*  T T F L U I  --  Flush tty input buffer */
8973
8974 void
8975 ttflux() {                              /* But first... */
8976 #ifdef MYREAD
8977 /*
8978   Flush internal MYREAD buffer.
8979 */
8980 #ifdef TCPSOCKET
8981     int dotnopts, x;
8982     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
8983                  (!xlocal && sstelnet)));
8984 #endif /* TCPSOCKET */
8985     debug(F101,"ttflux my_count","",my_count);
8986 #ifdef TCPSOCKET
8987     if (dotnopts) {
8988         CHAR ch = '\0';
8989         while (my_count > 0) {
8990             ch = myread();
8991 #ifdef CK_ENCRYPTION
8992             if (TELOPT_U(TELOPT_ENCRYPTION))
8993               ck_tn_decrypt((char *)&ch,1);
8994 #endif /* CK_ENCRYPTION */
8995             if (ch == IAC)
8996               x = tt_tnopt(ch);
8997         }
8998     } else
8999 #endif /* TCPSOCKET */
9000 #ifdef COMMENT
9001 #ifdef CK_ENCRYPTION
9002     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
9003       ck_tn_decrypt(&mybuf[my_item+1],my_count);
9004 #endif /* CK_ENCRYPTION */
9005 #endif /* COMMENT */
9006     my_count = 0;                       /* Reset count to zero */
9007     my_item = -1;                       /* And buffer index to -1 */
9008 #endif /* MYREAD */
9009 }
9010
9011 int
9012 ttflui() {
9013     int n, fd;
9014 #ifdef TCPSOCKET
9015     int dotnopts;
9016     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9017                  (!xlocal && sstelnet)));
9018 #endif /* TCPSOCKET */
9019
9020 #ifdef NETCMD
9021     if (ttpipe)
9022       fd = fdin;
9023     else
9024 #endif /* NETCMD */
9025       fd = ttyfd;
9026
9027 #ifdef TTLEBUF
9028     ttpush = -1;                        /* Clear the peek-ahead char */
9029     while (le_data && (le_inbuf() > 0)) {
9030         CHAR ch = '\0';
9031         if (le_getchar(&ch) > 0) {      /* Clear any more... */
9032             debug(F101,"ttflui le_inbuf ch","",ch);
9033         }
9034     }
9035 #endif /* TTLEBUF */
9036     debug(F101,"ttflui ttpipe","",ttpipe);
9037
9038 #ifdef MYREAD
9039 /*
9040   Flush internal MYREAD buffer *NEXT*, in all cases.
9041 */
9042     ttflux();
9043 #endif /* MYREAD */
9044
9045 #ifdef NETCONN
9046 /* Network flush is done specially, in the network support module. */
9047     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
9048         debug(F100,"ttflui netflui","",0);
9049 #ifdef COMMENT
9050 #ifdef TN_COMPORT
9051         if (istncomport())
9052             tnc_send_purge_data(TNC_PURGE_RECEIVE);
9053 #endif /* TN_COMPORT */
9054 #endif /* COMMENT */
9055         return(netflui());
9056     }
9057 #endif /* NETCONN */
9058
9059     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
9060     if (ttyfd < 0)
9061       return(-1);
9062
9063 #ifdef aegis
9064     sio_$control((short)yfd, sio_$flush_in, true, st);
9065     if (st.all != status_$ok) {
9066         fprintf(stderr, "flush failed: "); error_$print(st);
9067     } else {      /* sometimes the flush doesn't work */
9068         for (;;) {
9069             char buf[256];
9070             /* eat all the characters that shouldn't be available */
9071             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
9072             if (st.all == ios_$get_conditional_failed) break;
9073             fprintf(stderr, "flush failed(2): "); error_$print(st);
9074         }
9075     }
9076 #else
9077 #ifdef BSD44                            /* 4.4 BSD */
9078     n = FREAD;                          /* Specify read queue */
9079     debug(F100,"ttflui BSD44","",0);
9080     ioctl(fd,TIOCFLUSH,&n);
9081 #else
9082 #ifdef Plan9
9083 #undef POSIX                            /* Uh oh... */
9084 #endif /* Plan9 */
9085 #ifdef POSIX                            /* POSIX */
9086     debug(F100,"ttflui POSIX","",0);
9087     tcflush(fd,TCIFLUSH);
9088 #else
9089 #ifdef ATTSV                            /* System V */
9090 #ifndef VXVE
9091     debug(F100,"ttflui ATTSV","",0);
9092     ioctl(fd,TCFLSH,0);
9093 #endif /* VXVE */
9094 #else                                   /* Not BSD44, POSIX, or Sys V */
9095 #ifdef TIOCFLUSH                        /* Those with TIOCFLUSH defined */
9096 #ifdef ANYBSD                           /* Berkeley */
9097     n = FREAD;                          /* Specify read queue */
9098     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
9099     ioctl(fd,TIOCFLUSH,&n);
9100 #else                                   /* Others (V7, etc) */
9101     debug(F100,"ttflui TIOCFLUSH","",0);
9102     ioctl(fd,TIOCFLUSH,0);
9103 #endif /* ANYBSD */
9104 #else                                   /* All others... */
9105 /*
9106   No system call (that we know about) for input buffer flushing.
9107   So see how many there are and read them in a loop, using ttinc().
9108   ttinc() is buffered, so we're not getting charged with a system call
9109   per character, just a function call.
9110 */
9111     if ((n = ttchk()) > 0) {
9112         debug(F101,"ttflui read loop","",n);
9113         while ((n--) && ttinc(0) > 0) ;
9114     }
9115 #endif /* TIOCFLUSH */
9116 #endif /* ATTSV */
9117 #endif /* POSIX */
9118 #ifdef Plan9
9119 #define POSIX
9120 #endif /* Plan9 */
9121 #endif /* BSD44 */
9122 #endif /* aegis */
9123     return(0);
9124 }
9125
9126 int
9127 ttfluo() {                              /* Flush output buffer */
9128     int fd;
9129 #ifdef NETCMD
9130     if (ttpipe)
9131       fd = fdout;
9132     else
9133 #endif /* NETCMD */
9134       fd = ttyfd;
9135
9136 #ifdef Plan9
9137     return 0;
9138 #else
9139 #ifdef POSIX
9140     return(tcflush(fd,TCOFLUSH));
9141 #else
9142 #ifdef OXOS
9143     return(ioctl(fd,TCFLSH,1));
9144 #else
9145     return(0);                          /* All others, nothing */
9146 #endif /* OXOS */
9147 #endif /* POSIX */
9148 #endif /* Plan9 */
9149 }
9150
9151 /* Interrupt Functions */
9152
9153 /* Set up terminal interrupts on console terminal */
9154
9155 #ifndef FIONREAD                        /* We don't need esctrp() */
9156 #ifndef SELECT                          /* if we have any of these... */
9157 #ifndef CK_POLL
9158 #ifndef RDCHK
9159
9160 #ifndef OXOS
9161 #ifdef SVORPOSIX
9162 SIGTYP
9163 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9164     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9165     conesc = 1;
9166     debug(F101,"esctrp caught SIGQUIT","",conesc);
9167 }
9168 #endif /* SVORPOSIX */
9169 #endif /* OXOS */
9170
9171 #ifdef V7
9172 #ifndef MINIX2
9173 SIGTYP
9174 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9175     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9176     conesc = 1;
9177     debug(F101,"esctrp caught SIGQUIT","",conesc);
9178 }
9179 #endif /* MINIX2 */
9180 #endif /* V7 */
9181
9182 #ifdef C70
9183 SIGTYP
9184 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9185     conesc = 1;
9186     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9187 }
9188 #endif /* C70 */
9189
9190 #endif /* RDCHK */
9191 #endif /* CK_POLL */
9192 #endif /* SELECT */
9193 #endif /* FIONREAD */
9194
9195 /*  C O N B G T  --  Background Test  */
9196
9197 static int jc = 0;                      /* 0 = no job control */
9198
9199 /*
9200   Call with flag == 1 to prevent signal test, which can not be expected
9201   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
9202
9203   Call with flag == 0 to use the signal test, but only if the process-group
9204   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
9205   requires an argument when the man page says it doesn't, or vice versa.
9206
9207   If flag == 0 and the process-group test fails, then we determine background
9208   status simply (but not necessarily reliably) from isatty().
9209
9210   conbgt() sets the global backgrd = 1 if we appear to be in the background,
9211   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
9212   misbehavior.
9213 */
9214 VOID
9215 conbgt(flag) int flag; {
9216     int x = -1,                         /* process group or SIGINT test */
9217         y = 0;                          /* isatty() test */
9218 /*
9219   Check for background operation, even if not running on real tty, so that
9220   background flag can be set correctly.  If background status is detected,
9221   then Kermit will not issue its interactive prompt or most messages.
9222   If your prompt goes away, you can blame (and fix?) this function.
9223 */
9224
9225 /* Use process-group test if possible. */
9226
9227 #ifdef POSIX                            /* We can do it in POSIX */
9228 #define PGROUP_T
9229 #else
9230 #ifdef BSD4                             /* and in BSD 4.x. */
9231 #define PGROUP_T
9232 #else
9233 #ifdef HPUXJOBCTL                       /* and in most HP-UX's */
9234 #define PGROUP_T
9235 #else
9236 #ifdef TIOCGPGRP                        /* and anyplace that has this ioctl. */
9237 #define PGROUP_T
9238 #endif /* TIOCGPGRP */
9239 #endif /* HPUXJOBCTL */
9240 #endif /* BSD4 */
9241 #endif /* POSIX */
9242
9243 #ifdef MIPS                             /* Except if it doesn't work... */
9244 #undef PGROUP_T
9245 #endif /* MIPS */
9246
9247 #ifdef MINIX
9248 #undef PGROUP_T
9249 #endif  /* MINIX */
9250
9251 #ifdef PGROUP_T
9252 /*
9253   Semi-reliable process-group test.  Check whether this process's group is
9254   the same as the controlling terminal's process group.  This works if the
9255   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
9256 */
9257     PID_T mypgrp = (PID_T)0;            /* Kermit's process group */
9258     PID_T ctpgrp = (PID_T)0;            /* The terminal's process group */
9259 #ifndef _POSIX_SOURCE
9260 /*
9261   The getpgrp() prototype is obtained from system header files for POSIX
9262   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
9263   a duplicate declaration here, others don't, so it's safer to leave it in
9264   if we don't know for certain.
9265 */
9266 #ifndef SVR4
9267 #ifndef PS2AIX10
9268 #ifndef HPUX9
9269     extern PID_T getpgrp();
9270 #endif /* HPUX9 */
9271 #endif /* PS2AIX10 */
9272 #endif /* SVR4 */
9273 #endif /* _POSIX_SOURCE */
9274
9275 /* Get my process group. */
9276
9277 #ifdef SVR3 /* Maybe this should be ATTSV? */
9278 /* This function is not described in SVID R2 */
9279     mypgrp = getpgrp();
9280     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
9281 #else
9282 #ifdef POSIX
9283     mypgrp = getpgrp();
9284     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
9285 #else
9286 #ifdef OSFPC
9287     mypgrp = getpgrp();
9288     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
9289 #else
9290 #ifdef QNX
9291     mypgrp = getpgrp();
9292     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
9293 #else
9294 #ifdef OSF32                            /* (was OSF40) */
9295     mypgrp = getpgrp();
9296     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
9297 #else /* BSD, V7, etc */
9298 #ifdef MINIX2
9299     mypgrp = getpgrp();
9300 #else
9301     mypgrp = getpgrp(0);
9302 #endif /* MINIX2 */
9303     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
9304 #endif /* OSF32 */
9305 #endif /* QNX */
9306 #endif /* OSFPC */
9307 #endif /* POSIX */
9308 #endif /* SVR3 */
9309
9310 #ifdef MINIX
9311     /* MINIX does not support job control so Kermit is always in foreground */
9312     x = 0;
9313
9314 #else  /* Not MINIX */
9315
9316 /* Now get controlling tty's process group */
9317 #ifdef BSD44ORPOSIX
9318     ctpgrp = tcgetpgrp(1);              /* The POSIX way */
9319     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
9320 #else
9321     ioctl(1, TIOCGPGRP, &ctpgrp);       /* Or the BSD way */
9322    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
9323 #endif /* BSD44ORPOSIX */
9324
9325     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
9326       x = (mypgrp == ctpgrp) ? 0 : 1;   /* If they differ, then background. */
9327     else x = -1;                        /* If error, remember. */
9328     debug(F101,"conbgt process group test","",x);
9329 #endif /* PGROUP_T */
9330 #endif  /* MINIX */
9331
9332 /* Try to see if job control is available */
9333
9334 #ifdef NOJC                             /* User override */
9335     jc = 0;                             /* No job control allowed */
9336     debug(F111,"NOJC","jc",jc);
9337 #else
9338 #ifdef BSD44
9339     jc = 1;
9340 #else
9341 #ifdef SVR4ORPOSIX                      /* POSIX actually tells us */
9342     debug(F100,"SVR4ORPOSIX jc test...","",0);
9343 #ifdef _SC_JOB_CONTROL
9344 #ifdef __bsdi__
9345     jc = 1;
9346 #else
9347 #ifdef __386BSD__
9348     jc = 1;
9349 #else
9350     jc = sysconf(_SC_JOB_CONTROL);      /* Whatever system says */
9351     if (jc < 0) {
9352         debug(F101,"sysconf fails, jcshell","",jcshell);
9353         jc = (jchdlr == SIG_DFL) ? 1 : 0;
9354     } else
9355       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
9356 #endif /* __386BSD__ */
9357 #endif /* __bsdi__ */
9358 #else
9359 #ifdef _POSIX_JOB_CONTROL
9360     jc = 1;                             /* By definition */
9361     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
9362 #else
9363     jc = 0;                             /* Assume job control not allowed */
9364     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
9365 #endif /* _POSIX_JOB_CONTROL */
9366 #endif /* _SC_JOB_CONTROL */
9367 #else
9368 #ifdef BSD4
9369     jc = 1;                             /* Job control allowed */
9370     debug(F111,"BSD job control","jc",jc);
9371 #else
9372 #ifdef SVR3JC
9373     jc = 1;                             /* JC allowed */
9374     debug(F111,"SVR3 job control","jc",jc);
9375 #else
9376 #ifdef OXOS
9377     jc = 1;                             /* JC allowed */
9378     debug(F111,"X/OS job control","jc",jc);
9379 #else
9380 #ifdef HPUX9
9381     jc = 1;                             /* JC allowed */
9382     debug(F111,"HP-UX 9.0 job control","jc",jc);
9383 #else
9384 #ifdef HPUX10
9385     jc = 1;                             /* JC allowed */
9386     debug(F111,"HP-UX 10.0 job control","jc",jc);
9387 #else
9388     jc = 0;                             /* JC not allowed */
9389     debug(F111,"job control catch-all","jc",jc);
9390 #endif /* HPUX10 */
9391 #endif /* HPUX9 */
9392 #endif /* OXOS */
9393 #endif /* SVR3JC */
9394 #endif /* BSD4 */
9395 #endif /* SVR4ORPOSIX */
9396 #endif /* BSD44 */
9397 #endif /* NOJC */
9398     debug(F101,"conbgt jc","",jc);
9399 #ifndef NOJC
9400     debug(F101,"conbgt jcshell","",jcshell);
9401 /*
9402   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
9403   job control, but the shell or other process we are running under does not
9404   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
9405   will come of it.  So...
9406 */
9407     if (jc < 0) jc = 0;
9408     if (jc > 0 && jcshell == 0) jc = 0;
9409 #endif /* NOJC */
9410
9411 /*
9412   Another background test.
9413   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
9414   which is done by the shell (sh) if the program is started with '&'.
9415   Unfortunately, this is NOT done by csh or ksh so watch out!
9416   Note, it's safe to set SIGINT to SIG_IGN here, because further down
9417   we always set it to something else.
9418   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
9419   SIG_IGN ourselves.
9420 */
9421     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
9422
9423         SIGTYP (*osigint)();
9424
9425         osigint = signal(SIGINT,SIG_IGN);       /* What is SIGINT set to? */
9426         sigint_ign = 1;
9427         x = (osigint == SIG_IGN) ? 1 : 0;       /* SIG_IGN? */
9428         /* debug(F101,"conbgt osigint","",osigint); */
9429         /* debug(F101,"conbgt signal test","",x); */
9430     }
9431
9432 /* Also check to see if we're running with redirected stdio. */
9433 /* This is not really background operation, but we want to act as though */
9434 /* it were. */
9435
9436 #ifdef IKSD
9437     if (inserver) {                     /* Internet Kermit Server */
9438         backgrd = 0;                    /* is not in the background */
9439         return;
9440     }
9441 #endif /* IKSD */
9442
9443     y = (isatty(0) && isatty(1)) ? 1 : 0;
9444     debug(F101,"conbgt isatty test","",y);
9445
9446 #ifdef BSD29
9447 /* The process group and/or signal test doesn't work under these... */
9448     backgrd = !y;
9449 #else
9450 #ifdef sxaE50
9451     backgrd = !y;
9452 #else
9453 #ifdef MINIX
9454     backgrd = !y;
9455 #else
9456 #ifdef MINIX2
9457     backgrd = !y;
9458 #else
9459     if (x > -1)
9460       backgrd = (x || !y) ? 1 : 0;
9461     else backgrd = !y;
9462 #endif /* BSD29 */
9463 #endif /* sxaE50 */
9464 #endif /* MINIX */
9465 #endif /* MINIX2 */
9466     debug(F101,"conbgt backgrd","",backgrd);
9467 }
9468
9469 /*  C O N I N T  --  Console Interrupt setter  */
9470
9471 /*
9472   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
9473   Second arg is pointer to function to handle SIGTSTP (suspend).
9474 */
9475
9476 VOID                                    /* Set terminal interrupt traps. */
9477 #ifdef CK_ANSIC
9478 #ifdef apollo
9479 conint(f,s) SIGTYP (*f)(), (*s)();
9480 #else
9481 conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
9482 #endif /* apollo */
9483 #else
9484 conint(f,s) SIGTYP (*f)(), (*s)();
9485 #endif /* CK_ANSIC */
9486 /* conint */ {
9487
9488     debug(F101,"conint conistate","",conistate);
9489
9490     conbgt(0);                          /* Do background test. */
9491
9492 /* Set the desired handlers for hangup and software termination. */
9493
9494 #ifdef SIGTERM
9495     signal(SIGTERM,f);                  /* Software termination */
9496 #endif /* SIGTERM */
9497
9498 /*
9499   Prior to July 1999 we used to call sighup() here but now it's called in
9500   sysinit() so SIGHUP can be caught during execution of the init file or
9501   a kerbang script.
9502 */
9503
9504 /* Now handle keyboard stop, quit, and interrupt signals. */
9505 /* Check if invoked in background -- if so signals set to be ignored. */
9506 /* However, if running under a job control shell, don't ignore them. */
9507 /* We won't be getting any, as we aren't in the terminal's process group. */
9508
9509     debug(F101,"conint backgrd","",backgrd);
9510     debug(F101,"conint jc","",jc);
9511
9512     if (backgrd && !jc) {               /* In background, ignore signals */
9513         debug(F101,"conint background ignoring signals, jc","",jc);
9514 #ifdef SIGTSTP
9515         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
9516 #endif /* SIGTSTP */
9517         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
9518         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
9519         sigint_ign = 1;
9520         conistate = CONI_NOI;
9521     } else {                            /* Else in foreground or suspended */
9522         debug(F101,"conint foreground catching signals, jc","",jc);
9523         signal(SIGINT,f);               /* Catch terminal interrupt */
9524         sigint_ign = (f == SIG_IGN) ? 1 : 0;
9525
9526 #ifdef SIGTSTP                          /* Keyboard stop (suspend) */
9527         /* debug(F101,"conint SIGSTSTP","",s); */
9528         if (s == NULL) s = SIG_DFL;
9529 #ifdef NOJC                             /* No job control allowed. */
9530         signal(SIGTSTP,SIG_IGN);
9531 #else                                   /* Job control allowed */
9532         if (jc)                         /* if available. */
9533           signal(SIGTSTP,s);
9534         else
9535           signal(SIGTSTP,SIG_IGN);
9536 #endif /* NOJC */
9537 #endif /* SIGTSTP */
9538
9539 #ifndef OXOS
9540 #ifdef SVORPOSIX
9541 #ifndef FIONREAD                        /* Watch out, we don't know this... */
9542 #ifndef SELECT
9543 #ifndef CK_POLL
9544 #ifndef RDCHK
9545         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
9546 #endif /* RDCHK */
9547 #endif /* CK_POLL */
9548 #endif /* SELECT */
9549 #endif /* FIONREAD */
9550         if (conesc) conesc = 0;         /* Clear out pending escapes */
9551 #else
9552 #ifdef V7
9553         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
9554         if (conesc) conesc = 0;
9555 #else
9556 #ifdef aegis
9557         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
9558 #else
9559         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
9560 #endif /* aegis */
9561 #endif /* V7 */
9562 #endif /* SVORPOSIX */
9563 #endif /* OXOS */
9564         conistate = CONI_INT;
9565     }
9566 }
9567
9568
9569 /*  C O N N O I  --  Reset console terminal interrupts */
9570
9571 VOID
9572 connoi() {                              /* Console-no-interrupts */
9573
9574     debug(F101,"connoi conistate","",conistate);
9575 #ifdef SIGTSTP
9576     signal(SIGTSTP,SIG_IGN);            /* Suspend */
9577 #endif /* SIGTSTP */
9578     conint(SIG_IGN,SIG_IGN);            /* Interrupt */
9579     sigint_ign = 1;                     /* Remember we did this ourselves */
9580 #ifdef SIGQUIT
9581     signal(SIGQUIT,SIG_IGN);            /* Quit */
9582 #endif /* SIGQUIT */
9583 #ifdef SIGTERM
9584     signal(SIGTERM,SIG_IGN);            /* Term */
9585 #endif /* SIGTERM */
9586     conistate = CONI_NOI;
9587 }
9588
9589 /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
9590
9591 #ifdef  V7
9592 /*
9593  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
9594  eliminates blocking on a read, because we can read /dev/kmem to get the
9595  number of characters available for raw input.  If your system can't
9596  or you won't let the world read /dev/kmem then you must figure out a
9597  different way to do the counting of characters available, or else replace
9598  this by a dummy function that always returns 0.
9599 */
9600 /*
9601  * Call this routine as: initrawq(tty)
9602  * where tty is the file descriptor of a terminal.  It will return
9603  * (as a char *) the kernel-mode memory address of the rawq character
9604  * count, which may then be read.  It has the side-effect of flushing
9605  * input on the terminal.
9606  */
9607 /*
9608  * John Mackin, Physiology Dept., University of Sydney (Australia)
9609  * ...!decvax!mulga!physiol.su.oz!john
9610  *
9611  * Permission is hereby granted to do anything with this code, as
9612  * long as this comment is retained unmodified and no commercial
9613  * advantage is gained.
9614  */
9615 #ifndef MINIX
9616 #ifndef MINIX2
9617 #ifndef COHERENT
9618 #include <a.out.h>
9619 #include <sys/proc.h>
9620 #endif /* COHERENT */
9621 #endif /* MINIX2 */
9622 #endif /* MINIX */
9623
9624 #ifdef COHERENT
9625 #include <l.out.h>
9626 #include <sys/proc.h>
9627 #endif /* COHERENT */
9628
9629 char *
9630 initrawq(tty) int tty; {
9631 #ifdef MINIX
9632     return(0);
9633 #else
9634 #ifdef MINIX2
9635     return(0);
9636 #else
9637 #ifdef UTS24
9638     return(0);
9639 #else
9640 #ifdef BSD29
9641     return(0);
9642 #else
9643     long lseek();
9644     static struct nlist nl[] = {
9645         {PROCNAME},
9646         {NPROCNAME},
9647         {""}
9648     };
9649     static struct proc *pp;
9650     char *qaddr, *p, c;
9651     int m;
9652     PID_T pid, me;
9653     NPTYPE xproc;                       /* Its type is defined in makefile. */
9654     int catch();
9655
9656     me = getpid();
9657     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
9658     nlist(BOOTNAME, nl);
9659     if (nl[0].n_type == 0) err("proc array");
9660
9661     if (nl[1].n_type == 0) err("nproc");
9662
9663     lseek(m, (long)(nl[1].n_value), 0);
9664     read (m, &xproc, sizeof(xproc));
9665     saval = signal(SIGALRM, catch);
9666     if ((pid = fork()) == 0) {
9667         while(1)
9668             read(tty, &c, 1);
9669     }
9670     alarm(2);
9671
9672     if(setjmp(jjbuf) == 0) {
9673         while(1)
9674           read(tty, &c, 1);
9675     }
9676     signal(SIGALRM, SIG_DFL);
9677
9678 #ifdef DIRECT
9679     pp = (struct proc *) nl[0].n_value;
9680 #else
9681     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
9682     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
9683 #endif
9684     lseek(m, (long)(nl[1].n_value), 0);
9685     read(m, &xproc, sizeof(xproc));
9686
9687     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
9688     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
9689     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
9690         err("read proc table");
9691     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
9692         if (pp -> p_pid == (short) pid) goto iout;
9693     }
9694     err("no such proc");
9695
9696 iout:
9697     close(m);
9698     qaddr = (char *)(pp -> p_wchan);
9699     free (p);
9700     kill(pid, SIGKILL);
9701     wait((WAIT_T *)0);
9702     return (qaddr);
9703 #endif
9704 #endif
9705 #endif
9706 #endif
9707 }
9708
9709 /*  More V7-support functions...  */
9710
9711 static VOID
9712 err(s) char *s; {
9713     char buf[200];
9714
9715     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
9716     perror(buf);
9717     doexit(1,-1);
9718 }
9719
9720 static VOID
9721 catch(foo) int foo; {
9722     longjmp(jjbuf, -1);
9723 }
9724
9725
9726 /*  G E N B R K  --  Simulate a modem break.  */
9727
9728 #ifdef MINIX
9729 #define BSPEED B110
9730 #else
9731 #ifdef MINIX2
9732 #define BSPEED B110
9733 #else
9734 #define BSPEED B150
9735 #endif /* MINIX2 */
9736 #endif /* MINIX */
9737
9738 #ifndef MINIX2
9739 VOID
9740 genbrk(fn,msec) int fn, msec; {
9741     struct sgttyb ttbuf;
9742     int ret, sospeed, x, y;
9743
9744     ret = ioctl(fn, TIOCGETP, &ttbuf);
9745     sospeed = ttbuf.sg_ospeed;
9746     ttbuf.sg_ospeed = BSPEED;
9747     ret = ioctl(fn, TIOCSETP, &ttbuf);
9748     y = (int)strlen(brnuls);
9749     x = ( BSPEED * 100 ) / msec;
9750     if (x > y) x = y;
9751     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9752     ttbuf.sg_ospeed = sospeed;
9753     ret = ioctl(fn, TIOCSETP, &ttbuf);
9754     ret = write(fn, "@", 1);
9755     return;
9756 }
9757 #endif /* MINIX2 */
9758
9759 #ifdef MINIX2
9760 int
9761 genbrk(fn,msec) int fn, msec; {
9762     struct termios ttbuf;
9763     int ret, x, y;
9764     speed_t sospeed;
9765
9766     ret = tcgetattr(fn, &ttbuf);
9767     sospeed = ttbuf.c_ospeed;
9768     ttbuf.c_ospeed = BSPEED;
9769     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
9770     y = (int)strlen(brnuls);
9771     x = ( BSPEED * 100 ) / msec;
9772     if (x > y) x = y;
9773     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9774     ttbuf.c_ospeed = sospeed;
9775     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
9776     ret = write(fn, "@", 1);
9777     return ret;
9778 }
9779 #endif /* MINIX2 */
9780 #endif /* V7 */
9781
9782 /*
9783   I N C H K  --  Check if chars waiting to be read on given file descriptor.
9784
9785   This routine is a merger of ttchk() and conchk().
9786   Call with:
9787     channel == 0 to check console.
9788     channel == 1 to check communications connection.
9789   and:
9790     fd = file descriptor.
9791   Returns:
9792    >= 0: number of characters waiting, 0 or greater,
9793      -1: on any kind of error,
9794      -2: if there is (definitely) no connection.
9795   Note: In UNIX we don't have to call nettchk() because a socket
9796   file descriptor works just like in serial i/o, ioctls and all.
9797   (But this will change if we add non-file-descriptor channels,
9798   such as IBM X.25 for AIX...)
9799 */
9800 static int
9801 in_chk(channel, fd) int channel, fd; {
9802     int x, n = 0;                       /* Workers, n = return value */
9803     extern int clsondisc;               /* Close on disconnect */
9804 /*
9805   The first section checks to make sure we have a connection,
9806   but only if we're in local mode.
9807 */
9808 #ifdef DEBUG
9809     if (deblog) {
9810         debug(F111,"in_chk entry",ckitoa(fd),channel);
9811         debug(F101,"in_chk ttyfd","",ttyfd);
9812         debug(F101,"in_chk ttpty","",ttpty);
9813     }
9814 #endif /* DEBUG */
9815 /*
9816   But don't say connection is gone if we have any buffered-stuff.
9817 */
9818 #ifdef TTLEBUF
9819     debug(F101,"in_chk ttpush","",ttpush);
9820     if (channel == 1) {
9821         if (ttpush >= 0)
9822           n++;
9823         n += le_inbuf();
9824         if (n > 0)
9825           return(n);
9826     }
9827 #endif /* TTLEBUF */
9828
9829 #ifdef NETPTY
9830 #ifdef HAVE_PTYTRAP
9831     /* Special handling for HP-UX pty i/o */
9832     if (ttpty && pty_trap_pending(ttyfd) > 0) {
9833         if (pty_trap_handler(ttyfd) > 0) {
9834             ttclos(0);
9835             return(-2);
9836         }
9837     }
9838 #endif /* HAVE_PTYTRAP */
9839 #endif /* NETPTY */
9840
9841     if (channel) {                      /* Checking communications channel */
9842         if (ttyfd < 0) {                /* No connection */
9843           return(-2);                   /* That's what this means */
9844         } else if (xlocal &&            /* In local mode */
9845                    (!netconn            /* Serial connection or */
9846 #ifdef TN_COMPORT
9847                     || istncomport()    /* Telnet Com Port */
9848 #endif /* TN_COMPORT */
9849                    ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
9850 #ifdef COMMENT
9851 #ifdef MYREAD
9852 /*
9853   Seems like this would be a good idea but it prevents C-Kermit from
9854   popping back to the prompt automatically when carrier drops.  However,
9855   commenting this out prevents us from seeing the NO CARRIER message.
9856   Needs more work...
9857 */
9858                    && my_count < 1      /* Nothing in our internal buffer */
9859 #endif /* MYREAD */
9860 #endif /* COMMENT */
9861                    ) {
9862             int x;
9863             x = ttgmdm();               /* So get modem signals */
9864             debug(F101,"in_chk close-on-disconnect","",clsondisc);
9865             if (x > -1) {               /* Check for carrier */
9866                 if (!(x & BM_DCD)) {    /* No carrier */
9867                     debug(F101,"in_chk carrier lost","",x);
9868                     if (clsondisc)      /* If "close-on-disconnect" */
9869                       ttclos(0);        /* close device & release lock. */
9870                     return(-2);         /* This means "disconnected" */
9871                 }
9872             /* In case I/O to device after CD dropped always fails */
9873             /* as in Debian Linux 2.1 and Unixware 2.1... */
9874             } else {
9875                 debug(F101,"in_chk ttgmdm I/O error","",errno);
9876                 debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
9877                 if (gotsigs) {          /* If we got signals before... */
9878                     if (errno == 5 || errno == 6) { /* I/O error etc */
9879                         if (clsondisc)  /* like when modem hangs up */
9880                           ttclos(0);
9881                         return(-2);
9882                     }
9883                 }
9884                 /* If we never got modem signals successfully on this */
9885                 /* connection before, we can't conclude that THIS failure */
9886                 /* means the connection was lost. */
9887                 return(0);
9888             }
9889         }
9890     }
9891
9892 /* We seem to have a connection so now see if any bytes are waiting on it */
9893
9894 #ifdef CK_SSL
9895     if (ssl_active_flag || tls_active_flag) {
9896         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
9897         debug(F101,"in_chk SSL_pending","",n);
9898         if (n < 0) {
9899             ttclos(0);
9900             return(-1);
9901         } else if (n > 0) {
9902             return(n);
9903         }
9904     }
9905 #endif /* CK_SSL */
9906 #ifdef RLOGCODE
9907 #ifdef CK_KERBEROS
9908     /* It is not safe to read any data when using encrypted Klogin */
9909     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
9910 #ifdef KRB4
9911         if (ttnproto == NP_EK4LOGIN) {
9912             n += krb4_des_avail(ttyfd);
9913             debug(F101,"in_chk krb4_des_avail","",n);
9914         }
9915 #endif /* KRB4 */
9916 #ifdef KRB5
9917         if (ttnproto == NP_EK5LOGIN) {
9918             n += krb5_des_avail(ttyfd);
9919             debug(F101,"in_chk krb5_des_avail","",n);
9920         }
9921 #ifdef KRB5_U2U
9922         if (ttnproto == NP_K5U2U) {
9923             n += krb5_u2u_avail(ttyfd);
9924             debug(F101,"in_chk krb5_des_avail","",n);
9925         }
9926 #endif /* KRB5_U2U */
9927 #endif /* KRB5 */
9928         if (n < 0)                      /* Is this right? */
9929           return(-1);
9930         else
9931           return(n);
9932     }
9933 #endif /* CK_KERBEROS */
9934 #endif /* RLOGCODE */
9935
9936     errno = 0;                          /* Reset this so we log good info */
9937 #ifdef FIONREAD
9938     x = ioctl(fd, FIONREAD, &n);        /* BSD and lots of others */
9939 #ifdef DEBUG                            /* (the more the better) */
9940     if (deblog) {
9941         debug(F101,"in_chk FIONREAD return code","",x);
9942         debug(F101,"in_chk FIONREAD count","",n);
9943         debug(F101,"in_chk FIONREAD errno","",errno);
9944     }
9945 #endif /* DEBUG */
9946 #else /* FIONREAD not defined */
9947 /*
9948   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
9949   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
9950   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
9951   that I looked at, but it is needed to prevent the call from blocking), and
9952   the msghdr struct differs from place to place, so we would need another
9953   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
9954   only other known method of asking the OS for the *number* of characters
9955   available for reading.
9956 */
9957 #ifdef V7                               /* UNIX V7: look in kernel memory */
9958 #ifdef MINIX
9959     n = 0;                              /* But not in MINIX */
9960 #else
9961 #ifdef MINIX2
9962     n = 0;
9963 #else
9964     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
9965     x = read(kmem[TTY], &n, sizeof(int));
9966     if (x != sizeof(int))
9967       n = 0;
9968 #endif /* MINIX2 */
9969 #endif /* MINIX */
9970 #else /* Not V7 */
9971 #ifdef PROVX1
9972     x = ioctl(fd, TIOCQCNT, &ttbuf);    /* DEC Pro/3xx Venix V.1 */
9973     n = ttbuf.sg_ispeed & 0377;         /* Circa 1984 */
9974     if (x < 0) n = 0;
9975 #else
9976 #ifdef MYREAD
9977 /*
9978   Here we skip all the undependable and expensive calls below if we
9979   already have something in our internal buffer.  This tends to work quite
9980   nicely, so the only really bad case remaining is the one in which neither
9981   FIONREAD or MYREAD are defined, which is increasingly rare these days.
9982 */
9983     if (channel != 0 && my_count > 0) {
9984         debug(F101,"in_chk buf my_count","",my_count);
9985         n = my_count;                   /* n was 0 before we got here */
9986         return(n);
9987     }
9988 #endif /* MYREAD */
9989 /*
9990   rdchk(), select(), and poll() tell us *if* data is available to be read, but
9991   not how much, so these should be used only as a final resort.  Especially
9992   since these calls tend to add a lot overhead.
9993 */
9994 #ifdef RDCHK                            /* This mostly SCO-specific */
9995     n = rdchk(fd);
9996     debug(F101,"in_chk rdchk","",n);
9997 #else /* No RDCHK */
9998 #ifdef SELECT
9999 #ifdef Plan9
10000     /* Only allows select on the console ... don't ask */
10001     if (channel == 0)
10002 #endif /* Plan9 */
10003       {
10004         fd_set rfds;                    /* Read file descriptors */
10005 #ifdef BELLV10
10006         FD_ZERO(rfds);                  /* Initialize them */
10007         FD_SET(fd,rfds);                /* We want to look at this fd */
10008 #else
10009         FD_ZERO(&rfds);                 /* Initialize them */
10010         FD_SET(fd,&rfds);               /* We want to look at this fd */
10011         tv.tv_sec = tv.tv_usec = 0L;    /* A 0-valued timeval structure */
10012 #endif /* BELLV10 */
10013 #ifdef Plan9
10014         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10015         debug(F101,"in_chk Plan 9 select","",n);
10016 #else
10017 #ifdef BELLV10
10018         n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
10019         debug(F101,"in_chk BELLV10 select","",n);
10020 #else
10021 #ifdef BSD44
10022         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10023         debug(F101,"in_chk BSD44 select","",n);
10024 #else
10025 #ifdef BSD43
10026         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10027         debug(F101,"in_chk BSD43 select","",n);
10028 #else
10029 #ifdef SOLARIS
10030         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10031         debug(F101,"in_chk SOLARIS select","",n);
10032 #else
10033 #ifdef QNX6
10034         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10035         debug(F101,"in_chk QNX6 select","",n);
10036 #else
10037 #ifdef QNX
10038         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10039         debug(F101,"in_chk QNX select","",n);
10040 #else
10041 #ifdef COHERENT
10042         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10043         debug(F101,"in_chk COHERENT select","",n);
10044 #else
10045 #ifdef SVR4
10046         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10047         debug(F101,"in_chk SVR4 select","",n);
10048 #else
10049 #ifdef __linux__
10050         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10051         debug(F101,"in_chk LINUX select","",n);
10052 #ifdef OSF
10053         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10054         debug(F101,"in_chk OSF select","",n);
10055 #else
10056         n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
10057         debug(F101,"in_chk catchall select","",n);
10058 #endif /* OSF */
10059 #endif /* __linux__ */
10060 #endif /* SVR4 */
10061 #endif /* COHERENT */
10062 #endif /* QNX */
10063 #endif /* QNX6 */
10064 #endif /* SOLARIS */
10065 #endif /* BSD43 */
10066 #endif /* BSD44 */
10067 #endif /* BELLV10 */
10068 #endif /* Plan9 */
10069     }
10070 #else  /* Not SELECT */
10071 #ifdef CK_POLL
10072     {
10073       struct pollfd pfd;
10074
10075       pfd.fd = fd;
10076       pfd.events = POLLIN;
10077       pfd.revents = 0;
10078       n = poll(&pfd, 1, 0);
10079       debug(F101,"in_chk poll","",n);
10080       if ((n > 0) && (pfd.revents & POLLIN))
10081         n = 1;
10082     }
10083 #endif /* CK_POLL */
10084 #endif /* SELECT */
10085 #endif /* RDCHK */
10086 #endif /* PROVX1 */
10087 #endif /* V7 */
10088 #endif /* FIONREAD */
10089
10090 /* From here down, treat console and communication device differently... */
10091
10092     if (channel == 0) {                 /* Console */
10093
10094 #ifdef SVORPOSIX
10095 #ifndef FIONREAD
10096 #ifndef SELECT
10097 #ifndef CK_POLL
10098 #ifndef RDCHK
10099 /*
10100   This is the hideous hack used in System V and POSIX systems that don't
10101   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
10102   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
10103   only on the console.
10104 */
10105         if (conesc) {                   /* Escape character typed == SIGQUIT */
10106             debug(F100,"in_chk conesc","",conesc);
10107             conesc = 0;
10108             signal(SIGQUIT,esctrp);     /* Restore signal */
10109             n += 1;
10110         }
10111 #endif /* RDCHK */
10112 #endif /* CK_POLL */
10113 #endif /* SELECT */
10114 #endif /* FIONREAD */
10115 #endif /* SVORPOSIX */
10116
10117         return(n);                      /* Done with console */
10118     }
10119
10120     if (channel != 0) {                 /* Communications connection */
10121
10122 #ifdef MYREAD
10123 #ifndef FIONREAD
10124 /*
10125   select() or rdchk(), etc, has told us that something is waiting, but we
10126   don't know how much.  So we do a read to get it and then we know.  Note:
10127   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
10128   it should be safe in this case since the OS tells us at least one byte is
10129   waiting to be read, and MYREAD reads return as much as is there without
10130   waiting for any more.  Controlled tests on Solaris and Unixware (with
10131   FIONREAD deliberately undefined) show this to be true.
10132 */
10133         debug(F101,"in_chk read my_count","",my_count);
10134         debug(F101,"in_chk read n","",n);
10135         if (n > 0 && my_count == 0) {
10136             /* This also catches disconnects etc */
10137             /* Do what mygetbuf does except don't grab a character */
10138             my_count = myfillbuf();
10139             my_item = -1;               /* ^^^ */
10140             debug(F101,"in_chk myfillbuf my_count","",my_count);
10141             if (my_count < 0)
10142               return(-1);
10143             else
10144               n = 0;                    /* NB: n is replaced by my_count */
10145         }
10146 #endif /* FIONREAD */
10147 /*
10148   Here we add whatever we think is unread to what is still in our
10149   our internal buffer.  Thus the importance of setting n to 0 just above.
10150 */
10151         debug(F101,"in_chk my_count","",my_count);
10152         debug(F101,"in_chk n","",n);
10153         if (my_count > 0)
10154           n += my_count;
10155 #endif /* MYREAD */
10156     }
10157     debug(F101,"in_chk result","",n);
10158
10159     /* Errors here don't prove the connection has dropped so just say 0 */
10160
10161     return(n < 0 ? 0 : n);
10162 }
10163
10164
10165 /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
10166
10167 int
10168 ttchk() {
10169     int fd;
10170 #ifdef NETCMD
10171     if (ttpipe)
10172       fd = fdin;
10173     else
10174 #endif /* NETCMD */
10175       fd = ttyfd;
10176     return(in_chk(1,fd));
10177 }
10178
10179 /*  T T X I N  --  Get n characters from tty input buffer  */
10180
10181 /*  Returns number of characters actually gotten, or -1 on failure  */
10182
10183 /*  Intended for use only when it is known that n characters are actually */
10184 /*  Available in the input buffer.  */
10185
10186 int
10187 ttxin(n,buf) int n; CHAR *buf; {
10188     register int x = 0, c = -2;
10189 #ifdef TTLEBUF
10190     register int i = 0;
10191 #endif /* TTLEBUF */
10192     int fd;
10193
10194     if (n < 1)                          /* Nothing to do */
10195       return(0);
10196
10197 #ifdef TTLEBUF
10198     if (ttpush >= 0) {
10199         buf[0] = ttpush;                /* Put pushed char in buffer*/
10200         ttpush = -1;                    /* Clear the push buffer */
10201         if (ttchk() > 0)
10202           return(ttxin(n-1, &buf[1]) + 1);
10203         else
10204           return(1);
10205     }
10206     if (le_data) {
10207         while (le_inbuf() > 0) {
10208             if (le_getchar(&buf[i])) {
10209                 i++;
10210                 n--;
10211             }
10212         }
10213         if (ttchk() > 0)
10214           return(ttxin(n,&buf[i])+i);
10215         else
10216           return(i);
10217     }
10218 #endif /* TTLEBUF */
10219
10220 #ifdef NETCMD
10221     if (ttpipe)
10222       fd = fdin;
10223     else
10224 #endif /* NETCMD */
10225       fd = ttyfd;
10226
10227 #ifdef SUNX25
10228     if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
10229       return(x25xin(n,buf));
10230 #endif /* SUNX25 */
10231
10232 #ifdef IBMX25
10233     /* riehm: possibly not needed. Test worked with normal reads and writes */
10234     if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
10235         x = x25xin(n,buf);
10236         if (x > 0) buf[x] = '\0';
10237         return(x);
10238     }
10239 #endif /* IBMX25 */
10240
10241 #ifdef MYREAD
10242     debug(F101,"ttxin MYREAD","",n);
10243     while (x < n) {
10244         c = myread();
10245         if (c < 0) {
10246             debug(F101,"ttxin myread returns","",c);
10247             if (c == -3) x = -1;
10248             break;
10249         }
10250         buf[x++] = c & ttpmsk;
10251 #ifdef RLOGCODE
10252 #ifdef CK_KERBEROS
10253         /* It is impossible to know how many characters are waiting */
10254         /* to be read when you are using Encrypted Rlogin or SSL    */
10255         /* as the transport since the number of real data bytes     */
10256         /* can be greater or less than the number of bytes on the   */
10257         /* wire which is what ttchk() returns.                      */
10258         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
10259           if (ttchk() <= 0)
10260             break;
10261 #endif /* CK_KERBEROS */
10262 #endif /* RLOGCODE */
10263 #ifdef CK_SSL
10264         if (ssl_active_flag || tls_active_flag)
10265           if (ttchk() <= 0)
10266             break;
10267 #endif /* CK_SSL */
10268     }
10269 #else
10270     debug(F101,"ttxin READ","",n);
10271     x = read(fd,buf,n);
10272     for (c = 0; c < n; c++)             /* Strip any parity */
10273       buf[c] &= ttpmsk;
10274 #endif /* MYREAD */
10275
10276     debug(F101,"ttxin x","",x);         /* Done */
10277     if (x > 0) buf[x] = '\0';
10278     if (x < 0) x = -1;
10279     return(x);
10280 }
10281
10282 /*  T T O L  --  Write string s, length n, to communication device.  */
10283 /*
10284   Returns:
10285    >= 0 on success, number of characters actually written.
10286    -1 on failure.
10287 */
10288 #ifdef CK_ENCRYPTION
10289 CHAR * xpacket = NULL;
10290 int nxpacket = 0;
10291 #endif /* CK_ENCRYPTION */
10292
10293 #define TTOLMAXT 5
10294 int
10295 ttol(s,n) int n; CHAR *s; {
10296     int x, len, tries, fd;
10297 #ifdef CKXXCHAR
10298     extern int dblflag;                 /* For SET SEND DOUBLE-CHARACTER */
10299     extern short dblt[];
10300     CHAR *p = NULL, *p2, *s2, c;
10301     int n2 = 0;
10302 #endif /* CKXXCHAR */
10303
10304     if (ttyfd < 0)                      /* Not open? */
10305       return(-3);
10306 #ifdef DEBUG
10307     if (deblog) {
10308         /* debug(F101,"ttol ttyfd","",ttyfd); */
10309         ckhexdump("ttol s",s,n);
10310     }
10311 #endif /* DEBUG */
10312
10313 #ifdef NETCMD
10314     if (ttpipe)
10315       fd = fdout;
10316     else
10317 #endif /* NETCMD */
10318       fd = ttyfd;
10319
10320 #ifdef CKXXCHAR
10321 /*  Double any characters that must be doubled.  */
10322     debug(F101,"ttol dblflag","",dblflag);
10323     if (dblflag) {
10324         p = (CHAR *) malloc(n + n + 1);
10325         if (p) {
10326             s2 = s;
10327             p2 = p;
10328             n2 = 0;
10329             while (*s2) {
10330                 c = *s2++;
10331                 *p2++ = c;
10332                 n2++;
10333                 if (dblt[(unsigned) c] & 2) {
10334                     *p2++ = c;
10335                     n2++;
10336                 }
10337             }
10338             s = p;
10339             n = n2;
10340             s[n] = '\0';
10341         }
10342 #ifdef DEBUG
10343         ckhexdump("ttol doubled s",s,n);
10344 #endif /* DEBUG */
10345     }
10346 #endif /* CKXXCHAR */
10347
10348     tries = TTOLMAXT;                   /* Allow up to this many tries */
10349     len = n;                            /* Remember original length */
10350
10351 #ifdef CK_ENCRYPTION
10352 /*
10353   This is to avoid encrypting a packet that is already encrypted, e.g.
10354   when we resend a packet directly out of the packet buffer, and also to
10355   avoid encrypting a constant (literal) string, which can cause a memory
10356   fault.
10357 */
10358     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
10359         int x;
10360         if (nxpacket < n) {
10361             if (xpacket) {
10362                 free(xpacket);
10363                 xpacket = NULL;
10364                 nxpacket = 0;
10365             }
10366             x = n > 10240 ? n : 10240;
10367             xpacket = (CHAR *)malloc(x);
10368             if (!xpacket) {
10369                 fprintf(stderr,"ttol malloc failure\n");
10370                 return(-1);
10371             } else
10372               nxpacket = x;
10373         }
10374         memcpy((char *)xpacket,(char *)s,n);
10375         s = xpacket;
10376         ck_tn_encrypt((char *)s,n);
10377     }
10378 #endif /* CK_ENCRYPTION */
10379
10380     while (n > 0 &&
10381            (tries-- > 0
10382 #ifdef CK_ENCRYPTION
10383             /* keep trying if we are encrypting */
10384             || TELOPT_ME(TELOPT_ENCRYPTION)
10385 #endif /* CK_ENCRYPTION */
10386             )) {                        /* Be persistent */
10387         debug(F101,"ttol try","",TTOLMAXT - tries);
10388 #ifdef BEOSORBEBOX
10389         if (netconn && !ttpipe && !ttpty)
10390           x = nettol((char *)s,n);      /* Write string to device */
10391         else
10392 #endif /* BEOSORBEBOX */
10393 #ifdef IBMX25
10394           if (ttnet == NET_IX25)
10395             /*
10396              * this is a more controlled way of writing to X25
10397              * STREAMS, however write should also work!
10398              */
10399             x = x25write(ttyfd, s, n);
10400           else
10401 #endif /* IBMX25 */
10402 #ifdef CK_SSL
10403             if (ssl_active_flag || tls_active_flag) {
10404                 int error;
10405                 /* Write using SSL */
10406                 ssl_retry:
10407                 if (ssl_active_flag)
10408                   x = SSL_write(ssl_con, s, n);
10409                 else
10410                   x = SSL_write(tls_con, s, n);
10411                 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
10412                 case SSL_ERROR_NONE:
10413                     if (x == n)
10414                       return(len);
10415                     s += x;
10416                     n -= x;
10417                     goto ssl_retry;
10418                   case SSL_ERROR_WANT_WRITE:
10419                   case SSL_ERROR_WANT_READ:
10420                     x = 0;
10421                     break;
10422                   case SSL_ERROR_SYSCALL:
10423                     if (x != 0)
10424                       return(-1);
10425                   case SSL_ERROR_WANT_X509_LOOKUP:
10426                   case SSL_ERROR_SSL:
10427                   case SSL_ERROR_ZERO_RETURN:
10428                   default:
10429                     ttclos(0);
10430                     return(-3);
10431                 }
10432             } else
10433 #endif /* CK_SSL */
10434 #ifdef CK_KERBEROS
10435 #ifdef KRB4
10436 #ifdef RLOGCODE
10437             if (ttnproto == NP_EK4LOGIN) {
10438                 return(krb4_des_write(ttyfd,s,n));
10439             } else
10440 #endif /* RLOGCODE */
10441 #endif /* KRB4 */
10442 #ifdef KRB5
10443 #ifdef RLOGCODE
10444             if (ttnproto == NP_EK5LOGIN) {
10445                 return(krb5_des_write(ttyfd,(char *)s,n,0));
10446             } else
10447 #endif /* RLOGCODE */
10448 #ifdef KRB5_U2U
10449             if (ttnproto == NP_K5U2U) {
10450                 return(krb5_u2u_write(ttyfd,(char *)s,n));
10451             } else
10452 #endif /* KRB5_U2U */
10453 #endif /* KRB5 */
10454 #endif /* CK_KERBEROS */
10455               x = write(fd,s,n);        /* Write string to device */
10456
10457         if (x == n) {                   /* Worked? */
10458             debug(F101,"ttol ok","",x); /* OK */
10459 #ifdef CKXXCHAR
10460             if (p) free(p);
10461 #endif /* CKXXCHAR */
10462             return(len);                /* Done */
10463         } else if (x < 0) {             /* No, got error? */
10464             debug(F101,"ttol write error","",errno);
10465 #ifdef EWOULDBLOCK
10466             if (errno == EWOULDBLOCK) {
10467                 msleep(10);
10468                 continue;
10469             } else
10470 #endif /* EWOULDBLOCK */
10471 #ifdef TCPSOCKET
10472             if (netconn && ttnet == NET_TCPB) {
10473                 debug(F101,"ttol TCP error","",errno);
10474                 ttclos(0);              /* Close the connection. */
10475                 x = -3;
10476             }
10477 #endif /* TCPSOCKET */
10478 #ifdef CKXXCHAR
10479             if (p) free(p);
10480 #endif /* CKXXCHAR */
10481             return(x);
10482         } else {                        /* No error, so partial success */
10483             debug(F101,"ttol partial","",x); /* This never happens */
10484             s += x;                     /* Point to part not written yet */
10485             n -= x;                     /* Adjust length */
10486             if (x > 0) msleep(10);      /* Wait 10 msec */
10487         }                               /* Go back and try again */
10488     }
10489 #ifdef CKXXCHAR
10490     if (p) free(p);
10491 #endif /* CKXXCHAR */
10492     return(n < 1 ? len : -1);           /* Return the results */
10493 }
10494
10495 /*  T T O C  --  Output a character to the communication line  */
10496
10497 /*
10498  This function should only be used for interactive, character-mode operations,
10499  like terminal connection, script execution, dialer i/o, where the overhead
10500  of the signals and alarms does not create a bottleneck.
10501 */
10502 int
10503 #ifdef CK_ANSIC
10504 ttoc(char c)
10505 #else
10506 ttoc(c) char c;
10507 #endif /* CK_ANSIC */
10508 /* ttoc */ {
10509 #define TTOC_TMO 15                     /* Timeout in case we get stuck */
10510     int xx, fd;
10511
10512     if (ttyfd < 0)                      /* Check for not open. */
10513       return(-1);
10514
10515 #ifdef NETCMD
10516     if (ttpipe)
10517       fd = fdout;
10518     else
10519 #endif /* NETCMD */
10520       fd = ttyfd;
10521
10522     c &= 0xff;
10523     /* debug(F101,"ttoc","",(CHAR) c); */
10524     saval = signal(SIGALRM,timerh);     /* Enable timer interrupt */
10525     xx = alarm(TTOC_TMO);               /* for this many seconds. */
10526     if (xx < 0) xx = 0;                 /* Save old alarm value. */
10527     /* debug(F101,"ttoc alarm","",xx); */
10528     if (
10529 #ifdef CK_POSIX_SIG
10530         sigsetjmp(sjbuf,1)
10531 #else
10532         setjmp(sjbuf)
10533 #endif /* CK_POSIX_SIG */
10534         ) {             /* Timer went off? */
10535         ttimoff();                      /* Yes, cancel this alarm. */
10536         if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
10537         /* debug(F100,"ttoc timeout","",0); */
10538 #ifdef NETCONN
10539         if (!netconn) {
10540 #endif /* NETCONN */
10541             debug(F101,"ttoc timeout","",c);
10542             if (ttflow == FLO_XONX) {
10543                 debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
10544 #ifndef Plan9
10545 #ifdef POSIX
10546                 /* POSIX way to unstick. */
10547                 debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
10548 #else
10549 #ifdef BSD4                             /* Berkeley way to do it. */
10550 #ifdef TIOCSTART
10551 /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
10552                 {
10553                   int x = 0;
10554                   debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
10555                 }
10556 #endif /* TIOCSTART */
10557 #endif /* BSD4 */
10558                                         /* Is there a Sys V way to do this? */
10559 #endif /* POSIX */
10560 #endif /* Plan9 */
10561             }
10562 #ifdef NETCONN
10563         }
10564 #endif /* NETCONN */
10565         return(-1);                     /* Return failure code. */
10566     } else {
10567         int rc;
10568 #ifdef BEOSORBEBOX
10569 #ifdef NETCONN
10570         if (netconn && !ttpipe && !ttpty)
10571           rc = nettoc(c);
10572         else
10573 #endif /*  BEOSORBEBOX */
10574 #endif /* NETCONN */
10575 #ifdef CK_ENCRYPTION
10576           if (TELOPT_ME(TELOPT_ENCRYPTION))
10577             ck_tn_encrypt(&c,1);
10578 #endif /* CK_ENCRYPTION */
10579 #ifdef IBMX25
10580         /* riehm: maybe this isn't necessary after all. Test program
10581          * worked fine with data being sent and retrieved with normal
10582          * read's and writes!
10583          */
10584         if (ttnet == NET_IX25)
10585           rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
10586         else
10587 #endif /* IBMX25 */
10588 #ifdef CK_SSL
10589           if (ssl_active_flag || tls_active_flag) {
10590               int error;
10591               /* Write using SSL */
10592               if (ssl_active_flag)
10593                 rc = SSL_write(ssl_con, &c, 1);
10594               else
10595                 rc = SSL_write(tls_con, &c, 1);
10596               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
10597                 case SSL_ERROR_NONE:
10598                   break;
10599                 case SSL_ERROR_WANT_WRITE:
10600                 case SSL_ERROR_WANT_READ:
10601                   rc = 0;
10602                   break;
10603                 case SSL_ERROR_SYSCALL:
10604                   if (rc != 0)
10605                     return(-1);
10606                 case SSL_ERROR_WANT_X509_LOOKUP:
10607                 case SSL_ERROR_SSL:
10608                 case SSL_ERROR_ZERO_RETURN:
10609                 default:
10610                   ttclos(0);
10611                   return(-1);
10612               }
10613           } else
10614 #endif /* CK_SSL */
10615 #ifdef CK_KERBEROS
10616 #ifdef KRB4
10617 #ifdef RLOGCODE
10618           if (ttnproto == NP_EK4LOGIN) {
10619               rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
10620           } else
10621 #endif /* RLOGCODE */
10622 #endif /* KRB4 */
10623 #ifdef KRB5
10624 #ifdef RLOGCODE
10625           if (ttnproto == NP_EK5LOGIN) {
10626               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
10627           } else
10628 #endif /* RLOGCODE */
10629 #ifdef KRB5_U2U
10630           if (ttnproto == NP_K5U2U) {
10631               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
10632           } else
10633 #endif /* KRB5_U2U */
10634 #endif /* KRB5 */
10635 #endif /* CK_KERBEROS */
10636             rc = write(fd,&c,1);        /* Try to write the character. */
10637         if (rc < 1) {                   /* Failed */
10638             ttimoff();                  /* Turn off the alarm. */
10639             alarm(xx);                  /* Restore previous alarm. */
10640             debug(F101,"ttoc errno","",errno); /* Log the error, */
10641             return(-1);                 /* and return the error code. */
10642         }
10643     }
10644     ttimoff();                          /* Success, turn off the alarm. */
10645     alarm(xx);                          /* Restore previous alarm. */
10646     return(0);                          /* Return good code. */
10647 }
10648
10649 /*  T T I N L  --  Read a record (up to break character) from comm line.  */
10650 /*
10651   Reads up to "max" characters from the connection, terminating on:
10652     (a) the packet length field if the "turn" argument is zero, or
10653     (b) on the packet-end character (eol) if the "turn" argument is nonzero
10654     (c) a certain number of Ctrl-C's in a row
10655
10656   Returns:
10657     >= 0, the number of characters read upon success;
10658     -1 if "max" exceeded, timeout, or other correctable error;
10659     -2 on user interruption (c);
10660     -3 on fatal error like connection lost.
10661
10662   The name of this routine dates from the early days when Kermit packets
10663   were, indeed, always lines of text.  That was before control-character
10664   unprefixing and length-driven packet framing were introduced, which this
10665   version handle.  NB: this routine is ONLY for reading incoming Kermit
10666   packets, nothing else.  To read other kinds of incoming material, use
10667   ttinc() or ttxin().
10668
10669   The bytes that were input are copied into "dest" with their parity bits
10670   stripped if parity was selected.  Returns the number of bytes read.
10671   Bytes after the eol are available upon the next call to this function.
10672
10673   The idea is to minimize the number of system calls per packet, and also to
10674   minimize timeouts.  This function is the inner loop of the protocol and must
10675   be as efficient as possible.  The current strategy is to use myread(), a
10676   macro to manage buffered (and generally nonblocking) reads.
10677
10678   WARNING: This function calls parchk(), which is defined in another module.
10679   Normally, ckutio.c does not depend on code from any other module, but there
10680   is an exception in this case because all the other ck?tio.c modules also
10681   need to call parchk(), so it's better to have it defined in a common place.
10682 */
10683 #ifdef CTRLC
10684 #undef CTRLC
10685 #endif /* CTRLC */
10686 #define CTRLC '\03'
10687 /*
10688   We have four different declarations here because:
10689   (a) to allow Kermit to be built without the automatic parity sensing feature
10690   (b) one of each type for ANSI C, one for non-ANSI.
10691 */
10692 #ifndef NOXFER
10693
10694 static int pushedback = 0;
10695
10696 int
10697 #ifdef PARSENSE
10698 #ifdef CK_ANSIC
10699 ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
10700 #else
10701 ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
10702 #endif /* CK_ANSIC */
10703 #else /* not PARSENSE */
10704 #ifdef CK_ANSIC
10705 ttinl(CHAR *dest, int max,int timo, CHAR eol)
10706 #else
10707 ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
10708 #endif /* CK_ANSIC */
10709 #endif /* PARSENSE */
10710 /* ttinl */ {
10711
10712 #ifndef MYREAD
10713     CHAR ch, dum;
10714 #endif /* MYREAD */
10715 #ifdef PARSENSE
10716     int pktlen = -1;
10717     int lplen = 0;
10718     int havelen = 0;
10719 #endif /* PARSENSE */
10720     int fd;
10721     int sopmask = 0xff;                 /* Start-Of-Packet mask */
10722 #ifdef CKXXCHAR
10723     extern short dblt[];                /* Ignore-character table */
10724     extern int ignflag;
10725 #endif /* CKXXCHAR */
10726 #ifdef TCPSOCKET
10727     extern CHAR stchr;
10728 #endif /* TCPSOCKET */
10729     int x;
10730 #ifdef STREAMING
10731     extern int streaming;
10732     extern int sndtyp;
10733 #endif /* STREAMING */
10734
10735     if (ttyfd < 0) return(-3);          /* Not open. */
10736 /*
10737   In February 2007 I fixed ttinl() to work better under the truly awful
10738   conditions encountered by the AM-APEX oceanographic floats that gather
10739   hurricane data and phone home using Iridium satellite modems, which under
10740   certain conditions, can send two packets back to back after a long pause.
10741   In this case the second packet would be ignored because the SOH was skipped
10742   due to the ttflui() call.  But the reworked lookahead/pushback logic broke
10743   Kermit transfers on encrypted connections.  This was fixed 12-13 August
10744   2007.  All of this happened after 8.0.212 Dev.27 was released and before
10745   Dev.28, so no harm done other than the delay.
10746 */
10747     debug(F101,"ttinl max","",max);
10748     debug(F101,"ttinl timo","",timo);
10749
10750 #ifdef NETCMD
10751     if (ttpipe)
10752       fd = fdin;
10753     else
10754 #endif /* NETCMD */
10755       fd = ttyfd;
10756
10757 #ifdef COMMENT
10758     if (xlocal && conchk() > 0)         /* Allow for console interruptions */
10759       return(-1);
10760 #endif /* COMMENT */
10761
10762     *dest = '\0';                       /* Clear destination buffer */
10763     if (timo < 0) timo = 0;             /* Safety */
10764     if (timo) {                         /* Don't time out if timo == 0 */
10765         int xx;
10766         saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
10767         xx = alarm(timo);               /* Set it. */
10768         debug(F101,"ttinl alarm","",xx);
10769     }
10770     if (
10771 #ifdef CK_POSIX_SIG
10772         sigsetjmp(sjbuf,1)
10773 #else
10774         setjmp(sjbuf)
10775 #endif /* CK_POSIX_SIG */
10776         ) {                             /* Timer went off? */
10777         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
10778         /* debug(F110," with",(char *) dest,0); */
10779         ttimoff();                      /* Turn off timer */
10780         return(-1);                     /* and return error code. */
10781     } else {
10782         register int i, n = -1;         /* local variables */
10783         int ccn = 0;
10784 #ifdef PARSENSE
10785         register int flag = 0;
10786         debug(F000,"ttinl start","",start);
10787 #endif /* PARSENSE */
10788
10789         ttpmsk = ttprty ? 0177 : 0377;  /* Set parity stripping mask. */
10790         sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
10791
10792 /* Now read into destination, stripping parity and looking for the */
10793 /* the packet terminator, and also for several Ctrl-C's typed in a row. */
10794
10795         i = 0;                          /* Destination index */
10796         debug(F101,"ttinl eol","",eol);
10797
10798         while (i < max-1) {
10799 #ifdef MYREAD
10800             errno = 0;
10801             /* On encrypted connections myread returns encrypted bytes */
10802             n = myread();
10803             debug(F000,"TTINL myread char","",n);
10804             if (n < 0) {        /* Timeout or i/o error? */
10805 #ifdef DEBUG
10806                 if (deblog) {
10807                     debug(F101,"ttinl myread failure, n","",n);
10808                     debug(F101,"ttinl myread errno","",errno);
10809                 }
10810 #endif /* DEBUG */
10811                 /* Don't let EINTR break packets. */
10812                 if (n == -3) {
10813                     if (errno == EINTR && i > 0) {
10814                         debug(F111,"ttinl EINTR myread i","continuing",i);
10815                         continue;
10816                     } else {
10817                         debug(F110,"ttinl non-EINTR -3","closing",0);
10818                         wasclosed = 1;
10819                         ttimoff();      /* Turn off timer */
10820                         ttclos(0);
10821                         return(n);
10822                     }
10823                 } else if (n == -2 && netconn /* && timo == 0 */ ) {
10824                     /* Here we try to catch broken network connections */
10825                     /* even when ioctl() and read() do not catch them */
10826                     debug(F111,"ttinl network myread failure","closing",n);
10827                     wasclosed = 1;
10828                     ttimoff();
10829                     ttclos(0);
10830                     return(-3);
10831                 }
10832 #ifdef STREAMING
10833                 /* Streaming and no data to read */
10834                 else if (n == 0 && streaming && sndtyp == 'D')
10835                   return(0);
10836 #endif /* STREAMING */
10837                 break;                  /* Break out of while loop */
10838             }
10839
10840 #else /* not MYREAD (is this code used anywhere any more?) */
10841 /*
10842   The non-MYREAD code dates from the 1980s and was needed on certain platforms
10843   where there were no nonblocking reads.  -fdc, 2007/02/22.
10844 */
10845             if ((n = read(fd, &n, 1)) < 1)
10846               break;                    /* Error - break out of while loop */
10847
10848 #endif /* MYREAD */
10849
10850             /* Get here with char in n */
10851
10852 #ifdef CK_ENCRYPTION
10853             if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
10854                 CHAR ch = n;
10855                 ck_tn_decrypt((char *)&ch,1);
10856                 n = ch;
10857                 debug(F000,"TTINL decryp char","",n);
10858             }
10859             pushedback = 0;
10860 #endif /* CK_ENCRYPTION */
10861
10862 #ifdef TCPSOCKET
10863             if (n == IAC &&             /* Handle Telnet options */
10864                 ((xlocal && netconn && IS_TELNET()) ||
10865                 (!xlocal && sstelnet))) {
10866                 n = tt_tnopt(n);
10867                 if (n < 0)
10868                   return(n);
10869 #ifndef NOPARSEN
10870                 else if (n == 1)
10871                   start = stchr;
10872 #endif /* NOPARSEN */
10873                 if (n != 255)           /* No data - go back for next char */
10874                   continue;
10875             }                           /* Quoted IAC - keep going */
10876 #endif /* TCPSOCKET */
10877
10878 #ifdef CKXXCHAR
10879             if (ignflag)
10880               if (dblt[(unsigned) n] & 1) /* Character to ignore? */
10881                 continue;
10882 #endif /* CKXXCHAR */
10883 /*
10884   Use parity mask, rather than always stripping parity, to check for
10885   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
10886   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
10887   unlikely due to run-length encoding.)
10888 */
10889             /* Check cancellation */
10890             if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
10891                 if (++ccn >= xfrnum) {  /* If xfrnum in a row, bail out. */
10892                     if (timo) {         /* Clear timer. */
10893                         ttimoff();
10894                     }
10895                     if (xfrchr < 32)
10896                       printf("^%c...\r\n",(char)(xfrchr+64));
10897                     else
10898                       printf("Canceled...\r\n");
10899                     return(-2);
10900                 }
10901             } else ccn = 0;             /* No cancellation, reset counter, */
10902
10903 #ifdef PARSENSE
10904 /*
10905   Restructured code allows for a new packet to appear somewhere in the
10906   middle of a previous one.  -fdc, 24 Feb 2007.
10907 */
10908             if ((n & sopmask) == start) { /* Start of Packet */
10909                 debug(F101,"ttinl SOP i","",i);
10910                 flag = 1;               /* Flag that we are in a packet */
10911                 havelen = 0;            /* Invalidate previous length */
10912                 pktlen = -1;            /* (if any) in case we were */
10913                 lplen = 0;              /* alread processand a packet */
10914                 i = 0;                  /* and reset the dest buffer pointer */
10915             }
10916             if (flag == 0) {            /* No SOP yet... */
10917                 debug(F000,"ttinl skipping","",n);
10918                 continue;
10919             }
10920             dest[i++] = n & ttpmsk;
10921 /*
10922   If we have not been instructed to wait for a turnaround character, we can go
10923   by the packet length field.  If turn != 0, we must wait for the end of line
10924   (eol) character before returning.  This is an egregious violation of all
10925   principles of layering...  (Less egregious in C-Kermit 9.0, in which we go
10926   by the length field but also look for the eol in case it arrives early,
10927   e.g. if the length field was corrupted upwards.)
10928 */
10929             if (!havelen) {
10930                 if (i == 2) {
10931                     if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
10932                       return(-1);       /* fdc - 13 Apr 2010 */
10933                     pktlen = xunchar(dest[1] & 0x7f);
10934                     if (pktlen > 94)    /* Rubout in length field */
10935                       return(-1);       /* fdc - 13 Apr 2010 */
10936                     if (pktlen > 1) {
10937                         havelen = 1;
10938                         debug(F101,"ttinl pktlen value","",pktlen);
10939                     }
10940                 } else if (i == 5 && pktlen == 0) {
10941                     lplen = xunchar(dest[4] & 0x7f);
10942                 } else if (i == 6 && pktlen == 0) {
10943                     pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
10944                     havelen = 1;
10945                     debug(F101,"ttinl extended length","",pktlen);
10946                 }
10947             }
10948
10949 /*
10950   Suppose we looked at the sequence number here and found it was out of
10951   range?  This would mean either (a) incoming packets had SOP unprefixed
10952   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
10953   practice, let's ignore it.  So what should we do here if we know the
10954   packet is damaged?
10955
10956    1. Nothing -- keep trying to read the packet till we find what we think
10957       is the end, or we time out, and let the upper layer decide what to
10958       do.  But since either the packet is corrupt or we are out of sync,
10959       our criterion for finding the end does not apply and we are likely
10960       to time out (or swallow a piece of the next packet) if our assumed
10961       length is too long.  (This was the behavior prior to version 7.0.)
10962
10963    2. set flag = 0 and continue?  This would force us to wait for the
10964       next packet to come in, and therefore (in the nonwindowing case),
10965       would force a timeout in the other Kermit.
10966
10967    3. set flag = 0 and continue, but only if the window size is > 1 and
10968       the window is not blocked?  Talk about cheating!
10969
10970    4. Return a failure code and let the upper layer decide what to do.
10971       This should be equivalent to 3, but without the cheating.  So let's
10972       do it that way...  But note that we must ignore the parity bit
10973       in case this is the first packet and we have not yet run parchk().
10974 */
10975             if (i == 3) {               /* Peek at sequence number */
10976                 x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
10977                 if (x < 0 || x > 63) {
10978                     debug(F111,"ttinl bad seq",dest,x);
10979                     if (timo) ttimoff();
10980                     return(-1);         /* return a nonfatal error */
10981                 }
10982             }
10983
10984 #else /* PARSENSE */
10985             dest[i++] = n & ttpmsk;
10986 #endif /* PARSENSE */
10987
10988     /* Check for end of packet */
10989
10990             if (
10991                 ((n & ttpmsk) == eol)   /* Always break on the eol char */
10992 #ifdef PARSENSE
10993                  ||                     /* fdc - see notes of 13 Apr 2010 */
10994 /*
10995   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
10996   This allows packet terminators and handshake characters to appear
10997   literally inside a packet data field.
10998 */
10999                 (havelen && (i > pktlen+1) &&
11000                  (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
11001
11002 #endif /* PARSENSE */
11003                 ) {
11004 /*
11005   Here we have either read the last byte of the packet based on its length
11006   field, or else we have read the packet terminator (eol) or the half-duplex
11007   line-turnaround char (turn).
11008 */
11009 #ifndef PARSENSE
11010                 debug(F101,"ttinl got eol","",eol); /* (or turn) */
11011                 dest[i] = '\0';         /* Yes, terminate the string, */
11012                 /* debug(F101,"ttinl i","",i); */
11013
11014 #else  /* PARSENSE */
11015
11016 #ifdef DEBUG
11017                 if (deblog) {
11018                     if ((n & ttpmsk) != eol) {
11019                         debug(F101,"ttinl EOP length","",pktlen);
11020                         debug(F000,"ttinl EOP current char","",n);
11021                         debug(F101,"ttinl EOP packet buf index","",i);
11022                     } else debug(F101,"ttinl got eol","",eol);
11023                 }
11024 #endif /* DEBUG */
11025
11026 #ifdef MYREAD
11027 /*
11028   The packet was read based on its length.  This leaves the packet terminator
11029   unread, and so ttchk() will always return at least 1 because of this,
11030   possibly giving a false positive to the "is there another packet waiting?"
11031   test.  But if we know the terminator (or any other interpacket junk) is
11032   there, we can safely get rid of it.
11033
11034   NOTE: This code reworked to (a) execute even if the debug log isn't active;
11035   and (b) actually work.  -fdc, 2007/02/22.  And again 2007/08/12-13 to also
11036   work on encrypted connections.
11037 */      
11038                 debug(F101,"TTINL my_count","",my_count);
11039                 if ((n & ttpmsk) != eol) { /* Not the packet terminator */
11040                     int x;
11041                     while (my_count > 0) {
11042                         x = myread();      /* (was ttinc(0) */
11043                         debug(F000,"TTINL lkread char","",x);
11044 #ifdef CK_ENCRYPTION
11045                         if (TELOPT_U(TELOPT_ENCRYPTION)) {
11046                             CHAR ch = x;
11047                             ck_tn_decrypt((char *)&ch,1);
11048                             x = ch;
11049                             debug(F000,"TTINL lkdecr char","",x); 
11050                         }
11051 #endif  /* CK_ENCRYPTION */
11052                         /*
11053                           Note: while it might seem more elegant to simply
11054                           push back the encrypted byte, that desynchronizes
11055                           the decryption stream; the flag is necessary so we
11056                           don't try to decrypt the same byte twice.
11057                         */
11058                         if ((x & ttpmsk) == start) { /* Start of next packet */
11059                             myunrd(x);  /* Push back the decrypted byte */
11060                             pushedback = 1; /* And set flag */
11061                             debug(F000,"TTINL lkpush char","",x);
11062                             break;
11063                         }
11064                     }
11065                 }
11066 #endif /* MYREAD */
11067
11068                 dest[i] = '\0';         /* Terminate the string, */
11069                 if (needpchk) {         /* Parity checked yet? */
11070                     if (ttprty == 0) {  /* No, check. */
11071                         if ((ttprty = parchk(dest,start,i)) > 0) {
11072                             int j;
11073                             debug(F101,"ttinl senses parity","",ttprty);
11074                             debug(F110,"ttinl packet before",dest,0);
11075                             ttpmsk = 0x7f;
11076                             for (j = 0; j < i; j++)
11077                               dest[j] &= 0x7f;  /* Strip parity from packet */
11078                             debug(F110,"ttinl packet after ",dest,0);
11079                         } else ttprty = 0; /* Restore if parchk error */
11080                     }
11081                     sopmask = ttpmsk;
11082                     needpchk = 0;
11083                 }
11084 #endif /* PARSENSE */
11085
11086                 if (timo)               /* Turn off timer if it was on */
11087                   ttimoff();
11088                 ckhexdump("ttinl got",dest,i);
11089
11090 #ifdef STREAMING
11091                 /* ttinl() was called because there was non-packet */
11092                 /* data sitting in the back channel.  Ignore it.   */
11093                 if (streaming && sndtyp == 'D')
11094                   return(-1);
11095 #endif /* STREAMING */
11096                 return(i);
11097             }
11098         } /* End of while() */
11099         ttimoff();
11100         return(n);
11101     }
11102 }
11103 #endif /* NOXFER */
11104
11105 /*  T T I N C --  Read a character from the communication line  */
11106 /*
11107  On success, returns the character that was read, >= 0.
11108  On failure, returns -1 or other negative myread error code,
11109    or -2 if connection is broken or ttyfd < 0.
11110    or -3 if session limit has expired,
11111    or -4 if something or other...
11112  NOTE: The API does not provide for ttinc() returning a special code
11113  upon timeout, but we need it.  So for this we have a global variable,
11114  ttinctimo.
11115 */
11116 static int ttinctimo = 0;               /* Yuk */
11117
11118 int
11119 ttinc(timo) int timo; {
11120
11121     int n = 0, fd;
11122     int is_tn = 0;
11123     CHAR ch = 0;
11124
11125     ttinctimo = 0;
11126
11127     if (ttyfd < 0) return(-2);          /* Not open. */
11128
11129     is_tn = (xlocal && netconn && IS_TELNET()) ||
11130             (!xlocal && sstelnet);
11131
11132 #ifdef TTLEBUF
11133     if (ttpush >= 0) {
11134         debug(F111,"ttinc","ttpush",ttpush);
11135         ch = ttpush;
11136         ttpush = -1;
11137         return(ch);
11138     }
11139     if (le_data) {
11140         if (le_getchar(&ch) > 0) {
11141             debug(F111,"ttinc le_getchar","ch",ch);
11142             return(ch);
11143         }
11144     }
11145 #endif /* TTLEBUF */
11146
11147 #ifdef NETCMD
11148     if (ttpipe)
11149       fd = fdin;
11150     else
11151 #endif /* NETCMD */
11152       fd = ttyfd;
11153
11154     if ((timo <= 0)                     /* Untimed. */
11155 #ifdef MYREAD
11156         || (my_count > 0)               /* Buffered char already waiting. */
11157 #endif /* MYREAD */
11158         ) {
11159 #ifdef MYREAD
11160         /* Comm line failure returns -1 thru myread, so no &= 0377 */
11161         n = myread();                   /* Wait for a character... */
11162         /* debug(F000,"ttinc MYREAD n","",n); */
11163 #ifdef CK_ENCRYPTION
11164         /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
11165         if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11166             ch = n;
11167             ck_tn_decrypt((char *)&ch,1);
11168             n = ch;
11169         }
11170 #endif /* CK_ENCRYPTION */
11171
11172 #ifdef NETPTY
11173         if (ttpty && n < 0) {
11174             debug(F101,"ttinc error on pty","",n);
11175             ttclos(0);
11176             return(n);
11177         }
11178 #endif /* NETPTY */
11179
11180 #ifdef TNCODE
11181         if ((n > -1) && is_tn)
11182           return((unsigned)(n & 0xff));
11183         else
11184 #endif /* TNCODE */
11185           return(n < 0 ? n : (unsigned)(n & ttpmsk));
11186
11187 #else  /* MYREAD */
11188
11189         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
11190         /* Shouldn't have to loop in ver 5A. */
11191 #ifdef NETCONN
11192           if (netconn) {                /* Special handling for net */
11193               netclos();                /* If read() returns 0 it means */
11194               netconn = 0;              /* the connection has dropped. */
11195               errno = ENOTCONN;
11196               return(-2);
11197           }
11198 #endif /* NETCONN */
11199           ;
11200         /* debug(F101,"ttinc","",ch); */
11201 #ifdef TNCODE
11202         if ((n > 0) && is_tn) {
11203 #ifdef CK_ENCRYPTION
11204             if (TELOPT_U(TELOPT_ENCRYPTION)) {
11205                 ck_tn_decrypt(&ch,1);
11206                 n = ch;
11207             }
11208 #endif /* CK_ENCRYPTION */
11209             return((unsigned)(ch & 0xff));
11210         } else
11211 #endif /* TNCODE */
11212         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
11213 #endif /* MYREAD */
11214
11215     } else {                            /* Timed read */
11216
11217         int oldalarm;
11218         saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
11219         oldalarm = alarm(timo);         /* Set alarm, save old one. */
11220         if (
11221 #ifdef CK_POSIX_SIG
11222             sigsetjmp(sjbuf,1)
11223 #else
11224             setjmp(sjbuf)
11225 #endif /* CK_POSIX_SIG */
11226             ) {                         /* Timer expired */
11227             ttinctimo = 1;
11228             n = -1;                     /* set flag */
11229         } else {
11230 #ifdef MYREAD
11231             n = myread();               /* If managing own buffer... */
11232             debug(F101,"ttinc myread","",n);
11233             ch = n;
11234 #else
11235             n = read(fd,&ch,1);         /* Otherwise call the system. */
11236             if (n == 0) n = -1;
11237             debug(F101,"ttinc read","",n);
11238 #endif /* MYREAD */
11239
11240 #ifdef CK_ENCRYPTION
11241             if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11242                 ck_tn_decrypt((char *)&ch,1);
11243             }
11244 #endif /* CK_ENCRYPTION */
11245             if (n >= 0)
11246               n = (unsigned) (ch & 0xff);
11247             else
11248               n = (n < 0) ? -4 : -2;    /* Special return codes. */
11249         }
11250         ttimoff();                      /* Turn off the timer */
11251         if (oldalarm > 0) {
11252             if (n == -1)                /* and restore any previous alarm */
11253               oldalarm -= timo;
11254             if (oldalarm < 0)           /* adjusted by our timeout interval */
11255               oldalarm = 0;
11256             if (oldalarm) {
11257                 debug(F101,"ttinc restoring oldalarm","",oldalarm);
11258                 alarm(oldalarm);
11259             }
11260         }
11261 #ifdef NETCONN
11262         if (netconn) {
11263             if (n == -2) {              /* read() returns 0 */
11264                 netclos();              /* on network read failure */
11265                 netconn = 0;
11266                 errno = ENOTCONN;
11267             }
11268         }
11269 #endif  /* NETCONN */
11270 #ifdef TNCODE
11271         if ((n > -1) && is_tn)
11272           return((unsigned)(n & 0xff));
11273         else
11274 #endif /* TNCODE */
11275           /* Return masked char or neg. */
11276           return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
11277     }
11278 }
11279
11280 /*  S N D B R K  --  Send a BREAK signal of the given duration  */
11281
11282 static int
11283 #ifdef CK_ANSIC
11284 sndbrk(int msec) {                      /* Argument is milliseconds */
11285 #else
11286 sndbrk(msec) int msec; {
11287 #endif /* CK_ANSIC */
11288 #ifndef POSIX
11289     int x, n;
11290 #endif /* POSIX */
11291
11292 #ifdef OXOS
11293 #define BSDBREAK
11294 #endif /* OXOS */
11295
11296 #ifdef ANYBSD
11297 #define BSDBREAK
11298 #endif /* ANYBSD */
11299
11300 #ifdef BSD44
11301 #define BSDBREAK
11302 #endif /* BSD44 */
11303
11304 #ifdef COHERENT
11305 #ifdef BSDBREAK
11306 #undef BSDBREAK
11307 #endif /* BSDBREAK */
11308 #endif /* COHERENT */
11309
11310 #ifdef BELLV10
11311 #ifdef BSDBREAK
11312 #undef BSDBREAK
11313 #endif /* BSDBREAK */
11314 #endif /* BELLV10 */
11315
11316 #ifdef PROVX1
11317     char spd;
11318 #endif /* PROVX1 */
11319
11320     debug(F101,"ttsndb ttyfd","",ttyfd);
11321     if (ttyfd < 0) return(-1);          /* Not open. */
11322
11323 #ifdef Plan9
11324     return p9sndbrk(msec);
11325 #else
11326 #ifdef NETCONN
11327 #ifdef NETCMD
11328     if (ttpipe)                         /* Pipe */
11329       return(ttoc('\0'));
11330 #endif /* NETCMD */
11331 #ifdef NETPTY
11332     if (ttpty)
11333       return(ttoc('\0'));
11334 #endif /* NETPTY */
11335     if (netconn)                        /* Send network BREAK */
11336       return(netbreak());
11337 #endif /* NETCONN */
11338
11339     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
11340
11341 #ifdef POSIX                            /* Easy in POSIX */
11342     {
11343         int x;
11344         debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
11345         errno = 0;
11346         x = tcsendbreak(ttyfd,msec / 375);
11347         debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
11348         return(x);
11349     }
11350 #else
11351 #ifdef PROVX1
11352     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
11353     spd = ttbuf.sg_ospeed;              /* Save speed */
11354     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
11355     stty(ttyfd,&ttbuf);                 /*  ... */
11356     n = (int)strlen(brnuls);            /* Send the right number of nulls */
11357     x = msec / 91;
11358     if (x > n) x = n;
11359     write(ttyfd,brnuls,n);
11360     ttbuf.sg_ospeed = spd;              /* Restore speed */
11361     stty(ttyfd,&ttbuf);                 /*  ... */
11362     return(0);
11363 #else
11364 #ifdef aegis
11365     sio_$control((short)ttyfd, sio_$send_break, msec, st);
11366     return(0);
11367 #else
11368 #ifdef BSDBREAK
11369     n = FWRITE;                         /* Flush output queue. */
11370 /* Watch out for int vs long problems in &n arg! */
11371     debug(F101,"sndbrk BSDBREAK","",msec);
11372     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
11373     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
11374         perror("Can't send BREAK");
11375         return(-1);
11376     }
11377     x = msleep(msec);                    /* Sleep for so many milliseconds */
11378     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
11379         perror("BREAK stuck!!!");
11380         doexit(BAD_EXIT,-1);            /* Get out, closing the line. */
11381                                         /*   with bad exit status */
11382     }
11383     return(x);
11384 #else
11385 #ifdef ATTSV
11386 /*
11387   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
11388   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
11389   but there's no way for this code to know for sure.)
11390 */
11391     debug(F101,"sndbrk ATTSV","",msec);
11392     x = msec / 275;
11393     for (n = 0; n < x; n++) {
11394         /* Reportedly the cast breaks this function on some systems */
11395         /* But then why was it here in the first place? */
11396         if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
11397             perror("Can't send BREAK");
11398             return(-1);
11399         }
11400     }
11401     return(0);
11402 #else
11403 #ifdef  V7
11404     debug(F101,"sndbrk V7","",msec);
11405     return(genbrk(ttyfd,250));          /* Simulate a BREAK */
11406 #else
11407     debug(F101,"sndbrk catchall","",msec);
11408     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
11409     return(0);
11410 #endif /* V7 */
11411 #endif /* BSDBREAK */
11412 #endif /* ATTSV */
11413 #endif /* aegis */
11414 #endif /* PROVX1 */
11415 #endif /* POSIX */
11416 #endif /* Plan9 */
11417 }
11418
11419 /*  T T S N D B  --  Send a BREAK signal  */
11420
11421 int
11422 ttsndb() {
11423 #ifdef TN_COMPORT
11424     if (netconn && istncomport())
11425       return((tnsndb(275L) >= 0) ? 0 : -1);
11426     else
11427 #endif /* TN_COMPORT */
11428       return(sndbrk(275));
11429 }
11430
11431 /*  T T S N D L B  --  Send a Long BREAK signal  */
11432
11433 int
11434 ttsndlb() {
11435 #ifdef TN_COMPORT
11436     if (netconn && istncomport())
11437       return((tnsndb(1800L) >= 0) ? 0 : -1);
11438     else
11439 #endif /* TN_COMPORT */
11440     return(sndbrk(1500));
11441 }
11442
11443 /*  M S L E E P  --  Millisecond version of sleep().  */
11444
11445 /*
11446   Call with number of milliseconds (thousandths of seconds) to sleep.
11447   Intended only for small intervals.  For big ones, just use sleep().
11448   Highly system-dependent.
11449   Returns 0 always, even if it didn't work.
11450 */
11451
11452 /* Define MSLFTIME for systems that must use an ftime() loop. */
11453 #ifdef ANYBSD                           /* For pre-4.2 BSD versions */
11454 #ifndef BSD4
11455 #define MSLFTIME
11456 #endif /* BSD4 */
11457 #endif /* ANYBSD */
11458
11459 #ifdef TOWER1                           /* NCR Tower OS 1.0 */
11460 #define MSLFTIME
11461 #endif /* TOWER1 */
11462
11463 #ifdef COHERENT         /* Coherent... */
11464 #ifndef _I386           /* Maybe Coherent/386 should get this, too */
11465 #define MSLFTIME        /* Opinions are divided */
11466 #endif /* _I386 */
11467 #endif /* COHERENT */
11468
11469 #ifdef COMMENT
11470 #ifdef GETMSEC
11471
11472 /* Millisecond timer */
11473
11474 static long msecbase = 0L;              /* Unsigned long not portable */
11475
11476 long
11477 getmsec() {                             /* Milliseconds since base time */
11478     struct timeval xv;
11479     struct timezone xz;
11480     long secs, msecs;
11481     if (
11482 #ifdef GTODONEARG
11483         gettimeofday(&tv)
11484 #else
11485 #ifdef PTX
11486         gettimeofday(&tv, NULL)
11487 #else
11488         gettimeofday(&tv, &tz)
11489 #endif /* PTX */
11490 #endif /* GTODONEARG */
11491         < 0)
11492       return(-1);
11493     if (msecbase == 0L) {               /* First call, set base time. */
11494         msecbase = tv.tv_sec;
11495         debug(F101,"getmsec base","",msecbase);
11496     }
11497     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
11498 }
11499 #endif /* GETMSEC */
11500 #endif /* COMMENT */
11501
11502 #ifdef SELECT
11503 int
11504 ttwait(fd, secs) int fd, secs; {
11505     int x;
11506     fd_set rfds;
11507     FD_ZERO(&rfds);
11508     FD_SET(fd,&rfds);
11509     tv.tv_sec = secs;
11510     tv.tv_usec = 0L;
11511     errno = 0;
11512     if ((x = select(FD_SETSIZE,
11513 #ifdef HPUX9
11514                     (int *)
11515 #else
11516 #ifdef HPUX1000
11517                     (int *)
11518 #endif /* HPUX1000 */
11519 #endif /* HPUX9 */
11520                     &rfds,
11521                     0, 0, &tv)) < 0) {
11522         debug(F101,"ttwait select errno","",errno);
11523         return(0);
11524     } else {
11525         debug(F101,"ttwait OK","",errno);
11526         x = FD_ISSET(fd, &rfds);
11527         debug(F101,"ttwait select x","",x);
11528         return(x ? 1 : 0);
11529     }
11530 }
11531 #endif /* SELECT */
11532
11533 int
11534 msleep(m) int m; {
11535 /*
11536   Other possibilities here are:
11537    nanosleep(), reportedly defined in POSIX.4.
11538    sginap(), IRIX only (back to what IRIX version I don't know).
11539 */
11540 #ifdef Plan9
11541     return _SLEEP(m);
11542 #else
11543 #ifdef BEOSORBEBOX
11544     snooze(m*1000);
11545 #else /* BEOSORBEBOX */
11546 #ifdef SELECT
11547     int t1, x;
11548     debug(F101,"msleep SELECT 1","",m);
11549     if (m <= 0) return(0);
11550     if (m >= 1000) {                    /* Catch big arguments. */
11551         sleep(m/1000);
11552         m = m % 1000;
11553         if (m < 10) return(0);
11554     }
11555     debug(F101,"msleep SELECT 2","",m);
11556 #ifdef BELLV10
11557     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
11558     debug(F101,"msleep BELLV10 select","",x);
11559 #else /* BELLV10 */
11560 #ifdef HPUX9
11561     gettimeofday(&tv, &tz);
11562 #else
11563
11564 #ifndef COHERENT
11565 #ifdef GTODONEARG
11566     if (gettimeofday(&tv) < 0)
11567 #else
11568 #ifdef PTX
11569     if (gettimeofday(&tv,NULL) < 0)
11570 #else
11571 #ifdef NOTIMEZONE
11572     if (gettimeofday(&tv, NULL) < 0)    /* wonder what this does... */
11573 #else
11574     if (gettimeofday(&tv, &tz) < 0)
11575 #endif /* NOTIMEZONE */
11576 #endif /* PTX */
11577 #endif /* GTODONEARG */
11578       return(-1);
11579     t1 = tv.tv_sec;                     /* Seconds */
11580 #endif /* COHERENT */
11581 #endif /* HPUX9 */
11582     tv.tv_sec = 0;                      /* Use select() */
11583     tv.tv_usec = m * 1000L;
11584 #ifdef BSD44
11585     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11586     debug(F101,"msleep BSD44 select","",x);
11587 #else /* BSD44 */
11588 #ifdef __linux__
11589     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11590     debug(F101,"msleep __linux__ select","",x);
11591 #else /* __linux__ */
11592 #ifdef BSD43
11593     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11594     debug(F101,"msleep BSD43 select","",x);
11595 #else /* BSD43 */
11596 #ifdef QNX6
11597     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11598     debug(F101,"msleep QNX6 select","",x);
11599 #else /* QNX6 */
11600 #ifdef QNX
11601     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11602     debug(F101,"msleep QNX select","",x);
11603 #else /* QNX */
11604 #ifdef COHERENT
11605     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11606     debug(F101,"msleep COHERENT select","",x);
11607 #else /* COHERENT */
11608 #ifdef HPUX1000                         /* 10.00 only, not 10.10 or later */
11609     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11610     debug(F101,"msleep HP-UX 10.00 select","",x);
11611 #else /* HPUX1000 */
11612 #ifdef SVR4
11613     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11614     debug(F101,"msleep SVR4 select","",x);
11615 #else /* SVR4 */
11616 #ifdef OSF40
11617     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11618     debug(F101,"msleep OSF40 select","",x);
11619 #else /* OSF40 */
11620 #ifdef PTX
11621     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11622     debug(F101,"msleep OSF40 select","",x);
11623 #else
11624     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11625     debug(F101,"msleep catch-all select","",x);
11626 #endif /* PTX */
11627 #endif /* OSF40 */
11628 #endif /* HP1000 */
11629 #endif /* SVR4 */
11630 #endif /* COHERENT */
11631 #endif /* QNX */
11632 #endif /* QNX6 */
11633 #endif /* BSD43 */
11634 #endif /* __linux__ */
11635 #endif /* BSD44 */
11636 #endif /* BELLV10 */
11637     return(0);
11638
11639 #else                                   /* Not SELECT */
11640 #ifdef CK_POLL                          /* We have poll() */
11641     struct pollfd pfd;                  /* Supply a valid address for poll() */
11642
11643 #ifdef ODT30                            /* But in SCO ODT 3.0 */
11644 #ifdef NAP                              /* we should use nap() instead */
11645     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
11646     nap((long)m);                          /* seems to break dialing. */
11647     return(0);
11648 #else
11649     debug(F101,"msleep ODT 3.0 POLL","",m);
11650     poll(&pfd, 0, m);
11651     return(0);
11652 #endif /* NAP */
11653 #else
11654     debug(F101,"msleep POLL","",m);
11655     poll(&pfd, 0, m);
11656     return(0);
11657 #endif /* ODT30 */
11658
11659 /*
11660   We could handle the above more cleanly by just letting nap() always
11661   take precedence over poll() in this routine, but there is no way to know
11662   whether that would break something else.
11663 */
11664
11665 #else                                   /* Not POLL */
11666 #ifdef USLEEP
11667 /*
11668   "This routine is implemented using setitimer(2); it requires eight
11669   system calls...".  In other words, it might take 5 minutes to sleep
11670   10 milliseconds...
11671 */
11672     debug(F101,"msleep USLEEP","",m);
11673     if (m >= 1000) {                    /* Catch big arguments. */
11674         sleep(m/1000);
11675         m = m % 1000;
11676         if (m < 10) return(0);
11677     }
11678     usleep((unsigned int)(m * 1000));
11679     return(0);
11680 #else
11681 #ifdef aegis
11682     time_$clock_t dur;
11683     debug(F101,"msleep aegis","",m);
11684     dur.c2.high16 = 0;
11685     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
11686     time_$wait(time_$relative, dur, st);
11687     return(0);
11688 #else
11689 #ifdef PROVX1
11690     debug(F101,"msleep Venix","",m);
11691     if (m <= 0) return(0);
11692     sleep(-((m * 60 + 500) / 1000));
11693     return(0);
11694 #else
11695 #ifdef NAP
11696     debug(F101,"msleep NAP","",m);
11697     nap((long)m);
11698     return(0);
11699 #else
11700 #ifdef ATTSV
11701 #ifndef BSD44
11702     extern long times();                /* Or #include <times.h> ? */
11703 #endif /* BSD44 */
11704     long t1, t2, tarray[4];
11705     int t3;
11706     char *cp = getenv("HZ");
11707     int CLOCK_TICK;
11708     int hertz;
11709
11710     if (cp && (hertz = atoi(cp))) {
11711         CLOCK_TICK  = 1000 / hertz;
11712     } else {                            /* probably single user mode */
11713 #ifdef HZ
11714         CLOCK_TICK  = 1000 / HZ;
11715 #else
11716         static warned = 0;
11717         /* HZ always exists in, for instance, SCO Xenix, so you don't have to
11718          * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
11719          * have Xenix, you have should have nap(), so the best is to use -DNAP
11720          * in the makefile. Most systems have HZ.
11721          */
11722         CLOCK_TICK = 17;                /* 1/60 sec */
11723         if (!warned) {
11724           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
11725                  1000 / CLOCK_TICK);
11726           warned = 1;
11727         }
11728 #endif /* !HZ */
11729     }
11730     debug(F101,"msleep ATTSV","",m);
11731     if (m <= 0) return(0);
11732     if (m >= 1000) {                    /* Catch big arguments. */
11733         sleep(m/1000);
11734         m = m % 1000;
11735         if (m < 10) return(0);
11736     }
11737     if ((t1 = times(tarray)) < 0) return(-1);
11738     while (1) {
11739         if ((t2 = times(tarray)) < 0) return(-1);
11740         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
11741         if (t3 > m) return(t3);
11742     }
11743 #else /* Not ATTSV */
11744 #ifdef MSLFTIME                         /* Use ftime() loop... */
11745     int t1, t3 = 0;
11746     debug(F101,"msleep MSLFTIME","",m);
11747     if (m <= 0) return(0);
11748     if (m >= 1000) {                    /* Catch big arguments. */
11749         sleep(m/1000);
11750         m = m % 1000;
11751         if (m < 10) return(0);
11752     }
11753 #ifdef QNX
11754     ftime(&ftp);                        /* void ftime() in QNX */
11755 #else
11756     if (ftime(&ftp) < 0) return(-1);    /* Get base time. */
11757 #endif /* QNX */
11758     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
11759     while (1) {
11760         ftime(&ftp);                    /* Get current time and compare. */
11761         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
11762         if (t3 > m) return(0);
11763     }
11764 #else
11765 /* This includes true POSIX, which has no way to do this. */
11766     debug(F101,"msleep busy loop","",m);
11767     if (m >= 1000) {                    /* Catch big arguments. */
11768         sleep(m/1000);
11769         m = m % 1000;
11770         if (m < 10) return(0);
11771     }
11772     if (m > 0) while (m > 0) m--;       /* Just a dumb busy loop */
11773     return(0);
11774 #endif /* MSLFTIME */
11775 #endif /* ATTSV */
11776 #endif /* NAP */
11777 #endif /* PROVX1 */
11778 #endif /* aegis */
11779 #endif /* CK_POLL */
11780 #endif /* SELECT */
11781 #endif /* BEOSORBEBOX */
11782 #endif /* USLEEP */
11783 #endif /* Plan9 */
11784 }
11785
11786 /*  R T I M E R --  Reset elapsed time counter  */
11787
11788 VOID
11789 rtimer() {
11790     tcount = time( (time_t *) 0 );
11791 }
11792
11793
11794 /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
11795
11796 int
11797 gtimer() {
11798     int x;
11799     x = (int) (time( (time_t *) 0 ) - tcount);
11800     debug(F101,"gtimer","",x);
11801     return( (x < 0) ? 0 : x );
11802 }
11803
11804 #ifdef GFTIMER
11805 /*
11806   Floating-point timers.  Require not only floating point support, but
11807   also gettimeofday().
11808 */
11809 static struct timeval tzero;
11810
11811 VOID
11812 rftimer() {
11813 #ifdef GTODONEARG                       /* Account for Mot's definition */
11814     (VOID) gettimeofday(&tzero);
11815 #else
11816     (VOID) gettimeofday(&tzero, (struct timezone *)0);
11817 #endif /* GTODONEARG */
11818 }
11819
11820 CKFLOAT
11821 gftimer() {
11822     struct timeval tnow, tdelta;
11823     CKFLOAT s;
11824 #ifdef DEBUG
11825     char fpbuf[64];
11826 #endif /* DEBUG */
11827 #ifdef GTODONEARG                       /* Account for Mot's definition */
11828     (VOID) gettimeofday(&tnow);
11829 #else
11830     (VOID) gettimeofday(&tnow, (struct timezone *)0);
11831 #endif /* GTODONEARG */
11832
11833     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
11834     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
11835
11836     if (tdelta.tv_usec < 0) {
11837         tdelta.tv_sec--;
11838         tdelta.tv_usec += 1000000;
11839     }
11840     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
11841     if (s < GFMINTIME)
11842       s = GFMINTIME;
11843 #ifdef DEBUG
11844     if (deblog) {
11845         sprintf(fpbuf,"%f",s);
11846         debug(F110,"gftimer",fpbuf,0);
11847     }
11848 #endif /* DEBUG */
11849     return(s);
11850 }
11851 #endif /* GFTIMER */
11852
11853 /*  Z T I M E  --  Return asctime()-format date/time string  */
11854 /*
11855   NOTE: as a side effect of calling this routine, we can also set the
11856   following two variables, giving the micro- and milliseconds (fractions of
11857   seconds) of the clock time.  Currently this is done only in BSD-based builds
11858   that use gettimeofday().  When these variables are not filled in, they are
11859   left with a value of -1L.
11860 */
11861 static char asctmbuf[64];
11862
11863 VOID
11864 ztime(s) char **s; {
11865
11866 #ifdef GFTIMER
11867 /*
11868   The gettimeofday() method, which also sets ztmsec and ztusec, works for
11869   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
11870   and extern declarations for them are in ckcdeb.h; thus they are
11871   declared in this file by inclusion of ckcdeb.h.
11872 */
11873     char *asctime();
11874     struct tm *localtime();
11875     struct tm *tp;
11876     ztmsec = -1L;
11877     ztusec = -1L;
11878
11879     if (!s)
11880       debug(F100,"ztime s==NULL","",0);
11881
11882 #ifdef GTODONEARG
11883     /* No 2nd arg in Motorola SV88 and some others */
11884     if (gettimeofday(&tv) > -1)
11885 #else
11886 #ifndef COHERENT
11887 #ifdef PTX
11888     if (gettimeofday(&tv,NULL) > -1)
11889 #else
11890 #ifdef NOTIMEZONE
11891     if (gettimeofday(&tv, NULL) > -1)   /* wonder what this does... */
11892 #else
11893     if (gettimeofday(&tv, &tz) > -1)
11894 #endif /* NOTIMEZONE */
11895 #endif /* PTX */
11896 #endif /* COHERENT */
11897 #endif /* GTODONEARG */
11898       {                                 /* Fill in tm struct */
11899         ztusec = tv.tv_usec;            /* Microseconds */
11900         ztmsec = ztusec / 1000L;        /* Milliseconds */
11901 #ifdef HPUX9
11902         {
11903             time_t zz;
11904             zz = tv.tv_sec;
11905             tp = localtime(&zz);        /* Convert to local time */
11906         }
11907 #else
11908 #ifdef HPUX1000
11909         {
11910             time_t zz;
11911             zz = tv.tv_sec;
11912             tp = localtime(&zz);
11913         }
11914 #else
11915 #ifdef LINUX
11916         {   /* avoid unaligned access trap on 64-bit platforms */
11917             time_t zz;
11918             zz = tv.tv_sec;
11919             tp = localtime(&zz);
11920         }
11921 #else
11922 #ifdef MACOSX
11923         tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
11924 #else
11925         tp = localtime(&tv.tv_sec);
11926 #endif /* MACOSX */
11927 #endif /* LINUX */
11928 #endif /* HPUX1000 */
11929 #endif /* HPUX9 */
11930         if (s) {
11931             char * s2;
11932             s2 = asctime(tp);           /* Convert result to ASCII string */
11933             asctmbuf[0] = '\0';
11934             if (s2) ckstrncpy(asctmbuf,s2,64);
11935             *s = asctmbuf;
11936             debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
11937         }
11938     }
11939 #else  /* Not GFTIMER */
11940
11941 #undef ZTIMEV7                          /* Which systems need to use */
11942 #ifdef COHERENT                         /* old UNIX Version 7 way... */
11943 #define ZTIMEV7
11944 #endif /* COHERENT */
11945 #ifdef TOWER1
11946 #define ZTIMEV7
11947 #endif /* TOWER1 */
11948 #ifdef ANYBSD
11949 #ifndef BSD42
11950 #define ZTIMEV7
11951 #endif /* BSD42 */
11952 #endif /* ANYBSD */
11953 #ifdef V7
11954 #ifndef MINIX
11955 #define ZTIMEV7
11956 #endif /* MINIX */
11957 #endif /* V7 */
11958 #ifdef POSIX
11959 #define ZTIMEV7
11960 #endif /* POSIX */
11961
11962 #ifdef HPUX1020
11963 /*
11964   Prototypes are in <time.h>, included above.
11965 */
11966     time_t clock_storage;
11967     clock_storage = time((void *) 0);
11968     if (s) {
11969         *s = ctime(&clock_storage);
11970         debug(F110,"ztime: HPUX 10.20",*s,0);
11971     }
11972 #else
11973 #ifdef ATTSV                            /* AT&T way */
11974 /*  extern long time(); */              /* Theoretically these should */
11975     char *ctime();                      /* already been dcl'd in <time.h> */
11976     time_t clock_storage;
11977     clock_storage = time(
11978 #ifdef IRIX60
11979                          (time_t *)
11980 #else
11981 #ifdef BSD44
11982                          (time_t *)
11983 #else
11984                          (long *)
11985 #endif /* BSD44 */
11986 #endif /* IRIX60 */
11987                          0 );
11988     if (s) {
11989         *s = ctime( &clock_storage );
11990         debug(F110,"ztime: ATTSV",*s,0);
11991     }
11992 #else
11993 #ifdef PROVX1                           /* Venix 1.0 way */
11994     int utime[2];
11995     time(utime);
11996     if (s) {
11997         *s = ctime(utime);
11998         debug(F110,"ztime: PROVX1",*s,0);
11999     }
12000 #else
12001 #ifdef BSD42                            /* 4.2BSD way */
12002     char *asctime();
12003     struct tm *localtime();
12004     struct tm *tp;
12005     gettimeofday(&tv, &tz);
12006     ztusec = tv.tv_usec;
12007     ztmsec = tv.tv_usec / 1000L;
12008     tp = localtime(&tv.tv_sec);
12009     if (s) {
12010         *s = asctime(tp);
12011         debug(F111,"ztime: BSD42",*s,ztusec);
12012     }
12013 #else
12014 #ifdef MINIX                            /* MINIX way */
12015 #ifdef COMMENT
12016     extern long time();                 /* Already got these from <time.h> */
12017     extern char *ctime();
12018 #endif /* COMMENT */
12019     time_t utime[2];
12020     time(utime);
12021     if (s) {
12022         *s = ctime(utime);
12023         debug(F110,"ztime: MINIX",*s,0);
12024     }
12025 #else
12026 #ifdef ZTIMEV7                          /* The regular way */
12027     char *asctime();
12028     struct tm *localtime();
12029     struct tm *tp;
12030     long xclock;                        /* or unsigned long for BeBox? */
12031     time(&xclock);
12032     tp = localtime(&xclock);
12033     if (s) {
12034         *s = asctime(tp);
12035         debug(F110,"ztime: ZTIMEV7",*s,0);
12036     }
12037 #else                                   /* Catch-all for others... */
12038     if (s) {
12039         *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
12040         debug(F110,"ztime: catch-all",*s,0);
12041     }
12042 #endif /* ZTIMEV7 */
12043 #endif /* MINIX */
12044 #endif /* BSD42 */
12045 #endif /* PROVX1 */
12046 #endif /* ATTSV */
12047 #endif /* HPUX1020 */
12048 #endif /* GFTIMER */
12049 }
12050
12051 /*  C O N G M  --  Get console terminal modes.  */
12052
12053 /*
12054   Saves initial console mode, and establishes variables for switching
12055   between current (presumably normal) mode and other modes.
12056   Should be called when program starts, but only after establishing
12057   whether program is in the foreground or background.
12058   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
12059 */
12060 int
12061 congm() {
12062     int fd;
12063     if (backgrd || !isatty(0)) {        /* If in background. */
12064         cgmf = -1;                      /* Don't bother, modes are garbage. */
12065         return(-1);
12066     }
12067     if (cgmf > 0) return(0);            /* Already did this. */
12068     debug(F100,"congm getting modes","",0); /* Need to do it. */
12069 #ifdef aegis
12070     ios_$inq_type_uid(ios_$stdin, conuid, st);
12071     if (st.all != status_$ok) {
12072         fprintf(stderr, "problem getting stdin objtype: ");
12073         error_$print(st);
12074     }
12075     concrp = (conuid == mbx_$uid);
12076     conbufn = 0;
12077 #endif /* aegis */
12078
12079 #ifndef BEBOX
12080     if ((fd = open(CTTNAM,2)) < 0) {    /* Open controlling terminal */
12081 #ifdef COMMENT
12082         fprintf(stderr,"Error opening %s\n", CTTNAM);
12083         perror("congm");
12084         return(-1);
12085 #else
12086         fd = 0;
12087 #endif /* COMMENT */
12088     }
12089 #else
12090     fd = 0;
12091 #endif /* !BEBOX */
12092 #ifdef BSD44ORPOSIX
12093     if (tcgetattr(fd,&ccold) < 0) return(-1);
12094     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
12095     if (tcgetattr(fd,&ccraw) < 0) return(-1);
12096 #else
12097 #ifdef ATTSV
12098     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
12099     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
12100     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
12101 #ifdef VXVE
12102     cccbrk.c_line = 0;                  /* STTY line 0 for CDC VX/VE */
12103     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
12104     ccraw.c_line = 0;                   /* STTY line 0 for CDC VX/VE */
12105     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
12106 #endif /* VXVE */
12107 #else
12108 #ifdef BELLV10
12109     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
12110     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
12111     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
12112     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
12113 #else
12114     if (gtty(fd,&ccold) < 0) return(-1);
12115     if (gtty(fd,&cccbrk) < 0) return(-1);
12116     if (gtty(fd,&ccraw) < 0) return(-1);
12117 #endif /* BELLV10 */
12118 #endif /* ATTSV */
12119 #endif /* BSD44ORPOSIX */
12120 #ifdef sony_news                        /* Sony NEWS */
12121     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
12122         perror("congm error getting Kanji mode");
12123         debug(F101,"congm error getting Kanji mode","",0);
12124         km_con = -1;                    /* Make sure this stays undefined. */
12125         return(-1);
12126     }
12127 #endif /* sony_news */
12128     if (fd > 0)
12129       close(fd);
12130     cgmf = 1;                           /* Flag that we got them. */
12131     return(1);
12132 }
12133
12134
12135 static VOID
12136 congetbuf(x) int x; {
12137     int n;
12138     n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
12139     if (x > n) {
12140         debug(F101,"congetbuf char loss","",x-n);
12141         x = n;
12142     }
12143     x = read(0,conbufp,x);
12144     conbufn += x;
12145     debug(F111,"congetbuf readahead",conbuf,x);
12146 }
12147
12148
12149 /*  C O N C B --  Put console in cbreak mode.  */
12150
12151 /*  Returns 0 if ok, -1 if not  */
12152
12153 int
12154 #ifdef CK_ANSIC
12155 concb(char esc)
12156 #else
12157 concb(esc) char esc;
12158 #endif /* CK_ANSIC */
12159 /* concb */ {
12160     int x, y = 0;
12161     debug(F101,"concb constate","",constate);
12162     debug(F101,"concb cgmf","",cgmf);
12163     debug(F101,"concb backgrd","",backgrd);
12164
12165     if (constate == CON_CB)
12166       return(0);
12167
12168     if (cgmf < 1)                       /* Did we get console modes yet? */
12169       if (!backgrd)                     /* No, in background? */
12170         congm();                        /* No, try to get them now. */
12171     if (cgmf < 1)                       /* Still don't have them? */
12172       return(0);                        /* Give up. */
12173     debug(F101,"concb ttyfd","",ttyfd);
12174     debug(F101,"concb ttfdflg","",ttfdflg);
12175 #ifdef COMMENT
12176     /* This breaks returning to prompt after protocol with "-l 0" */
12177     /* Commented out July 1998 */
12178     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
12179       return(0);
12180 #endif /* COMMENT */
12181     x = isatty(0);
12182     debug(F101,"concb isatty","",x);
12183     if (!x) return(0);                  /* Only when running on real ttys */
12184     debug(F101,"concb xsuspend","",xsuspend);
12185     if (backgrd)                        /* Do nothing if in background. */
12186       return(0);
12187     escchr = esc;                       /* Make this available to other fns */
12188     ckxech = 1;                         /* Program can echo characters */
12189 #ifdef aegis
12190     conbufn = 0;
12191     if (concrp) return(write(1, "\035\002", 2));
12192     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
12193 #endif /* aegis */
12194
12195 #ifdef COHERENT
12196 #define SVORPOSIX
12197 #endif /* COHERENT */
12198
12199 #ifdef Plan9
12200     x = p9concb();
12201 #else
12202 #ifndef SVORPOSIX                       /* BSD, V7, etc */
12203     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
12204     debug(F101,"concb stty CBREAK","",0);
12205     cccbrk.sg_flags |= (CBREAK|CRMOD);  /* Set to character wakeup, */
12206     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
12207     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
12208     errno = 0;
12209 /*
12210   BSD stty() clears the console buffer.  So if anything is waiting in it,
12211   we have to read it now to avoid losing it.
12212 */
12213     x = conchk();
12214     if (x > 0)
12215       congetbuf(x);
12216
12217 #ifdef BELLV10
12218     x = ioctl(0,TIOCSETP,&cccbrk);
12219 #else
12220     x = stty(0,&cccbrk);
12221     debug(F101,"cccbrk.sg_flags concb x","", x);
12222 #endif /* BELLV10 */
12223 #else                                   /* Sys V and POSIX */
12224 #ifndef OXOS
12225     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
12226 #ifdef QNX
12227     /* Don't mess with IEXTEN */
12228     cccbrk.c_lflag &= ~(ICANON|ECHO);
12229 #else
12230 #ifdef COHERENT
12231     cccbrk.c_lflag &= ~(ICANON|ECHO);
12232 #else
12233     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
12234 #endif /* COHERENT */
12235 #endif /* QNX */
12236     cccbrk.c_lflag |= ISIG;             /* Allow signals in command mode. */
12237     cccbrk.c_iflag |= IGNBRK;           /* But ignore BREAK signal */
12238     cccbrk.c_iflag &= ~BRKINT;
12239
12240 #else /* OXOS */
12241     debug(F100,"concb OXOS is defined","",0);
12242     cccbrk.c_lflag &= ~(ICANON|ECHO);
12243     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
12244 #endif /* OXOS */
12245 #ifdef COMMENT
12246 /*
12247   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
12248   array reference is out of bounds.  It's only a debug() call so who needs it.
12249 */
12250 #ifdef VSUSP
12251     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
12252 #endif /* VSUSP */
12253 #endif /* COMMENT */
12254 #ifndef VINTR
12255     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
12256     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
12257 #else
12258     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
12259     cccbrk.c_cc[VINTR] = 003;
12260 #endif /* VINTR */
12261 #ifndef VQUIT
12262     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
12263 #else
12264     cccbrk.c_cc[VQUIT] = escchr;
12265 #endif /* VQUIT */
12266 #ifndef VEOF
12267     cccbrk.c_cc[4] = 1;
12268 #else
12269 #ifndef OXOS
12270 #ifdef VMIN
12271     cccbrk.c_cc[VMIN] = 1;
12272 #endif /* VMIN */
12273 #else /* OXOS */
12274     cccbrk.c_min = 1;
12275 #endif /* OXOS */
12276 #endif /* VEOF */
12277 #ifdef ZILOG
12278     cccbrk.c_cc[5] = 0;
12279 #else
12280 #ifndef VEOL
12281     cccbrk.c_cc[5] = 1;
12282 #else
12283 #ifndef OXOS
12284 #ifdef VTIME
12285     cccbrk.c_cc[VTIME] = 1;
12286 #endif /* VTIME */
12287 #else /* OXOS */
12288     cccbrk.c_time = 1;
12289 #endif /* OXOS */
12290 #endif /* VEOL */
12291 #endif /* ZILOG */
12292     errno = 0;
12293 #ifdef BSD44ORPOSIX                     /* Set new modes */
12294     x = tcsetattr(0,TCSADRAIN,&cccbrk);
12295 #else /* ATTSV */                       /* or the POSIX way */
12296     x = ioctl(0,TCSETAW,&cccbrk);       /* the Sys V way */
12297 #endif /* BSD44ORPOSIX */
12298 #endif /* SVORPOSIX */
12299
12300 #ifdef COHERENT
12301 #undef SVORPOSIX
12302 #endif /* COHERENT */
12303
12304     debug(F101,"concb x","",x);
12305     debug(F101,"concb errno","",errno);
12306
12307 #ifdef  V7
12308 #ifndef MINIX
12309     if (kmem[CON] < 0) {
12310         qaddr[CON] = initrawq(0);
12311         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
12312             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
12313             perror("/dev/kmem");
12314             exit(1);
12315         }
12316     }
12317 #endif /* MINIX */
12318 #endif /* V7 */
12319 #endif /* Plan9 */
12320
12321     if (x > -1)
12322       constate = CON_CB;
12323
12324     debug(F101,"concb returns","",x);
12325     return(x);
12326 }
12327
12328 /*  C O N B I N  --  Put console in binary mode  */
12329
12330 /*  Returns 0 if ok, -1 if not  */
12331
12332 int
12333 #ifdef CK_ANSIC
12334 conbin(char esc)
12335 #else
12336 conbin(esc) char esc;
12337 #endif /* CK_ANSIC */
12338 /* conbin */  {
12339
12340     int x;
12341
12342     debug(F101,"conbin constate","",constate);
12343
12344     if (constate == CON_BIN)
12345       return(0);
12346
12347     if (!isatty(0)) return(0);          /* only for real ttys */
12348     congm();                            /* Get modes if necessary. */
12349     debug(F100,"conbin","",0);
12350     escchr = esc;                       /* Make this available to other fns */
12351     ckxech = 1;                         /* Program can echo characters */
12352 #ifdef aegis
12353     conbufn = 0;
12354     if (concrp) return(write(1, "\035\002", 2));
12355     if (conuid == input_pad_$uid) {
12356         pad_$raw(ios_$stdin, st);
12357         return(0);
12358       }
12359 #endif /* aegis */
12360
12361 #ifdef COHERENT
12362 #define SVORPOSIX
12363 #endif /* COHERENT */
12364
12365 #ifdef Plan9
12366     return p9conbin();
12367 #else
12368 #ifdef SVORPOSIX
12369 #ifndef OXOS
12370 #ifdef QNX
12371     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12372 #else
12373 #ifdef COHERENT
12374     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12375 #else
12376     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
12377 #endif /* COHERENT */
12378 #endif /* QNX */
12379 #else /* OXOS */
12380     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12381     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
12382 #endif /* OXOS */
12383     ccraw.c_iflag |= IGNPAR;
12384 /*
12385   Note that for terminal sessions we disable Xon/Xoff flow control to allow
12386   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
12387   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
12388   control, if in use, is not affected.
12389 */
12390 #ifdef ATTSV
12391 #ifdef BSD44
12392     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
12393                         |INPCK|ISTRIP);
12394 #else
12395     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
12396                         |INPCK|ISTRIP);
12397 #endif /* BSD44 */
12398 #else /* POSIX */
12399     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
12400 #endif /* ATTSV */
12401     ccraw.c_oflag &= ~OPOST;
12402 #ifdef COMMENT
12403 /*
12404   WHAT THE HECK WAS THIS FOR?
12405   The B9600 setting (obviously) prevents CONNECT from working at any
12406   speed other than 9600 when you are logged in to the 7300 on a serial
12407   line.  Maybe some of the other flags are necessary -- if so, put back
12408   the ones that are needed.  This code is supposed to work the same, no
12409   matter whether you are logged in to the 7300 on the real console device,
12410   or through a serial port.
12411 */
12412 #ifdef ATT7300
12413     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
12414 #endif /* ATT7300 */
12415 #endif /* COMMENT */
12416
12417 /*** Kermit used to put the console in 8-bit raw mode, but some users have
12418  *** pointed out that this should not be done, since some sites actually
12419  *** use terminals with parity settings on their Unix systems, and if we
12420  *** override the current settings and stop doing parity, then their terminals
12421  *** will display blotches for characters whose parity is wrong.  Therefore,
12422  *** the following two lines are commented out (Larry Afrin, Clemson U):
12423  ***
12424  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
12425  ***   ccraw.c_cflag |= (CS8|CREAD);
12426  ***
12427  *** Sys III/V sites that have trouble with this can restore these lines.
12428  ***/
12429 #ifndef VINTR
12430     ccraw.c_cc[0] = 003;                /* Interrupt char is Ctrl-C */
12431 #else
12432     ccraw.c_cc[VINTR] = 003;
12433 #endif /* VINTR */
12434 #ifndef VQUIT
12435     ccraw.c_cc[1] = escchr;             /* Escape during packet mode */
12436 #else
12437     ccraw.c_cc[VQUIT] = escchr;
12438 #endif /* VQUIT */
12439 #ifndef VEOF
12440     ccraw.c_cc[4] = 1;
12441 #else
12442 #ifndef OXOS
12443 #ifdef VMIN
12444     ccraw.c_cc[VMIN] = 1;
12445 #endif /* VMIN */
12446 #else /* OXOS */
12447     ccraw.c_min = 1;
12448 #endif /* OXOS */
12449 #endif /* VEOF */
12450
12451 #ifdef ZILOG
12452     ccraw.c_cc[5] = 0;
12453 #else
12454 #ifndef VEOL
12455     ccraw.c_cc[5] = 1;
12456 #else
12457 #ifndef OXOS
12458 #ifdef VTIME
12459     ccraw.c_cc[VTIME] = 1;
12460 #endif /* VTIME */
12461 #else /* OXOS */
12462     ccraw.c_time = 1;
12463 #endif /* OXOS */
12464 #endif /* VEOL */
12465 #endif /* ZILOG */
12466
12467 #ifdef BSD44ORPOSIX
12468     x = tcsetattr(0,TCSADRAIN,&ccraw);  /* Set new modes. */
12469 #else
12470     x = ioctl(0,TCSETAW,&ccraw);
12471 #endif /* BSD44ORPOSIX */
12472 #else /* Berkeley, etc. */
12473     x = conchk();                       /* Because stty() is destructive */
12474     if (x > 0)
12475       congetbuf(x);
12476     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
12477     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
12478 #ifdef BELLV10
12479     x = ioctl(0,TIOCSETP,&ccraw);
12480 #else
12481     x = stty(0,&ccraw);
12482 #endif /* BELLV10 */
12483 #endif /* SVORPOSIX */
12484 #endif /* Plan9 */
12485
12486     if (x > -1)
12487       constate = CON_BIN;
12488
12489     debug(F101,"conbin returns","",x);
12490     return(x);
12491
12492 #ifdef COHERENT
12493 #undef SVORPOSIX
12494 #endif /* COHERENT */
12495
12496 }
12497
12498
12499 /*  C O N R E S  --  Restore the console terminal  */
12500
12501 int
12502 conres() {
12503     int x;
12504     debug(F101,"conres cgmf","",cgmf);
12505     debug(F101,"conres constate","",constate);
12506
12507     if (cgmf < 1)                       /* Do nothing if modes unchanged */
12508       return(0);
12509     if (constate == CON_RES)
12510       return(0);
12511
12512     if (!isatty(0)) return(0);          /* only for real ttys */
12513     debug(F100,"conres isatty ok","",0);
12514     ckxech = 0;                         /* System should echo chars */
12515
12516 #ifdef aegis
12517     conbufn = 0;
12518     if (concrp) return(write(1, "\035\001", 2));
12519     if (conuid == input_pad_$uid) {
12520         pad_$cooked(ios_$stdin, st);
12521         constate = CON_RES;
12522         return(0);
12523     }
12524 #endif /* aegis */
12525
12526 #ifdef Plan9
12527     p9conres();
12528 #else
12529 #ifdef BSD44ORPOSIX
12530     debug(F100,"conres restoring tcsetattr","",0);
12531     x = tcsetattr(0,TCSADRAIN,&ccold);
12532 #else
12533 #ifdef ATTSV
12534     debug(F100,"conres restoring ioctl","",0);
12535     x = ioctl(0,TCSETAW,&ccold);
12536 #else /* BSD, V7, and friends */
12537 #ifdef sony_news                        /* Sony NEWS */
12538     if (km_con != -1)
12539       ioctl(0,TIOCKSET,&km_con);        /* Restore console Kanji mode */
12540 #endif /* sony_news */
12541     msleep(100);
12542     debug(F100,"conres restoring stty","",0);
12543     x = conchk();                       /* Because stty() is destructive */
12544     if (x > 0)
12545       congetbuf(x);
12546 #ifdef BELLV10
12547     x = ioctl(0,TIOCSETP,&ccold);
12548 #else
12549     x = stty(0,&ccold);
12550 #endif /* BELLV10 */
12551 #endif /* ATTSV */
12552 #endif /* BSD44ORPOSIX */
12553 #endif /* Plan9 */
12554     if (x > -1)
12555       constate = CON_RES;
12556
12557     debug(F101,"conres returns","",x);
12558     return(x);
12559 }
12560
12561 /*  C O N O C  --  Output a character to the console terminal  */
12562
12563 int
12564 #ifdef CK_ANSIC
12565 conoc(char c)
12566 #else
12567 conoc(c) char c;
12568 #endif /* CK_ANSIC */
12569 /* conoc */ {
12570
12571 #ifdef IKSD
12572     if (inserver && !local)
12573       return(ttoc(c));
12574
12575 #ifdef CK_ENCRYPTION
12576     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12577         ck_tn_encrypt(&c,1);
12578 #endif /* CK_ENCRYPTION */
12579 #endif /* IKSD */
12580
12581 #ifdef Plan9
12582     return conwrite(&c,1);
12583 #else
12584     return(write(1,&c,1));
12585 #endif /* Plan9 */
12586 }
12587
12588 /*  C O N X O  --  Write x characters to the console terminal  */
12589
12590 int
12591 conxo(x,s) int x; char *s; {
12592
12593 #ifdef IKSD
12594     if (inserver && !local)
12595       return(ttol((CHAR *)s,x));
12596
12597 #ifdef CK_ENCRYPTION
12598     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12599         ck_tn_encrypt(s,x);
12600 #endif /* CK_ENCRYPTION */
12601 #endif /* IKSD */
12602
12603 #ifdef Plan9
12604     return(conwrite(s,x));
12605 #else
12606     return(write(1,s,x));
12607 #endif /* Plan9 */
12608 }
12609
12610 /*  C O N O L  --  Write a line to the console terminal  */
12611
12612 int
12613 conol(s) char *s; {
12614     int len;
12615     if (!s) s = "";                     /* Always do this! */
12616     len = strlen(s);
12617     if (len == 0)
12618       return(0);
12619
12620 #ifdef IKSD
12621     if (inserver && !local)
12622       return(ttol((CHAR *)s,len));
12623
12624 #ifdef CK_ENCRYPTION
12625     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
12626         if (nxpacket < len) {
12627             if (xpacket) {
12628                 free(xpacket);
12629                 xpacket = NULL;
12630                 nxpacket = 0;
12631             }
12632             len = len > 10240 ? len : 10240;
12633             xpacket = (CHAR *)malloc(len);
12634             if (!xpacket) {
12635                 fprintf(stderr,"ttol malloc failure\n");
12636                 return(-1);
12637             } else
12638               nxpacket = len;
12639         }
12640         memcpy(xpacket,s,len);
12641         s = (char *)xpacket;
12642         ck_tn_encrypt(s,len);
12643     }
12644 #endif /* CK_ENCRYPTION */
12645 #endif /* IKSD */
12646
12647 #ifdef Plan9
12648     return(conwrite(s,len));
12649 #else
12650     return(write(1,s,len));
12651 #endif /* Plan9 */
12652 }
12653
12654 /*  C O N O L A  --  Write an array of lines to the console terminal */
12655
12656 int
12657 conola(s) char *s[]; {
12658     char * p;
12659     int i, x;
12660
12661
12662     if (!s) return(0);
12663     for (i = 0; ; i++) {
12664         p = s[i];
12665         if (!p) p = "";                 /* Let's not dump core shall we? */
12666         if (!*p)
12667           break;
12668 #ifdef IKSD
12669         if (inserver && !local)
12670           x = ttol((CHAR *)p,(int)strlen(p));
12671         else
12672 #endif /* IKSD */
12673           x = conol(p);
12674         if (x < 0)
12675           return(-1);
12676     }
12677     return(0);
12678 }
12679
12680 /*  C O N O L L  --  Output a string followed by CRLF  */
12681
12682 int
12683 conoll(s) char *s; {
12684     CHAR buf[3];
12685     buf[0] = '\r';
12686     buf[1] = '\n';
12687     buf[2] = '\0';
12688     if (!s) s = "";
12689
12690 #ifdef IKSD
12691     if (inserver && !local) {
12692         if (*s) ttol((CHAR *)s,(int)strlen(s));
12693         return(ttol(buf,2));
12694     }
12695 #endif /* IKSD */
12696
12697     if (*s) conol(s);
12698 #ifdef IKSD
12699 #ifdef CK_ENCRYPTION
12700     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12701       ck_tn_encrypt((char *)buf,2);
12702 #endif /* CK_ENCRYPTION */
12703 #endif /* IKSD */
12704
12705 #ifdef Plan9
12706     return(conwrite(buf, 2));
12707 #else
12708     return(write(1,buf,2));
12709 #endif /* Plan9 */
12710 }
12711
12712 /*  C O N C H K  --  Return how many characters available at console  */
12713 /*
12714   We could also use select() here to cover a few more systems that are not
12715   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
12716 */
12717 int
12718 conchk() {
12719     static int contyp = 0;              /* +1 for isatty, -1 otherwise */
12720
12721     if (contyp == 0)                    /* This prevents unnecessary */
12722       contyp = (isatty(0) ? 1 : -1);    /* duplicated calls to isatty() */
12723     debug(F101,"conchk contyp","",contyp);
12724     if (backgrd || (contyp < 0))
12725       return(0);
12726
12727 #ifdef aegis
12728     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
12729
12730     /* read in more characters */
12731     conbufn = ios_$get(ios_$stdin,
12732               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
12733     if (st.all != status_$ok) conbufn = 0;
12734     conbufp = conbuf;
12735     return(conbufn);
12736 #else
12737 #ifdef IKSD
12738     if (inserver && !local)
12739       return(in_chk(1,ttyfd));
12740     else
12741 #endif /* IKSD */
12742       return(in_chk(0,0));
12743 #endif /* aegis */
12744 }
12745
12746 /*  C O N I N C  --  Get a character from the console  */
12747 /*
12748   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
12749   read.  Upon success, returns the character.  Upon failure, returns -1.
12750   A timed read that does not complete within the timeout period returns -2.
12751 */
12752 int
12753 coninc(timo) int timo; {
12754     int n = 0; CHAR ch;
12755     int xx;
12756
12757     if (conbufn > 0) {                  /* If something already buffered */
12758         --conbufn;
12759         return((unsigned)(*conbufp++ & 0xff));
12760     }
12761
12762     errno = 0;                          /* Clear this */
12763 #ifdef IKSD
12764     if (inserver && !local) {
12765         xx = ttinc(timo);
12766         if (xx < 0)
12767           return(ttinctimo ? -2 : -1);
12768         else
12769           return(xx);
12770     }
12771 #endif /* IKSD */
12772
12773 #ifdef aegis                            /* Apollo Aegis only... */
12774     debug(F101,"coninc timo","",timo);
12775     fflush(stdout);
12776     if (conchk() > 0) {
12777         --conbufn;
12778         return((unsigned)(*conbufp++ & 0xff));
12779     }
12780 #endif /* aegis */
12781
12782 #ifdef TTLEBUF
12783     if (
12784 #ifdef IKSD
12785         inserver &&
12786 #endif /* IKSD */
12787         !xlocal
12788         ) {
12789         if (ttpush >= 0) {
12790             debug(F111,"ttinc","ttpush",ttpush);
12791             ch = ttpush;
12792             ttpush = -1;
12793             return(ch);
12794         }
12795         if (le_data) {
12796             if (le_getchar(&ch) > 0) {
12797                 debug(F111,"ttinc LocalEchoInBuf","ch",ch);
12798                 return(ch);
12799             }
12800         }
12801     }
12802 #endif /* TTLEBUF */
12803
12804     if (timo <= 0) {                    /* Untimed, blocking read. */
12805         while (1) {                     /* Keep trying till we get one. */
12806             n = read(0, &ch, 1);        /* Read a character. */
12807             if (n == 0) continue;       /* Shouldn't happen. */
12808             if (n > 0) {                /* If read was successful, */
12809 #ifdef IKSD
12810 #ifdef CK_ENCRYPTION
12811                 debug(F100,"coninc decrypt 1","",0);
12812                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12813                   ck_tn_decrypt((char *)&ch,1);
12814 #endif /* CK_ENCRYPTION */
12815 #endif /* IKSD */
12816                 return((unsigned)(ch & 0xff)); /* return the character. */
12817             }
12818
12819 /* Come here if read() returned an error. */
12820
12821             debug(F101, "coninc(0) errno","",errno); /* Log the error. */
12822 #ifndef OXOS
12823 #ifdef SVORPOSIX
12824 #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
12825 #ifndef EINTR
12826 #define EINTR 4
12827 #endif /* EINTR */
12828 #endif /* CIE */
12829 /*
12830   This routine is used for several different purposes.  In CONNECT mode, it is
12831   used to do an untimed, blocking read from the keyboard in the lower CONNECT
12832   fork.  During local-mode file transfer, it reads a character from the
12833   console to interrupt the file transfer (like A for a status report, X to
12834   cancel a file, etc).  Obviously, we don't want the reads in the latter case
12835   to be blocking, or the file transfer would stop until the user typed
12836   something.  Unfortunately, System V does not allow the console device input
12837   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
12838   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
12839   and trapped by esctrp(), and this routine pretends to have read the quit
12840   character from the keyboard normally.  But, kludge or no kludge, the read()
12841   issued by this command, under System V only, can fail if a signal -- ANY
12842   signal -- is caught while the read is pending.  This can occur not only when
12843   the user types the quit character, but also during telnet negotiations, when
12844   the lower CONNECT fork signals the upper one about an echoing mode change.
12845   When this happens, we have to post the read() again.  This is apparently not
12846   a problem in BSD-based UNIX versions.
12847 */
12848             if (errno == EINTR)         /* Read interrupted. */
12849               if (conesc)  {            /* If by SIGQUIT, */
12850                  conesc = 0;            /* the conesc variable is set, */
12851                  return(escchr);        /* so return the escape character. */
12852              } else continue;           /* By other signal, try again. */
12853 #else
12854 /*
12855   This might be dangerous, but let's do this on non-System V versions too,
12856   since at least one SunOS 4.1.2 user complains of immediate disconnections
12857   upon first making a TELNET connection.
12858 */
12859             if (errno == EINTR)         /* Read interrupted. */
12860               continue;
12861 #endif /* SVORPOSIX */
12862 #else /* OXOS */
12863             if (errno == EINTR)         /* Read interrupted. */
12864               continue;
12865 #endif /* OXOS */
12866             return(-1);                 /* Error */
12867         }
12868     }
12869 #ifdef DEBUG
12870     if (deblog && timo <= 0) {
12871         debug(F100,"coninc timeout logic error","",0);
12872         timo = 1;
12873     }
12874 #endif /* DEBUG */
12875
12876 /* Timed read... */
12877
12878     saval = signal(SIGALRM,timerh);     /* Set up timeout handler. */
12879     xx = alarm(timo);                   /* Set the alarm. */
12880     debug(F101,"coninc alarm set","",timo);
12881     if (
12882 #ifdef CK_POSIX_SIG
12883         sigsetjmp(sjbuf,1)
12884 #else
12885         setjmp(sjbuf)
12886 #endif /* CK_POSIX_SIG */
12887         )                               /* The read() timed out. */
12888       n = -2;                           /* Code for timeout. */
12889     else
12890       n = read(0, &ch, 1);
12891     ttimoff();                          /* Turn off timer */
12892     if (n > 0) {                        /* Got character OK. */
12893 #ifdef IKSD
12894 #ifdef CK_ENCRYPTION
12895         debug(F100,"coninc decrypt 2","",0);
12896         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12897           ck_tn_decrypt((char *)&ch,1);
12898 #endif /* CK_ENCRYPTION */
12899 #endif /* IKSD */
12900         return((unsigned)(ch & 0xff));  /* Return it. */
12901     }
12902 /*
12903   read() returned an error.  Same deal as above, but without the loop.
12904 */
12905     debug(F101, "coninc(timo) n","",n);
12906     debug(F101, "coninc(timo) errno","",errno);
12907 #ifndef OXOS
12908 #ifdef SVORPOSIX
12909     if (n == -1 && errno == EINTR && conesc != 0) {
12910         conesc = 0;
12911         return(escchr);                 /* User entered escape character. */
12912     }
12913 #endif /* SVORPOSIX */
12914     if (n == 0 && errno > 0) {          /* It's an error */
12915         return(-1);
12916     }
12917 #endif /* ! OXOS */
12918     return(n);
12919 }
12920
12921 /*  C O N G K S  --  Console Get Keyboard Scancode  */
12922
12923 #ifndef congks
12924 /*
12925   This function needs to be filled in with the various system-dependent
12926   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
12927   keyboard scan code.  Unfortunately there aren't any.
12928 */
12929 int
12930 congks(timo) int timo; {
12931
12932 #ifdef IKSD
12933     if (inserver && !local)
12934       return(ttinc(timo));
12935 #endif /* IKSD */
12936
12937     return(coninc(timo));
12938 }
12939 #endif /* congks */
12940
12941 #ifdef ATT7300
12942
12943 /*  A T T D I A L  --  Dial up the remote system using internal modem
12944  * Purpose: to open and dial a number on the internal modem available on the
12945  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
12946  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
12947  * Uses information in <sys/phone.h> and our status int attmodem.
12948  */
12949 attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
12950     char *telnum;
12951
12952     attmodem &= ~ISMODEM;                       /* modem not in use yet */
12953                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
12954                     /* We turn this flag off once the dial is complete */
12955     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
12956
12957     /* Condition line, check availability & DATA mode, turn on speaker */
12958     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
12959         printf("cannot access phone\n");
12960         ttclos(0);
12961         return (-2);
12962     }
12963     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
12964
12965     if (dialer.c_lineparam & VOICE) {   /* phone must be in DATA mode */
12966         printf(" Should not dial with modem in VOICE mode.\n");
12967         printf(" Exit Kermit, switch to DATA and retry call.\n");
12968         ttclos(0);
12969         return (-2);
12970     }
12971 #ifdef ATTTONED                         /* Old way, tone dialing only. */
12972     dialer.c_lineparam = DATA | DTMF;   /* Dial with tones, */
12973     dialer.c_lineparam &= ~PULSE;       /* not with pulses. */
12974 #else
12975     /* Leave current pulse/tone state alone. */
12976     /* But what about DATA?  Add it back if you have trouble. */
12977     /* sys/phone says you get DATA automatically by opening device RDWR */
12978 #endif
12979     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
12980 #ifdef COMMENT
12981     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
12982 #else
12983     /* sys/phone says RINGON used only for incoming voice calls */
12984     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
12985     dialer.c_feedback |= SPEAKERON|NORMSPK;
12986 #endif
12987     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
12988     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
12989         printf("Cannot set modem characteristics\n");
12990         ttclos(0);
12991         return (-2);
12992     }
12993     ioctl(ttyfd,PIOCRECONN,0);          /* Turns on speaker for pulse */
12994
12995 #ifdef COMMENT
12996     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
12997 line_status:%o feedback:%o\n",
12998     dialer.c_lineparam, dialer.c_waitdialtone,
12999     dialer.c_linestatus, dialer.c_feedback);
13000 #endif
13001
13002     attmodem |= ISMODEM;                        /* modem is now in-use */
13003     sleep(1);
13004     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
13005 #ifdef ATTTONED
13006       /* Tone dialing only */
13007       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13008           perror("Error in dialing");
13009           ttclos(0);
13010           return(-2);
13011       }
13012 #else /* Allow Pulse or Tone dialing */
13013     switch (*telnum) {
13014       case 't': case 'T': case '%':     /* Tone dialing requested */
13015         dialer.c_lineparam |= DTMF;
13016         dialer.c_lineparam &= ~PULSE;
13017         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13018             printf("Cannot set modem to tone dialing\n");
13019             ttclos(0);
13020             return(-2);
13021         }
13022         break;
13023       case 'd': case 'D': case 'p': case 'P': case '^':
13024         dialer.c_lineparam |= PULSE;
13025         dialer.c_lineparam &= ~DTMF;
13026         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13027             printf("Cannot set modem to pulse dialing\n");
13028             ttclos(0);
13029             return(-2);
13030         }
13031         break;
13032       default:
13033         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13034             perror("Dialing error");
13035             ttclos(0);
13036             return(-2);
13037         }
13038         break;
13039     }
13040 #endif
13041
13042     ioctl(ttyfd,PIOCDIAL,"@");          /* terminator for data call */
13043     do {                                /* wait for modems to Connect */
13044         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
13045             perror("Cannot get modems to connect");
13046             ttclos(0);
13047             return(-2);
13048         }
13049     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
13050     /* Turn off O_NDELAY flag now. */
13051     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
13052     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
13053     return(0);                          /* return success */
13054 }
13055
13056 /*
13057   Offgetty, ongetty functions. These function get the 'getty(1m)' off
13058   and restore it to the indicated line.  Shell's return codes are:
13059     0: Can't do it.  Probably a user logged on.
13060     1: No need.  No getty on that line.
13061     2: Done, you should restore the getty when you're done.
13062   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
13063   Thanks to Kevin O'Gorman, Anarm Software Systems.
13064
13065    getoff.sh looks like:   geton.sh looks like:
13066      setgetty $1 0           setgetty $1 1
13067      err=$?                  exit $?
13068      sleep 2
13069      exit $err
13070 */
13071
13072 /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
13073  * and get status so it can be restarted after the line is hung up.
13074  */
13075 int
13076 offgetty(ttname) char *ttname; {
13077     char temp[30];
13078     while (*ttname != '\0') ttname++;       /* seek terminator of path */
13079     ttname -= 3;                            /* get last 3 chars of name */
13080     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
13081     return(zsyscmd(temp));
13082 }
13083
13084 /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
13085
13086 int
13087 ongetty(ttname) char *ttname; {
13088     char temp[30];
13089     while (*ttname != '\0') ttname++;       /* comms tty path name */
13090     ttname -= 3;
13091     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
13092     return(zsyscmd(temp));
13093 }
13094 #endif /* ATT7300 */
13095
13096 /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
13097  *
13098  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
13099  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
13100  *  2 = Auto: For "modem direct": The same as "Off".
13101  *            For real modem types: Heed carrier during connect, but ignore
13102  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
13103  *
13104  * As you can see, this setting does not affect dialing, which always ignores
13105  * carrier (unless there is some special exception for some modem type).  It
13106  * does affect ttopen() if it is set before ttopen() is used.  This setting
13107  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
13108  * (or should be) always called before any communications is tried, which
13109  * means that, practically speaking, the effect is immediate.
13110  *
13111  * Of course, nothing of this applies to remote mode (xlocal = 0).
13112  *
13113  * Someone has yet to uncover how to manipulate the carrier in the BSD
13114  * environment (or any non-termio using environment).  Until that time, this
13115  * will simply be a no-op for BSD.
13116  *
13117  * Note that in previous versions, the carrier was most often left unchanged
13118  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
13119  * has changed.  Now it is controlled by ttcarr in conjunction with these
13120  * modes.
13121  */
13122 int
13123 ttscarr(carrier) int carrier; {
13124     ttcarr = carrier;
13125     debug(F101, "ttscarr","",ttcarr);
13126     return(ttcarr);
13127 }
13128
13129 /* C A R R C T L  --  Set tty modes for carrier treatment.
13130  *
13131  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
13132  * (actually, there are no bits in sgttyb for that), or performs any other
13133  * operations needed to control this on the current system.  The function does
13134  * not do the actual TCSETA or stty, since often we want to set other bits too
13135  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
13136  *
13137  * We don't know how to do anything like carrier control on non-ATTSV systems,
13138  * except, apparently, ultrix.  See above.  It is also known that this doesn't
13139  * have much effect on a Xenix system.  For Xenix, one should switch back and
13140  * forth between the upper and lower case device files.  Maybe later.
13141  * Presently, Xenix will stick to the mode it was opened with.
13142  *
13143  * carrier: 0 = ignore carrier, 1 = require carrier.
13144  * The current state is saved in curcarr, and checked to save labour.
13145  */
13146 #ifdef SVORPOSIX
13147 int
13148 #ifdef BSD44ORPOSIX
13149 carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
13150 #else /* ATTSV */
13151 carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
13152 #endif /* BSD44ORPOSIX */
13153 /* carrctl */ {
13154     debug(F101, "carrctl","",carrier);
13155     if (carrier)
13156       ttpar->c_cflag &= ~CLOCAL;
13157     else
13158       ttpar->c_cflag |= CLOCAL;
13159     return(0);
13160 }
13161 #else /* Berkeley, V7, et al... */
13162 int
13163 carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
13164     debug(F101, "carrctl","",carrier);
13165     if (carrier == curcarr)
13166       return(0);
13167     curcarr = carrier;
13168 #ifdef ultrix
13169 #ifdef COMMENT
13170 /*
13171   Old code from somebody at DEC that tends to get stuck, time out, etc.
13172 */
13173     if (carrier) {
13174         ioctl(ttyfd, TIOCMODEM, &temp);
13175         ioctl(ttyfd, TIOCHPCL, 0);
13176     } else {
13177         /* (According to the manuals, TIOCNCAR should be preferred */
13178         /* over TIOCNMODEM...) */
13179         ioctl(ttyfd, TIOCNMODEM, &temp);
13180     }
13181 #else
13182 /*
13183   New code from Jamie Watson that, he says, eliminates the problems.
13184 */
13185     if (carrier) {
13186         ioctl(ttyfd, TIOCCAR);
13187         ioctl(ttyfd, TIOCHPCL);
13188     } else {
13189         ioctl(ttyfd, TIOCNCAR);
13190     }
13191 #endif /* COMMENT */
13192 #endif /* ultrix */
13193     return(0);
13194 }
13195 #endif /* SVORPOSIX */
13196
13197
13198 /*  T T G M D M  --  Get modem signals  */
13199 /*
13200  Looks for RS-232 modem signals, and returns those that are on in as its
13201  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
13202  Returns:
13203  -3 Not implemented
13204  -2 if the communication device does not have modem control (e.g. telnet)
13205  -1 on error.
13206  >= 0 on success, with a bit mask containing the modem signals that are on.
13207 */
13208
13209 /*
13210   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
13211   modem control, namely the TIOCMGET ioctl.
13212 */
13213
13214 #ifdef BSD43
13215 #define K_MDMCTL
13216 #endif /* BSD43 */
13217
13218 #ifdef SUNOS4
13219 #define K_MDMCTL
13220 #endif /* SUNOS4 */
13221
13222 /*
13223   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
13224   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
13225   must be defined in order to get the high serial speeds that are new to
13226   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
13227   ioctl() returns -1 with errno 22 (invalid function).  But third-party
13228   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
13229   driven by those drivers.
13230 */
13231 #ifdef SCO_OSR504
13232 #ifndef TIOCMGET
13233 #define TIOCMGET (('t'<<8)|29)
13234 #endif /* TIOCMGET */
13235 #endif /* SCO_OSR504 */
13236
13237 #ifdef CK_SCOV5
13238 /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
13239 #ifndef TIOCM_DTR
13240 #define TIOCM_DTR       0x0002          /* data terminal ready */
13241 #define TIOCM_RTS       0x0004          /* request to send */
13242 #define TIOCM_CTS       0x0020          /* clear to send */
13243 #define TIOCM_CAR       0x0040          /* carrier detect */
13244 #define TIOCM_RNG       0x0080          /* ring */
13245 #define TIOCM_DSR       0x0100          /* data set ready */
13246 #define TIOCM_CD        TIOCM_CAR
13247 #define TIOCM_RI        TIOCM_RNG
13248 #endif /* TIOCM_DTR */
13249 #endif /* CK_SCOV5 */
13250
13251 #ifdef QNX
13252 #define K_MDMCTL
13253 #else
13254 #ifdef TIOCMGET
13255 #define K_MDMCTL
13256 #endif /* TIOCMGET */
13257 #endif /* QNX */
13258 /*
13259   "A serial communication program that can't read modem signals
13260    is like a car without windows."
13261 */
13262 int
13263 ttgmdm() {
13264
13265 #ifdef QNX
13266 #include <sys/qioctl.h>
13267
13268     unsigned long y, mdmbits[2];
13269     int x, z = 0;
13270
13271     if (xlocal && ttyfd < 0)
13272       return(-1);
13273
13274 #ifdef NETCONN
13275     if (netconn) {                      /* Network connection */
13276 #ifdef TN_COMPORT
13277         if (istncomport()) {
13278             gotsigs = 1;
13279             return(tngmdm());
13280         } else
13281 #endif /* TN_COMPORT */
13282           return(-2);                   /* No modem signals */
13283     }
13284 #endif /* NETCONN */
13285
13286 #ifdef NETCMD
13287     if (ttpipe) return(-2);
13288 #endif /* NETCMD */
13289 #ifdef NETPTY
13290     if (ttpty) return(-2);
13291 #endif /* NETPTY */
13292
13293     mdmbits[0] = 0L;
13294     mdmbits[1] = 0L;
13295 /*
13296  * From <sys/qioctl.h>:
13297  *
13298  * SERIAL devices   (all Dev.ser versions)
13299  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
13300  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
13301  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
13302  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
13303  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
13304  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
13305  * 6 - reserved     14 : Break        22 = RI           30 - reserved
13306  * 7 - reserved     15 = 0            23 = CD           31 - reserved
13307  */
13308     errno = 0;
13309     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
13310     debug(F101,"ttgmdm qnx_ioctl","",x);
13311     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
13312     if (!x) {
13313         debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
13314         debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
13315         y = mdmbits[0];
13316         if (y & 0x000001L) z |= BM_DTR; /* Bit  0 */
13317         if (y & 0x000002L) z |= BM_RTS; /* Bit  1 */
13318         if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
13319         if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
13320         if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
13321         if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
13322         debug(F101,"ttgmdm qnx result","",z);
13323         debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
13324         gotsigs = 1;
13325         return(z);
13326     } else return(-1);
13327 #else /* QNX */
13328 #ifdef HPUX                             /* HPUX has its own way */
13329     int x, z;
13330
13331 #ifdef HPUX10                           /* Modem flag word */
13332     mflag y;                            /* mflag typedef'd in <sys/modem.h> */
13333 #else
13334 #ifdef HPUX9
13335     mflag y;
13336 #else
13337 #ifdef HPUX8
13338     mflag y;
13339 #else
13340     unsigned long y;                    /* Not sure about pre-8.0... */
13341 #endif /* HPUX8 */
13342 #endif /* HPUX9 */
13343 #endif /* HPUX10 */
13344
13345     if (xlocal && ttyfd < 0)
13346       return(-1);
13347
13348 #ifdef NETCONN
13349     if (netconn) {                      /* Network connection */
13350 #ifdef TN_COMPORT
13351         if (istncomport()) {
13352             gotsigs = 1;
13353             return(tngmdm());
13354         } else
13355 #endif /* TN_COMPORT */
13356           return(-2);                   /* No modem signals */
13357     }
13358 #endif /* NETCONN */
13359
13360 #ifdef NETCMD
13361     if (ttpipe) return(-2);
13362 #endif /* NETCMD */
13363 #ifdef NETPTY
13364     if (ttpty) return(-2);
13365 #endif /* NETPTY */
13366
13367     if (xlocal)                         /* Get modem signals */
13368       x = ioctl(ttyfd,MCGETA,&y);
13369     else
13370       x = ioctl(0,MCGETA,&y);
13371     if (x < 0) return(-1);
13372     debug(F101,"ttgmdm","",y);
13373
13374     z = 0;                              /* Initialize return value */
13375
13376 /* Now set bits for each modem signal that is reported to be on. */
13377
13378 #ifdef MCTS
13379     /* Clear To Send */
13380     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
13381     if (y & MCTS) z |= BM_CTS;
13382 #endif
13383 #ifdef MDSR
13384     /* Data Set Ready */
13385     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
13386     if (y & MDSR) z |= BM_DSR;
13387 #endif
13388 #ifdef MDCD
13389     /* Carrier */
13390     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
13391     if (y & MDCD) z |= BM_DCD;
13392 #endif
13393 #ifdef MRI
13394     /* Ring Indicate */
13395     debug(F101,"ttgmdm HPUX RI","",y & MRI);
13396     if (y & MRI) z |= BM_RNG;
13397 #endif
13398 #ifdef MDTR
13399     /* Data Terminal Ready */
13400     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
13401     if (y & MDTR) z |= BM_DTR;
13402 #endif
13403 #ifdef MRTS
13404     /* Request To Send */
13405     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
13406     if (y & MRTS) z |= BM_RTS;
13407 #endif
13408     gotsigs = 1;
13409     return(z);
13410
13411 #else /* ! HPUX */
13412
13413 #ifdef K_MDMCTL
13414 /*
13415   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
13416   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
13417   are needed.
13418 */
13419 #ifndef TIOCMGET
13420 #include <sys/ttycom.h>
13421 #endif /* TIOCMGET */
13422
13423     int x, y, z;
13424
13425     debug(F100,"ttgmdm K_MDMCTL defined","",0);
13426
13427 #ifdef NETCONN
13428     if (netconn) {                      /* Network connection */
13429 #ifdef TN_COMPORT
13430         if (istncomport()) {
13431             gotsigs = 1;
13432             return(tngmdm());
13433         } else
13434 #endif /* TN_COMPORT */
13435           return(-2);                   /* No modem signals */
13436     }
13437 #endif /* NETCONN */
13438
13439 #ifdef NETCMD
13440     if (ttpipe) return(-2);
13441 #endif /* NETCMD */
13442 #ifdef NETPTY
13443     if (ttpty) return(-2);
13444 #endif /* NETPTY */
13445
13446     if (xlocal && ttyfd < 0)
13447       return(-1);
13448
13449     if (xlocal)
13450       x = ioctl(ttyfd,TIOCMGET,&y);     /* Get modem signals. */
13451     else
13452       x = ioctl(0,TIOCMGET,&y);
13453     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
13454     if (x < 0) {
13455         debug(F101,"ttgmdm errno","",errno);
13456         return(-1);
13457     }
13458     debug(F101,"ttgmdm bits","",y);
13459
13460     z = 0;                              /* Initialize return value. */
13461 #ifdef TIOCM_CTS
13462     /* Clear To Send */
13463     if (y & TIOCM_CTS) z |= BM_CTS;
13464     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); 
13465 #else
13466     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
13467 #endif
13468 #ifdef TIOCM_DSR
13469     /* Data Set Ready */
13470     if (y & TIOCM_DSR) z |= BM_DSR;
13471     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); 
13472 #else
13473     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
13474 #endif
13475 #ifdef TIOCM_CAR
13476     /* Carrier */
13477     if (y & TIOCM_CAR) z |= BM_DCD;
13478     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); 
13479 #else
13480     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
13481 #endif
13482 #ifdef TIOCM_RNG
13483     /* Ring Indicate */
13484     if (y & TIOCM_RNG) z |= BM_RNG;
13485     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); 
13486 #else
13487     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
13488 #endif
13489 #ifdef TIOCM_DTR
13490     /* Data Terminal Ready */
13491     if (y & TIOCM_DTR) z |= BM_DTR;
13492     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); 
13493 #else
13494     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
13495 #endif
13496 #ifdef TIOCM_RTS
13497     /* Request To Send */
13498     if (y & TIOCM_RTS) z |= BM_RTS;
13499     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); 
13500 #else
13501     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
13502 #endif
13503     gotsigs = 1;
13504     return(z);
13505
13506 #else /* !K_MDMCTL catch-All */
13507
13508     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
13509 #ifdef TIOCMGET
13510     debug(F100,"ttgmdm TIOCMGET defined","",0);
13511 #else
13512     debug(F100,"ttgmdm TIOCMGET not defined","",0);
13513 #endif /* TIOCMGET */
13514 #ifdef _SVID3
13515     debug(F100,"ttgmdm _SVID3 defined","",0);
13516 #else
13517     debug(F100,"ttgmdm _SVID3 not defined","",0);
13518 #endif /* _SVID3 */
13519
13520 #ifdef NETCONN
13521     if (netconn) {                      /* Network connection */
13522 #ifdef TN_COMPORT
13523         if (istncomport()) {
13524             gotsigs = 1;
13525             return(tngmdm());
13526         } else
13527 #endif /* TN_COMPORT */
13528           return(-2);                   /* No modem signals */
13529     }
13530 #endif /* NETCONN */
13531
13532 #ifdef NETCMD
13533     if (ttpipe) return(-2);
13534 #endif /* NETCMD */
13535 #ifdef NETPTY
13536     if (ttpty) return(-2);
13537 #endif /* NETPTY */
13538
13539     return(-3);                         /* Sorry, I don't know how... */
13540
13541 #endif /* K_MDMCTL */
13542 #endif /* HPUX */
13543 #endif /* QNX */
13544 }
13545
13546 /*  P S U S P E N D  --  Put this process in the background.  */
13547
13548 /*
13549   Call with flag nonzero if suspending is allowed, zero if not allowed.
13550   Returns 0 on apparent success, -1 on failure (flag was zero, or
13551   kill() returned an error code.
13552 */
13553 int
13554 psuspend(flag) int flag; {
13555
13556 #ifdef RTU
13557     extern int rtu_bug;
13558 #endif /* RTU */
13559
13560     if (flag == 0) return(-1);
13561
13562 #ifdef NOJC
13563     return(-1);
13564 #else
13565 #ifdef SIGTSTP
13566 /*
13567   The big question here is whether job control is *really* supported.
13568   There's no way Kermit can know for sure.  The fact that SIGTSTP is
13569   defined does not guarantee the Unix kernel supports it, and the fact
13570   that the Unix kernel supports it doesn't guarantee that the user's
13571   shell (or other process that invoked Kermit) supports it.
13572 */
13573 #ifdef RTU
13574     rtu_bug = 1;
13575 #endif /* RTU */
13576     if (kill(0,SIGSTOP) < 0
13577 #ifdef MIPS
13578 /* Let's try this for MIPS too. */
13579         && kill(getpid(),SIGSTOP) < 0
13580 #endif /* MIPS */
13581         ) {                             /* If job control, suspend the job */
13582         perror("suspend");
13583         debug(F101,"psuspend error","",errno);
13584         return(-1);
13585     }
13586     debug(F100,"psuspend ok","",0);
13587     return(0);
13588 #else
13589     return(-1);
13590 #endif /* SIGTSTP */
13591 #endif /* NOJC */
13592 }
13593
13594 /*
13595   setuid package, by Kristoffer Eriksson, with contributions from Dean
13596   Long and fdc.
13597 */
13598
13599 /* The following is for SCO when CK_ANSILIBS is defined... */
13600 #ifdef M_UNIX
13601 #ifdef CK_ANSILIBS
13602 #ifndef NOGETID_PROTOS
13603 #define NOGETID_PROTOS
13604 #endif /* NOGETID_PROTOS */
13605 #endif /* CK_ANSILIBS */
13606 #endif /* M_UNIX */
13607
13608 #ifndef _POSIX_SOURCE
13609 #ifndef SUNOS4
13610 #ifndef NEXT
13611 #ifndef PS2AIX10
13612 #ifndef sequent
13613 #ifndef HPUX9
13614 #ifndef HPUX10
13615 #ifndef COHERENT
13616 #ifndef NOGETID_PROTOS
13617 _PROTOTYP( UID_T getuid, (void) );
13618 _PROTOTYP( UID_T geteuid, (void) );
13619 _PROTOTYP( UID_T getreuid, (void) );
13620 _PROTOTYP( UID_T getgid, (void) );
13621 _PROTOTYP( UID_T getegid, (void) );
13622 _PROTOTYP( UID_T getregid, (void) );
13623 #endif /* NOGETID_PROTOS */
13624 #else
13625 _PROTOTYP( UID_T getreuid, (void) );
13626 _PROTOTYP( UID_T getregid, (void) );
13627 #endif /* COHERENT */
13628 #endif /* HPUX10 */
13629 #endif /* HPUX9 */
13630 #endif /* sequent */
13631 #endif /* PS2AIX10 */
13632 #endif /* NEXT */
13633 #endif /* SUNOS4 */
13634 #endif /* _POSIX_SOURCE */
13635
13636 /*
13637 Subject: Set-user-id
13638 To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
13639 Date: Sat, 21 Apr 90 4:48:25 MES
13640 From: Kristoffer Eriksson <ske@pkmab.se>
13641
13642 This is a set of functions to be used in programs that may be run set-user-id
13643 and/or set-group-id. They handle both the case where the program is not run
13644 with such privileges (nothing special happens then), and the case where one
13645 or both of these set-id modes are used.  The program is made to run with the
13646 user's real user and group ids most of the time, except for when more
13647 privileges are needed.  Don't set-user-id to "root".
13648
13649 This works on System V and POSIX.  In BSD, it depends on the
13650 "saved-set-user-id" feature.
13651 */
13652
13653 #define UID_ROOT 0                      /* Root user and group ids */
13654 #define GID_ROOT 0
13655
13656 /*
13657   The following code defines the symbol SETEUID for UNIX systems based
13658   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
13659   seteuid() and setegid() instead of setuid() and setgid(), which still
13660   don't allow arbitrary switching.  It also avoids setreuid() and
13661   setregid(), which are included in BSD4.4 for compatibility only, are
13662   insecure, and print warnings to stderr under at least one system (NetBSD
13663   1.0).  Note that POSIX systems should still use setuid() and setgid();
13664   the seteuid() and setegid() functions are BSD4.4 extensions to the
13665   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
13666 */
13667 #ifdef BSD44
13668 #define SETEUID
13669 #endif /* BSD44 */
13670
13671 /*
13672   The following construction automatically defines the symbol SETREUID for
13673   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
13674   defined, then this program will use getreuid() and getregid() calls in
13675   preference to getuid() and getgid(), which in Berkeley-based Unixes do
13676   not allow arbitrary switching back and forth of real & effective uid.
13677   This construction also allows -DSETREUID to be put on the cc command line
13678   for any system that has and wants to use setre[ug]id().  It also prevents
13679   automatic definition of SETREUID if -DNOSETREU is included on the cc
13680   command line (or otherwise defined).
13681 */
13682 #ifdef FT18                             /* None of this for Fortune. */
13683 #define NOSETREU
13684 #endif /* FT18 */
13685
13686 #ifdef ANYBSD
13687 #ifndef BSD29
13688 #ifndef BSD41
13689 #ifndef SETREUID
13690 #ifndef NOSETREU
13691 #ifndef SETEUID
13692 #define SETREUID
13693 #endif /* SETEUID */
13694 #endif /* NOSETREU */
13695 #endif /* SETREUID */
13696 #endif /* !BSD41 */
13697 #endif /* !BSD29 */
13698 #endif /* ANYBSD */
13699
13700 /* Variables for user and group IDs. */
13701
13702 static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
13703 static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
13704
13705
13706 /* P R I V _ I N I  --  Initialize privileges package  */
13707
13708 /* Called as early as possible in a set-uid or set-gid program to store the
13709  * set-to uid and/or gid and step down to the users real uid and gid. The
13710  * stored id's can be temporarily restored (allowed in System V) during
13711  * operations that require the privilege.  Most of the time, the program
13712  * should execute in unpriviliged state, to not impose any security threat.
13713  *
13714  * Note: Don't forget that access() always uses the real id:s to determine
13715  * file access, even with privileges restored.
13716  *
13717  * Returns an error mask, with error values or:ed together:
13718  *   1 if setuid() fails,
13719  *   2 if setgid() fails, and
13720  *   4 if the program is set-user-id to "root", which can't be handled.
13721  *
13722  * Only the return value 0 indicates real success. In case of failure,
13723  * those privileges that could be reduced have been, at least, but the
13724  * program should be aborted none-the-less.
13725  *
13726  * Also note that these functions do not expect the uid or gid to change
13727  * without their knowing. It may work if it is only done temporarily, but
13728  * you're on your own.
13729  */
13730 int
13731 priv_ini() {
13732     int err = 0;
13733
13734 #ifndef HAVE_LOCKDEV
13735
13736     /* Save real ID:s. */
13737     realuid = getuid();
13738     realgid = getgid();
13739
13740     /* Save current effective ID:s, those set to at program exec. */
13741     privuid = geteuid();
13742     privgid = getegid();
13743
13744     /* If running set-uid, go down to real uid, otherwise remember that
13745      * no privileged uid is available.
13746      *
13747      * Exceptions:
13748      *
13749      * 1) If the real uid is already "root" and the set-uid uid (the
13750      * initial effective uid) is not "root", then we would have trouble
13751      * if we went "down" to "root" here, and then temporarily back to the
13752      * set-uid uid (not "root") and then again tried to become "root". I
13753      * think the "saved set-uid" is lost when changing uid from effective
13754      * uid "root", which changes all uid, not only the effective uid. But
13755      * in this situation, we can simply go to "root" and stay there all
13756      * the time. That should give sufficient privilege (understatement!),
13757      * and give the right uids for subprocesses.
13758      *
13759      * 2) If the set-uid (the initial effective uid) is "root", and we
13760      * change uid to the real uid, we can't change it back to "root" when
13761      * we need the privilege, for the same reason as in 1). Thus, we can't
13762      * handle programs that are set-user-id to "root" at all. The program
13763      * should be stopped.  Use some other uid.  "root" is probably too
13764      * privileged for such things, anyway. (The uid is reverted to the
13765      * real uid until termination.)
13766      *
13767      * These two exceptions have the effect that the "root" uid will never
13768      * be one of the two uids that are being switched between, which also
13769      * means we don't have to check for such cases in the switching
13770      * functions.
13771      *
13772      * Note that exception 1) is handled by these routines (by constantly
13773      * running with uid "root", while exception 2) is a serious error, and
13774      * is not provided for at all in the switching functions.
13775      */
13776     if (realuid == privuid)
13777         privuid = (UID_T) -1;           /* Not running set-user-id. */
13778
13779     /* If running set-gid, go down to real gid, otherwise remember that
13780      * no privileged gid is available.
13781      *
13782      * There are no exception like there is for the user id, since there
13783      * is no group id that is privileged in the manner of uid "root".
13784      * There could be equivalent problems for group changing if the
13785      * program sometimes ran with uid "root" and sometimes not, but
13786      * that is already avoided as explained above.
13787      *
13788      * Thus we can expect always to be able to switch to the "saved set-
13789      * gid" when we want, and back to the real gid again. You may also
13790      * draw the conclusion that set-gid provides for fewer hassles than
13791      * set-uid.
13792      */
13793
13794 #ifdef SUIDDEBUG
13795     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
13796     fprintf(stderr,"realuid=%d\n",realuid);
13797     fprintf(stderr,"privuid=%d\n",privuid);
13798 #endif /* SUIDDEBUG */
13799
13800     if (realgid == privgid)             /* If not running set-user-id, */
13801       privgid = (GID_T) -1;             /*  remember it this way. */
13802
13803     err = priv_off();                   /* Turn off setuid privilege. */
13804
13805     if (privuid == UID_ROOT)            /* If setuid to root, */
13806       err |= 4;                         /* return this error. */
13807
13808     if (realuid == UID_ROOT) {          /* If real id is root, */
13809         privuid = (UID_T) -1;           /* stay root at all times. */
13810 #ifdef ATT7300
13811         /* If Kermit installed SUID uucp and user is running as root */
13812         err &= ~1;                      /* System V R0 does not save UID */
13813 #endif /* ATT7300 */
13814     }
13815 #endif /* HAVE_LOCKDEV */
13816     return(err);
13817 }
13818
13819
13820 /* Macros for hiding the differences in UID/GID setting between various Unix
13821  * systems. These macros should always be called with both the privileged ID
13822  * and the non-privileged ID. The one in the second argument, will become the
13823  * effective ID. The one in the first argument will be retained for later
13824  * retrieval.
13825  */
13826 #ifdef SETREUID
13827 #ifdef SAVEDUID
13828 /* On BSD systems with the saved-UID feature, we just juggle the effective
13829  * UID back and forth, and leave the real UID at its true value.  The kernel
13830  * allows switching to both the current real UID, the effective UID, and the
13831  * UID which the program is set-UID to.  The saved set-UID always holds the
13832  * privileged UID for us, and the real UID will always be the non-privileged,
13833  * and we can freely choose one of them for the effective UID at any time.
13834  */
13835 #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
13836 #define switchgid(hidden,active) setregid( (GID_T) -1, active)
13837
13838 #else   /* SETREUID,!SAVEDUID */
13839
13840 /* On systems with setreXid() but without the saved-UID feature, notably
13841  * BSD 4.2, we swap the real and effective UIDs each time.  It's
13842  * the effective UID that we are interested in, but we have to retain the
13843  * unused UID somewhere to enable us to restore it later, and we do this
13844  * in the real UID.  The kernel only allows switching to either the current
13845  * real or the effective UID, unless you're "root".
13846  */
13847 #define switchuid(hidden,active)        setreuid(hidden,active)
13848 #define switchgid(hidden,active)        setregid(hidden,active)
13849 #endif
13850
13851 #else /* !SETREUID, !SAVEDUID */
13852
13853 #ifdef SETEUID
13854 /*
13855   BSD 4.4 works similarly to System V and POSIX (see below), but uses
13856   seteXid() instead of setXid() to change effective IDs.  In addition, the
13857   seteXid() functions work the same for "root" as for other users.
13858 */
13859 #define switchuid(hidden,active)        seteuid(active)
13860 #define switchgid(hidden,active)        setegid(active)
13861
13862 #else /* !SETEUID */
13863
13864 /* On System V and POSIX, the only thing we can change is the effective UID
13865  * (unless the current effective UID is "root", but initsuid() avoids that for
13866  * us).  The kernel allows switching to the current real UID or to the saved
13867  * set-UID.  These are always set to the non-privileged UID and the privileged
13868  * UID, respectively, and we only change the effective UID.  This breaks if
13869  * the current effective UID is "root", though, because for "root" setuid/gid
13870  * becomes more powerful, which is why initsuid() treats "root" specially.
13871  * Note: That special treatment maybe could be ignored for BSD?  Note: For
13872  * systems that don't fit any of these four cases, we simply can't support
13873  * set-UID.
13874  */
13875 #define switchuid(hidden,active)        setuid(active)
13876 #define switchgid(hidden,active)        setgid(active)
13877
13878 #endif /* SETEUID */
13879 #endif /* SETREUID */
13880
13881
13882 /* P R I V _ O N  --  Turn on the setuid and/or setgid */
13883
13884 /* Go to the privileged uid (gid) that the program is set-user-id
13885  * (set-group-id) to, unless the program is running unprivileged.
13886  * If setuid() fails, return value will be 1. If getuid() fails it
13887  * will be 2.  Return immediately after first failure, and the function
13888  * tries to restore any partial work done.  Returns 0 on success.
13889  * Group id is changed first, since it is less serious than user id.
13890  */
13891 int
13892 priv_on() {
13893 #ifndef HAVE_LOCKDEV
13894     if (privgid != (GID_T) -1)
13895       if (switchgid(realgid,privgid))
13896         return(2);
13897
13898     if (privuid != (UID_T) -1)
13899       if (switchuid(realuid,privuid)) {
13900           if (privgid != (GID_T) -1)
13901             switchgid(privgid,realgid);
13902           return(1);
13903       }
13904 #endif /* HAVE_LOCKDEV */
13905     return(0);
13906 }
13907
13908 /* P R I V _ O F F  --  Turn on the real uid and gid */
13909
13910 /* Return to the unprivileged uid (gid) after an temporary visit to
13911  * privileged status, unless the program is running without set-user-id
13912  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
13913  * in setgid() or:ed together. The functions tries to return both uid
13914  * and gid to unprivileged state, regardless of errors. Returns 0 on
13915  * success.
13916  */
13917 int
13918 priv_off() {
13919     int err = 0;
13920 #ifndef HAVE_LOCKDEV
13921     if (privuid != (UID_T) -1)
13922        if (switchuid(privuid,realuid))
13923           err |= 1;
13924
13925     if (privgid != (GID_T) -1)
13926        if (switchgid(privgid,realgid))
13927         err |= 2;
13928 #endif /* HAVE_LOCKDEV */
13929     return(err);
13930 }
13931
13932 /* Turn off privilege permanently.  No going back.  This is necessary before
13933  * a fork() on BSD43 machines that don't save the setUID or setGID, because
13934  * we swap the real and effective ids, and we don't want to let the forked
13935  * process swap them again and get the privilege back. It will work on other
13936  * machines too, such that you can rely on its effect always being the same,
13937  * for instance, even when you're in priv_on() state when this is called.
13938  * (Well, that part about "permanent" is on System V only true if you follow
13939  * this with a call to exec(), but that's what we want it for anyway.)
13940  * Added by Dean Long -- dlong@midgard.ucsc.edu
13941  */
13942 int
13943 priv_can() {
13944 #ifndef HAVE_LOCKDEV
13945 #ifdef SETREUID
13946     int err = 0;
13947     if (privuid != (UID_T) -1)
13948        if (setreuid(realuid,realuid))
13949           err |= 1;
13950
13951     if (privgid != (GID_T) -1)
13952         if (setregid(realgid,realgid))
13953           err |= 2;
13954
13955     return(err);
13956
13957 #else
13958 #ifdef SETEUID
13959     int err = 0;
13960     if (privuid != (UID_T) -1)
13961         if (setuid(realuid)) {
13962             debug(F101,"setuid failed","",errno);
13963             err |= 1;
13964             debug(F101,"ruid","",getuid());
13965             debug(F101,"euid","",geteuid());
13966         }
13967     debug(F101,"setuid","",realuid);
13968     if (privgid != (GID_T) -1)
13969         if (setgid(realgid)) {
13970             debug(F101,"setgid failed","",errno);
13971             err |= 2;
13972             debug(F101,"rgid","",getgid());
13973             debug(F101,"egid","",getegid());
13974         }
13975     debug(F101,"setgid","",realgid);
13976     return(err);
13977 #else
13978     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
13979     return(priv_off());
13980 #endif /* SETEUID */
13981 #endif /* SETREUID */
13982 #else
13983     return(0);
13984 #endif /* HAVE_LOCKDEV */
13985 }
13986
13987 /* P R I V _ O P N  --  For opening protected files or devices. */
13988
13989 int
13990 priv_opn(name, modes) char *name; int modes; {
13991     int x;
13992     priv_on();                          /* Turn privileges on */
13993     debug(F111,"priv_opn",name,modes);
13994     errno = 0;
13995     x = open(name, modes);              /* Try to open the device */
13996     debug(F101,"priv_opn result","",x);
13997     debug(F101,"priv_opn errno","",errno);
13998     priv_off();                         /* Turn privileges off */
13999     return(x);                          /* Return open's return code */
14000 }
14001
14002 /*  P R I V _ C H K  --  Check privileges.  */
14003
14004 /*  Try to turn them off.  If turning them off did not succeed, cancel them */
14005
14006 int
14007 priv_chk() {
14008     int x, y = 0;
14009     x = priv_off();                     /* Turn off privs. */
14010     if (x != 0 || getuid() == privuid || geteuid() == privuid)
14011       y = priv_can();
14012     if (x != 0 || getgid() == privgid || getegid() == privgid)
14013       y = y | priv_can();
14014     return(y);
14015 }
14016
14017 UID_T
14018 real_uid() {
14019     return(realuid);
14020 }
14021
14022 VOID
14023 ttimoff() {                             /* Turn off any timer interrupts */
14024     /* int xx; */
14025 /*
14026   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
14027   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
14028   cure (mask, really) a deeper problem with stray alarms that occurs on some
14029   systems, possibly having to do with sleep(), that caused core dumps.  It
14030   should be OK to do this, because no code in this module uses nested alarms.
14031   (But we still have to watch out for SCRIPT and DIAL...)
14032 */
14033     /* xx = */ alarm(0);
14034     /* debug(F101,"ttimoff alarm","",xx); */
14035     if (saval) {                        /* Restore any previous */
14036         signal(SIGALRM,saval);          /* alarm handler. */
14037         /* debug(F101,"ttimoff alarm restoring saval","",saval); */
14038         saval = NULL;
14039     } else {
14040         signal(SIGALRM,SIG_IGN);        /* Used to be SIG_DFL */
14041         /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
14042     }
14043 }
14044
14045
14046 int
14047 tt_is_secure() {          /* Tells whether the current connection is secure */
14048
14049     if (ttyfd == -1)
14050       return(0);
14051
14052     if (0
14053 #ifdef SSHBUILTIN
14054         || IS_SSH()
14055 #endif /* SSHBUILTIN */
14056 #ifdef CK_ENCRYPTION
14057         || ck_tn_encrypting() && ck_tn_decrypting()
14058 #endif /* CK_ENCRYPTION */
14059 #ifdef CK_SSL
14060         || tls_active_flag || ssl_active_flag
14061 #endif /* CK_SSL */
14062 #ifdef RLOGCODE
14063 #ifdef CK_KERBEROS
14064 #ifdef CK_ENCRYPTION
14065         || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
14066 #endif /* CK_ENCRYPTION */
14067 #endif /* CK_KERBEROS */
14068 #endif /* RLOGCODE */
14069         )
14070       return(1);
14071     return(0);
14072 }
14073
14074 #ifdef CK_REDIR
14075   
14076 /* External protocol handler parameters from ckuus3.c */
14077 extern int exp_handler, exp_stderr, exp_timo;
14078
14079 #ifdef SELECT
14080 #ifdef NETPTY
14081
14082 /* The right size is 24576 */
14083
14084 #ifndef PTY_PBUF_SIZE                   /* Size of buffer to read from pty */
14085 #define PTY_PBUF_SIZE 24576             /* and write to net. */
14086 #endif  /* PTY_PBUF_SIZE */
14087
14088 #ifndef PTY_TBUF_SIZE                   /* Size of buffer to read from net */
14089 #define PTY_TBUF_SIZE 24576             /* and write to pty. */
14090 #endif  /* PTY_TBUF_SIZE */
14091
14092 #ifdef O_NDELAY                         /* Whether to use nonblocking */
14093 #ifndef PTY_NO_NDELAY                   /* reads on the pseudoterminal */
14094 #ifndef PTY_USE_NDELAY
14095 #define PTY_USE_NDELAY
14096 #endif  /* PTY_USE_NDELAY */
14097 #endif  /* PTY_NO_NDELAY */
14098 #endif  /* O_NDELAY */
14099
14100 #ifndef HAVE_OPENPTY
14101 #ifndef USE_CKUPTY_C
14102 #define USE_CKUPTY_C
14103 #endif /* USE_CKUPTY_C */
14104 #endif /* HAVE_OPENPTY */
14105
14106 VOID
14107 pty_make_raw(fd) int fd; {
14108     int x = -23, i;
14109
14110 #ifdef BSD44ORPOSIX                     /* POSIX */
14111     struct termios tp;
14112 #else
14113 #ifdef ATTSV                            /* AT&T UNIX */
14114 #ifdef CK_ANSIC
14115     struct termio tp = {0};
14116 #else
14117     struct termio tp;
14118 #endif  /* CK_ANSIC */
14119 #else
14120     struct sgttyb tp;                   /* Traditional */
14121 #endif /* ATTSV */
14122 #endif /* BSD44ORPOSIX */
14123
14124     debug(F101,"pty_make_raw fd","",fd);
14125     errno = 0;
14126
14127 #ifdef BSD44ORPOSIX                     /* POSIX */
14128     x = tcgetattr(fd,&tp);
14129     debug(F101,"pty_make_raw tcgetattr","",x);
14130 #else
14131 #ifdef ATTSV                            /* AT&T UNIX */
14132     x = ioctl(fd,TCGETA,&tp);
14133     debug(F101,"pty_make_raw TCGETA ioctl","",x);
14134 #else
14135     x = gtty(fd,&tp);
14136     debug(F101,"pty_make_raw ttty","",x);
14137 #endif /* ATTSV */
14138 #endif /* BSD44ORPOSIX */
14139     debug(F101,"pty_make_raw GET errno","",errno);
14140
14141 #ifdef USE_CFMAKERAW
14142     errno = 0;
14143     cfmakeraw(&tp);
14144     debug(F101,"pty_make_raw cfmakeraw errno","",errno);
14145 #else  /* USE_CFMAKERAW */
14146
14147 #ifdef COMMENT
14148
14149 /* This very simple version recommended by Serg Iakolev doesn't work */
14150
14151     tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
14152     tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
14153     tp.c_cflag &= ~(CSIZE|PARENB);
14154     tp.c_cflag |= CS8;
14155     tp.c_oflag &= ~(OPOST);
14156     tp.c_cc[VMIN] = 1;
14157     tp.c_cc[VTIME] = 0;
14158
14159     debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
14160     debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
14161     debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
14162     debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
14163     debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
14164
14165 #else
14166 #ifdef COMMENT
14167 /*
14168   In this version we unset everything and then set only the
14169   bits we know we need.
14170 */
14171     /* iflags */
14172     tp.c_iflag = 0L;
14173     tp.c_iflag |= IGNBRK;
14174 #ifdef IMAXBEL
14175     tp.c_iflag |= IMAXBEL;
14176 #endif /* IMAXBEL */
14177
14178     /* oflags */
14179     tp.c_oflag = 0L;
14180
14181     /* lflags */
14182     tp.c_lflag = 0L;
14183 #ifdef NOKERNINFO
14184     tp.c_lflag |= NOKERNINFO;
14185 #endif  /* NOKERNINFO */
14186
14187     /* cflags */
14188     tp.c_cflag = 0L;
14189     tp.c_cflag |= CS8|CREAD;
14190
14191     for (i = 0; i < NCCS; i++) {        /* No special characters */
14192         tp.c_cc[i] = 0;
14193     }
14194 #ifdef VMIN
14195     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14196 #endif  /* VMIN */
14197     debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
14198     debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
14199     debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
14200     debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
14201     debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
14202
14203 #else  /* COMMENT */
14204 /*
14205   In this version we set or unset every single flag explicitly.  It works a
14206   bit better than the simple version just above, but it's still far from
14207   adequate.
14208 */
14209     /* iflags */
14210     tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
14211     tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
14212     tp.c_iflag |= IGNBRK;
14213 #ifdef IMAXBEL
14214 #ifdef COMMENT
14215     tp.c_iflag |= IMAXBEL;
14216 #else
14217     tp.c_iflag &= ~IMAXBEL;
14218 #endif /* COMMENT */
14219 #endif /* IMAXBEL */
14220 #ifdef IUCLC
14221     tp.c_iflag &= ~IUCLC;
14222 #endif /* IUCLC */
14223
14224     /* oflags */
14225 #ifdef BSDLY
14226     tp.c_oflag &= ~BSDLY;
14227 #endif /* BSDLY */
14228 #ifdef CRDLY
14229     tp.c_oflag &= ~CRDLY;
14230 #endif /* CRDLY */
14231 #ifdef FFDLY
14232     tp.c_oflag &= ~FFDLY;
14233 #endif /* FFDLY */
14234 #ifdef NLDLY
14235     tp.c_oflag &= ~NLDLY;
14236 #endif /* NLDLY */
14237 #ifdef TABDLY
14238     tp.c_oflag &= ~TABDLY;
14239 #endif /* TABDLY */
14240 #ifdef VTDLY
14241     tp.c_oflag &= ~VTDLY;
14242 #endif /* VTDLY */
14243 #ifdef OFDEL
14244     tp.c_oflag &= ~OFDEL;
14245 #endif /* OFDEL */
14246 #ifdef OFILL
14247     tp.c_oflag &= ~OFILL;
14248 #endif /* OFILL */
14249 #ifdef OLCUC
14250     tp.c_oflag &= ~OLCUC;
14251 #endif /* OLCUC */
14252 #ifdef CMSPAR
14253     tp.c_oflag &= ~CMSPAR;
14254 #endif /* CMSPAR */
14255     tp.c_oflag &= ~OPOST;
14256 #ifdef OXTABS
14257     tp.c_oflag &= ~OXTABS;
14258 #endif /* OXTABS */
14259 #ifdef COMMENT
14260 #ifdef ONOCR
14261     tp.c_oflag &= ~ONOCR;               /* Maybe should be |=? */
14262     tp.c_oflag |= ONOCR;                /* makes no difference either way */
14263 #endif /* ONOCR */
14264 #endif /* COMMENT */
14265 #ifdef ONOEOT
14266     tp.c_oflag &= ~ONOEOT;
14267 #endif /* ONOEOT */
14268 #ifdef ONLRET
14269     tp.c_oflag &= ~ONLRET;
14270 #endif /* ONLRET */
14271 #ifdef ONLCR
14272     tp.c_oflag &= ~ONLCR;
14273 #endif /* ONLCR */
14274 #ifdef OCRNL
14275     tp.c_oflag &= ~OCRNL;
14276 #endif /* OCRNL */
14277
14278     /* lflags */
14279     tp.c_lflag &= ~ECHO;
14280 #ifdef ECHOE
14281     tp.c_lflag &= ~ECHOE;
14282 #endif /* ECHOE */
14283 #ifdef ECHONL
14284     tp.c_lflag &= ~ECHONL;
14285 #endif /* ECHONL */
14286 #ifdef ECHOPRT
14287     tp.c_lflag &= ~ECHOPRT;
14288 #endif /* ECHOPRT */
14289 #ifdef ECHOKE
14290     tp.c_lflag &= ~ECHOKE;
14291 #endif /* ECHOKE */
14292 #ifdef ECHOCTL
14293     tp.c_lflag &= ~ECHOCTL;
14294 #endif /* ECHOCTL */
14295 #ifdef XCASE
14296     tp.c_lflag &= ~XCASE;
14297 #endif /* XCASE */
14298 #ifdef ALTWERASE
14299     tp.c_lflag &= ~ALTWERASE;
14300 #endif /* ALTWERASE */
14301 #ifdef EXTPROC
14302     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
14303 #else
14304     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
14305 #endif  /* EXTPROC */
14306 #ifdef NOKERNINFO
14307     tp.c_lflag |= NOKERNINFO;
14308 #endif  /* NOKERNINFO */
14309 #ifndef COMMENT
14310     tp.c_lflag &= ~NOFLSH;              /* TRY IT THE OTHER WAY? */
14311 #else
14312     tp.c_lflag |= NOFLSH;               /* No, this way is worse */
14313 #endif /* COMMENT */
14314
14315     /* cflags */
14316     tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
14317     tp.c_cflag |= CS8|CREAD;
14318
14319 #ifdef MDMBUF
14320     tp.c_cflag &= ~(MDMBUF);
14321 #else
14322 #ifdef CCAR_OFLOW
14323     tp.c_cflag &= ~(CCAR_OFLOW);        /* two names for the same thing */
14324 #endif /* CCAR_OFLOW */
14325 #endif /* MDMBUF */
14326
14327 #ifdef CCTS_OFLOW
14328     tp.c_cflag &= ~(CCTS_OFLOW);
14329 #endif /* CCTS_OFLOW */
14330 #ifdef CDSR_OFLOW
14331     tp.c_cflag &= ~(CDSR_OFLOW);
14332 #endif /* CDSR_OFLOW */
14333 #ifdef CDTR_IFLOW
14334     tp.c_cflag &= ~(CDTR_IFLOW);
14335 #endif /* CDTR_IFLOW */
14336 #ifdef CRTS_IFLOW
14337     tp.c_cflag &= ~(CRTS_IFLOW);
14338 #endif /* CRTS_IFLOW */
14339 #ifdef CRTSXOFF
14340     tp.c_cflag &= ~(CRTSXOFF);
14341 #endif /* CRTSXOFF */
14342 #ifdef CRTSCTS
14343     tp.c_cflag &= ~(CRTSCTS);
14344 #endif /* CRTSCTS */
14345 #ifdef CLOCAL
14346     tp.c_cflag &= ~(CLOCAL);
14347 #endif /* CLOCAL */
14348 #ifdef CSTOPB
14349     tp.c_cflag &= ~(CSTOPB);
14350 #endif /* CSTOPB */
14351 #ifdef HUPCL
14352     tp.c_cflag &= ~(HUPCL);
14353 #endif /* HUPCL */
14354
14355     for (i = 0; i < NCCS; i++) {        /* No special characters */
14356         tp.c_cc[i] = 0;
14357     }
14358 #ifdef VMIN
14359     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14360 #endif  /* VMIN */
14361     debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
14362     debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
14363     debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
14364     debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
14365     debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
14366 #endif /* COMMENT */
14367 #endif /* COMMENT */
14368
14369     errno = 0;
14370 #ifdef BSD44ORPOSIX                     /* POSIX */
14371     x = tcsetattr(fd,TCSANOW,&tp);
14372     debug(F101,"pty_make_raw tcsetattr","",x);
14373 #else
14374 #ifdef ATTSV                            /* AT&T UNIX */
14375     x = ioctl(fd,TCSETA,&tp);
14376     debug(F101,"pty_make_raw ioctl","",x);
14377 #else
14378     x = stty(fd,&tp);                   /* Traditional */
14379     debug(F101,"pty_make_raw stty","",x);
14380 #endif /* ATTSV */
14381 #endif /* BSD44ORPOSIX */
14382     debug(F101,"pty_make_raw errno","",errno);
14383
14384 #endif /* __NetBSD__ */
14385 }
14386
14387 static int
14388 pty_chk(fd) int fd; {
14389     int x, n = 0;
14390     errno = 0;
14391 #ifdef FIONREAD
14392     x = ioctl(fd, FIONREAD, &n);        /* BSD and most others */
14393     ckmakmsg(msgbuf,500,
14394              "pty_chk ioctl FIONREAD errno=",
14395              ckitoa(errno),
14396              " count=",
14397              ckitoa(n));
14398     debug(F100,msgbuf,"",0);
14399 #else
14400     n = rdchk(fd);
14401     debug(F101,"pty_chk rdchk","",n);
14402 #ifdef RDCHK
14403 #endif  /* RDCHK */
14404 #endif  /* FIONREAD */
14405     return((n > -1) ? n : 0);
14406 }
14407
14408 static int
14409 pty_get_status(fd,pid) int fd; PID_T pid; {
14410     int x, status = -1;
14411     PID_T w;
14412
14413     debug(F101,"pty_get_status fd","",fd);
14414     debug(F101,"pty_get_status pid","",pid);
14415
14416     if (pexitstat > -1)
14417       return(pexitstat);
14418
14419 #ifdef COMMENT
14420     /* Not only unnecessary but harmful */
14421     errno = 0;
14422     x = kill(pty_fork_pid,0);
14423     debug(F101,"pty_get_status kill value","",x);
14424     debug(F101,"pty_get_status kill errno","",errno);
14425     if (x > -1 && errno != ESRCH)
14426       return(-1);                       /* Fork still there */
14427     /* Fork seems to be gone */
14428 #endif  /* COMMENT */
14429
14430     errno = 0;
14431     x = waitpid(pty_fork_pid,&status,WNOHANG);
14432     debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
14433     if (x <= 0 && errno == 0) {
14434         debug(F101,"pty_get_status waitpid return","",-1);
14435         return(-1);
14436     }
14437     if (x > 0) {
14438         if (x != pty_fork_pid)
14439           debug(F101,
14440                 "pty_get_status waitpid pid doesn't match","",pty_fork_pid); 
14441         debug(F101,"pty_get_status waitpid status","",status);
14442         debug(F101,"pty_get_status waitpid errno","",errno);
14443         if (WIFEXITED(status)) {
14444             debug(F100,"pty_get_status WIFEXITED","",0);
14445             status = WEXITSTATUS(status);
14446             debug(F101,"pty_get_status fork exit status","",status);
14447 #ifdef COMMENT
14448             end_pty();
14449 #endif  /* COMMENT */
14450             close(fd);
14451             pexitstat = status;
14452         } else {
14453             debug(F100,"pty_get_status waitpid unexpected status","",0);
14454         }
14455     }
14456     debug(F101,"pty_get_status return status","",status);
14457     return(status);
14458 }
14459
14460 /* t t p t y c m d  --  Run command on pty and forward to net */
14461
14462 /*
14463   Needed for running external protocols on secure connections.
14464   For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
14465   connection, and then needs to transfer a file with Zmodem, which is
14466   an external program, this routine reads Zmodem's output, encrypts it,
14467   and then forwards it out the connection, and reads the encrypted data
14468   stream coming in from the connection, decrypts it, and forwards it to
14469   Zmodem.
14470
14471   Works like a TCP/IP port forwarder except one end is a pty rather
14472   than a socket, which introduces some complications:
14473
14474    . On most platforms, select() always indicates the output side of
14475      the pty has characters waiting to be read, even when it doesn't,
14476      even when the pty process has already exited.
14477
14478    . Nonblocking reads must be used on the pty, because there is no
14479      way on certain platforms (e.g. NetBSD) to find out how many characters
14480      are available to be read (the FIONREAD ioctl always says 0).  The code
14481      also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
14482      defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
14483      result in single-byte reads and writes (NetBSD again).
14484
14485    . Testing for "EOF" on the pty is problematic.  select() never gives
14486      any indication.  After the pty process has exited and the fork has
14487      disappeared, read() can still return with 0 bytes read but without an
14488      error (NetBSD); no known test on the pty file descriptor will indicate
14489      that it is no longer valid.  The process ID of the pty fork can be
14490      tested on some platforms (NetBSD, luckily) but not others (Solaris,
14491      Linux).
14492
14493   On the network side, we use ttinc() and ttoc(), which, for network 
14494   connections, handle any active security methods.
14495
14496   Call with s = command.
14497   Returns 0 on failure, 1 on success.
14498   fdc - December 2006 - August 2007.
14499
14500   NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
14501   defined in the header files, which should be true of every recent Unix
14502   platform.  If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
14503   building C-Kermit:
14504
14505     touch ckutio.c
14506     make platformname KFLAGS=-DPTY_NO_NODELAY
14507 */
14508 static int have_pty = 0;                /* Do we have a pty? */
14509
14510 static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */
14511
14512 static VOID
14513 sigchld_handler(sig) int sig; {
14514     have_pty = 0;                       /* We don't have a pty */
14515 #ifdef DEBUG
14516     if (save_sigchld) {
14517         (VOID) signal(SIGCHLD,save_sigchld);
14518         save_sigchld = NULL;
14519     }
14520     if (deblog) {
14521         debug(F100,"**************","",0);
14522         debug(F100,"SIGCHLD caught","",0);
14523         debug(F100,"**************","",0);
14524     }
14525 #endif  /* DEBUG */
14526 }
14527 #define HAVE_IAC 1
14528 #define HAVE_CR  2
14529
14530 int
14531 ttptycmd(s) char *s; {
14532     CHAR tbuf[PTY_TBUF_SIZE];           /* Read from net, write to pty */
14533     int tbuf_avail = 0;                 /* Pointers for tbuf */
14534     int tbuf_written = 0;
14535     static int in_state = 0;            /* For TELNET IAC and NVT in */
14536     static int out_prev = 0;            /* Simpler scheme for out */
14537
14538     CHAR pbuf[PTY_PBUF_SIZE];           /* Read from pty, write to net */
14539     CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
14540     int pbuf_avail = 0;                 /* Pointers for pbuf */
14541     int pbuf_written = 0;
14542
14543     int ptyfd = -1;                     /* Pty file descriptor */
14544     int have_net = 0;                   /* We have a network connection */
14545     int pty_err = 0;                    /* Got error on pty */
14546     int net_err = 0;                    /* Got error on net */
14547     int status = -1;                    /* Pty process exit status */
14548     int rc = 0;                         /* Our return code */
14549
14550     int x1 = 0, x2 = 0;                 /* Workers... */
14551     int c, n, m, t, x;                  /* Workers */
14552
14553     long seconds_to_wait = 0L;          /* select() timeout */
14554     struct timeval tv, *tv2;            /* For select() */
14555 #ifdef INTSELECT
14556     int in, out, err;                   /* For select() */
14557 #else
14558     fd_set in, out, err;
14559 #endif /* INTSELECT */
14560     int nfds = 0;                       /* For select() */
14561
14562     int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
14563     int read_net_bytes = 0;             /* Stats */
14564     int write_net_bytes = 0;            /* Stats */
14565     int read_pty_bytes = 0;             /* Stats */
14566     int write_pty_bytes = 0;            /* Stats */
14567     int is_tn = 0;                      /* TELNET protocol is active */
14568
14569     int masterfd = -1;
14570     int slavefd = -1;
14571 #ifndef USE_CKUPTY_C
14572     struct termios term;
14573     struct winsize twin;
14574     struct stringarray * q;
14575     char ** args = NULL;
14576 #endif /* USE_CKUPTY_C */
14577
14578     in_state = 0;                       /* No previous character yet */
14579
14580     if (ttyfd == -1) {
14581         printf("?Sorry, communication channel is not open\n");
14582         return(0);
14583     } else {
14584         have_net = 1;
14585     }
14586     if (nopush) {
14587         debug(F100,"ttptycmd fail: nopush","",0);
14588         return(0);
14589     }
14590     if (!s) s = "";                     /* Defense de bogus arguments */
14591     if (!*s) return(0);
14592     pexitstat = -1;                     /* Fork process exit status */
14593
14594 #ifdef TNCODE
14595     is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
14596             (!xlocal && sstelnet);
14597 #endif /* TNCODE */
14598
14599     debug(F110,"ttptycmd command",s,0);
14600     debug(F101,"ttptycmd ttyfd","",ttyfd);
14601     debug(F101,"ttptycmd is_tn","",is_tn);
14602     debug(F101,"ttptycmd ckermit pid","",getpid());
14603
14604 #ifdef USE_CKUPTY_C
14605     /* Call ckupty.c module to get and set up the pty fork */
14606     /* fc 1 == "run an external protocol" */
14607     debug(F100,"ttptycmd using ckupty.c","",0);
14608     if (do_pty(&ptyfd,s,1) < 0) {       /* Start the command on a pty */
14609         debug(F100,"ttptycmd do_pty fails","",0);
14610         return(0);
14611     }
14612     masterfd = ptyfd;
14613     pty_master_fd = ptyfd;
14614 #ifdef COMMENT
14615     slavefd = pty_slave_fd;             /* This is not visible to us */
14616 #endif /* COMMENT */
14617     debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
14618     debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
14619     debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
14620 #ifndef SOLARIS
14621     /* "ioctl inappropriate on device" for pty master */
14622     pty_make_raw(masterfd);
14623 #endif /* SOLARIS */
14624
14625 #else /* USE_CKUPTY_C */
14626
14627     debug(F100,"ttptycmd OPENPTY","",0);
14628     if (tcgetattr(0, &term) == -1) {    /* Get controlling terminal's modes */
14629         perror("tcgetattr");
14630         return(0);
14631     }
14632     if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
14633         perror("ioctl TIOCGWINSZ");
14634         return(0);
14635     }
14636     if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
14637         debug(F101,"ttptycmd openpty failed errno","",errno);
14638         perror("opentpy");
14639         return(0);
14640     }
14641     debug(F101,"ttptycmd openpty masterfd","",masterfd);
14642     debug(F101,"ttptycmd openpty slavefd","",slavefd);
14643     pty_master_fd = masterfd;
14644     pty_slave_fd = slavefd;
14645     debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
14646
14647     /* Put pty master in raw mode but let forked app control the slave */
14648     pty_make_raw(masterfd);
14649
14650 #ifdef COMMENT
14651 #ifdef TIOCREMOTE
14652     /* TIOCREMOTE,0 = disable all termio processing */
14653     x = ioctl(masterfd, TIOCREMOTE, 1);
14654     debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
14655 #endif  /* TIOCREMOTE */
14656 #ifdef TIOCTTY
14657     /* TIOCTTY,0 = disable all termio processing */
14658     x = ioctl(masterfd, TIOCTTY, 0);
14659     debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
14660 #endif  /* TIOCTTY */
14661 #endif /* COMMENT */
14662
14663     have_pty = 1;                       /* We have an open pty */
14664     save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
14665
14666     pty_fork_pid = fork();              /* Make fork for external protocol */
14667     debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
14668     if (pty_fork_pid == -1) {
14669         perror("fork");
14670         return(0);
14671     } else if (pty_fork_pid == 0) {     /* In new fork */
14672         int x;
14673         debug(F101,"ttptycmd new fork pid","",getpid());
14674         close(masterfd);                /* Slave quarters no masters allowed */
14675         x = setsid();
14676         debug(F101,"ttptycmd new fork setsid","",x);
14677         if (x == -1) {
14678             perror("ttptycmd setsid");
14679             exit(1);
14680         }
14681         signal(SIGINT,SIG_IGN);         /* Let upper fork catch this */
14682         
14683 #ifdef COMMENT
14684 #ifdef TIOCSCTTY
14685         /* Make pty the controlling terminal for the process */
14686         /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
14687         x = ioctl(slavefd, TIOCSCTTY, NULL);
14688         debug(F101,"ttptycmd TIOCSCTTY","",x);
14689 #endif  /* TIOCSCTTY */
14690 #endif  /* COMMENT */
14691
14692         /* Initialize slave pty modes and size to those of our terminal */
14693         if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
14694             perror("ttptycmd tcsetattr");
14695             exit(1);
14696         }
14697         if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
14698             perror("ttptycmd ioctl");
14699             exit(1);
14700         }
14701 #ifdef COMMENT
14702 #ifdef TIOCNOTTY
14703         /* Disassociate this process from its terminal */
14704         /* THIS HAS NO EFFECT */
14705         x = ioctl(slavefd, TIOCNOTTY, NULL);
14706         debug(F101,"ttptycmd TIOCNOTTY","",x);
14707 #endif  /* TIOCNOTTY */
14708 #endif  /* COMMENT */
14709
14710 #ifdef COMMENT
14711 #ifdef SIGTTOU  
14712         /* Ignore terminal output interrupts */
14713         /* THIS HAS NO EFFECT */
14714         debug(F100,"ttptycmd ignoring SIGTTOU","",0);
14715         signal(SIGTTOU, SIG_IGN);
14716 #endif  /* SIGTTOU */
14717 #ifdef SIGTSTP  
14718         /* Ignore terminal output interrupts */
14719         /* THIS HAS NO EFFECT */
14720         debug(F100,"ttptycmd ignoring SIGTSTP","",0);
14721         signal(SIGTSTP, SIG_IGN);
14722 #endif  /* SIGTSTP */
14723 #endif  /* COMMENT */
14724
14725         pty_make_raw(slavefd);          /* Put it in rawmode */
14726
14727         errno = 0;
14728         if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
14729             dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
14730             debug(F101,"ttptycmd new fork dup2 error","",errno);
14731             perror("ttptycmd dup2");
14732             exit(1);
14733         }
14734         debug(F100,"ttptycmd new fork dup2 ok","",0);
14735
14736         /* Parse external protocol command line */
14737         q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
14738         if (!q) {
14739             debug(F100,"ttptycmd cksplit failed","",0);
14740             exit(1);
14741         } else {
14742             int i, n;
14743             debug(F100,"ttptycmd cksplit ok","",0);
14744             n = q->a_size;
14745             args = q->a_head + 1;
14746             for (i = 0; i <= n; i++) {
14747                 if (!args[i]) {
14748                     break;
14749                 } else {
14750                     /* sometimes cksplit() doesn't terminate the list */
14751                     if ((i == n) && args[i]) {
14752                         if ((int)strlen(args[i]) == 0)
14753                           makestr(&(args[i]),NULL);
14754                     }
14755                 }
14756             }       
14757         }
14758 #ifdef COMMENT
14759 /*
14760   Putting the slave pty in rawmode should not be necessary because the
14761   external protocol program is supposed to do that itself.  Yet doing this
14762   here cuts down on Zmodem binary-file transmission errors by 30-50% but
14763   still doesn't eliminate them.
14764 */
14765         pty_make_raw(STDIN_FILENO);
14766         pty_make_raw(STDOUT_FILENO);
14767 #endif /* COMMENT */
14768
14769         debug(F100,"ttptycmd execvp'ing external protocol","",0);
14770         execvp(args[0],args);
14771         perror("execvp failed");
14772         debug(F101,"ttptycmd execvp failed","",errno);
14773         close(slavefd);
14774         exit(1);
14775     } 
14776     /* (there are better ways to do this...) */
14777     msleep(1000);                 /* Make parent wait for child to be ready */
14778     ptyfd = masterfd;                   /* We talk to the master */
14779
14780 #endif /* USE_CKUPTY_C */
14781
14782     debug(F101,"ttptycmd ptyfd","",ptyfd);
14783     if (ptyfd < 0) {
14784         printf("?Failure to get pty\n");
14785         return(-9);
14786     }
14787     have_pty = 1;             /* We have an open pty or we wouldn't he here */
14788
14789     debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
14790     debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
14791
14792 #ifdef PTY_USE_NDELAY
14793     /* 
14794        NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
14795        on the pty, we don't need nonblocking reads.  Performance of either
14796        method seems to be about the same, so use whatever works.
14797     */
14798     errno = 0;
14799     x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
14800     ckmakmsg(msgbuf,500,
14801              "ttptycmd set O_NDELAY errno=",
14802              ckitoa(errno),
14803              " fcntl=",
14804              ckitoa(x));
14805     debug(F100,msgbuf,"",0);
14806 #endif /* PTY_USE_NDELAY */
14807
14808 #ifdef COMMENT
14809 /* Not necessary, the protocol module already did this */
14810
14811 #ifdef USE_CFMAKERAW
14812     if (tcgetattr(ttyfd, &term) > -1) {
14813         cfmakeraw(&term);
14814         debug(F101,"ttptycmd net cfmakeraw errno","",errno);
14815         x tcsetattr(ttyfd, TCSANOW, &term);
14816         debug(F101,"ttptycmd net tcsetattr","",x);
14817         debug(F101,"ttptycmd net tcsetattr","",errno);
14818     }
14819 #else
14820     if (local)                          /* Put network connection in */
14821       ttpkt(ttspeed,ttflow,ttprty);     /* "packet mode". */
14822     else
14823       conbin((char)escchr);             /* OR... pty_make_raw(0) */
14824 #endif /* USE_CFMAKERAW */
14825 #endif /* COMMENT */
14826
14827 #ifdef TNCODE
14828     if (is_tn) {
14829       debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
14830       debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
14831     }
14832 #endif /* TNCODE */
14833
14834     debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
14835
14836     while (have_pty || have_net) {
14837         FD_ZERO(&in);                   /* Initialize select() structs */
14838         FD_ZERO(&out);
14839         FD_ZERO(&err);                  /* (not used because useless) */
14840         nfds = -1;
14841
14842         debug(F101,"ttptycmd loop top have_pty","",have_pty);
14843         debug(F101,"ttptycmd loop top have_net","",have_net);
14844
14845         /* Pty is open and we have room to read from it? */
14846         if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
14847             debug(F100,"ttptycmd FD_SET ptyfd in","",0);
14848             FD_SET(ptyfd, &in);
14849             nfds = ptyfd;
14850         }
14851         /* Network is open and we have room to read from it? */
14852         if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
14853             debug(F100,"ttptycmd FD_SET ttyfd in","",0);
14854             FD_SET(ttyfd, &in);
14855             if (ttyfd > nfds) nfds = ttyfd;
14856         }
14857         /* Pty is open and we have stuff to write to it? */
14858         if (have_pty && tbuf_avail - tbuf_written > 0) {
14859             debug(F100,"ttptycmd FD_SET ptyfd out","",0);
14860             FD_SET (ptyfd, &out);
14861             if (ptyfd > nfds) nfds = ptyfd;
14862         }
14863         /* Net is open and we have stuff to write to it? */
14864         debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
14865               pbuf_avail - pbuf_written);
14866         if (have_net && pbuf_avail - pbuf_written > 0) {
14867             debug(F100,"ttptycmd FD_SET ttyfd out","",0);
14868             FD_SET (ttyfd, &out);
14869             if (ttyfd > nfds) nfds = ttyfd;
14870         }
14871         /* We don't use err because it's not really for errors, */
14872         /* but for out of band data on the TCP socket, which, if it is */
14873         /* to be handled at all, is handled in the tt*() routines */
14874
14875         nfds++;                         /* 0-based to 1-based */
14876         debug(F101,"ttptycmd nfds","",nfds);
14877         if (!nfds) {
14878             debug(F100,"ttptycmd NO FDs set for select","",0);
14879             if (have_pty) {
14880                 /* This is not right -- sleeping won't accomplish anything */
14881                 debug(F101,"ttptycmd msleep","",100);
14882                 msleep(100);        
14883             } else {
14884                 debug(F100,"ttptycmd no pty - quitting loop","",0);
14885                 break;
14886             }
14887         }
14888         errno = 0;
14889
14890         if (seconds_to_wait > 0L) {     /* Timeout in case nothing happens */
14891             tv.tv_sec = seconds_to_wait; /* for a long time */
14892             tv.tv_usec = 0L;            
14893             tv2 = &tv;
14894         } else {
14895             tv2 = NULL;
14896         }
14897         x = select(nfds, &in, &out, NULL, tv2);
14898         debug(F101,"ttptycmd select","",x);
14899         if (x < 0) {
14900             if (errno == EINTR)
14901               continue;
14902             debug(F101,"ttptycmd select error","",errno);
14903             break;
14904         }
14905         if (x == 0) {
14906             debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait); 
14907             if (have_pty) {
14908                 status = pty_get_status(ptyfd,pty_fork_pid);
14909                 debug(F101,"ttptycmd pty_get_status A","",status);
14910                 if (status > -1) pexitstat = status;
14911                 have_pty = 0;
14912             }
14913             break;
14914         }
14915         /* We want to handle any pending writes first to make room */
14916         /* for new incoming. */
14917
14918         if (FD_ISSET(ttyfd, &out)) {    /* Can write to net? */
14919             CHAR * s;
14920             s = pbuf + pbuf_written;    /* Current spot for sending */
14921 #ifdef TNCODE
14922             if (is_tn) {                /* ttol() doesn't double IACs */
14923                 CHAR c;                 /* Rewrite string with IACs doubled */
14924                 int i;
14925                 s = pbuf + pbuf_written; /* Source */
14926                 x = 0;                   /* Count */
14927                 for (i = 0; i < pbuf_avail - pbuf_written; i++) {
14928                     c = s[i];           /* Next character */
14929                     if (c == IAC) {     /* If it's IAC */
14930                         dbuf[x++] = c;  /* put another one */
14931                         debug(F000,">>> QUOTED IAC","",c);
14932                     } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */
14933                         if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
14934                             c = 0x00;
14935                             dbuf[x++] = c;
14936                             debug(F000,">>> CR-NUL","",c);
14937                         }                       
14938                     }
14939                     dbuf[x++] = c;      /* Copy and count it */
14940                     debug(F000,">>> char",ckitoa(in_state),c);
14941                     out_prev = c;
14942                 }
14943                 s = dbuf;               /* New source */
14944             } else
14945 #endif /* TNCODE */
14946               x = pbuf_avail - pbuf_written; /* How much to send */
14947
14948             debug(F101,"ttptycmd bytes to send","",x);
14949             x = ttol(s, x);
14950             debug(F101,">>> ttol","",x);
14951             if (x < 0) {
14952                 net_err++;
14953                 debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
14954                 x = 0;
14955             }
14956             write_net_bytes += x;
14957             pbuf_written += x;
14958         }
14959         if (FD_ISSET(ptyfd, &out)) {    /* Can write to pty? */
14960             debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
14961             errno = 0;
14962 #ifndef COMMENT
14963             x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
14964 #else
14965             /* Byte loop to rule out data overruns in the pty */
14966             /* (it makes no difference) */
14967             {
14968                 char *p = tbuf+tbuf_written;
14969                 int n = tbuf_avail - tbuf_written;
14970                 for (x = 0; x < n; x++) {
14971                     msleep(10);
14972                     if (write(ptyfd,&(p[x]),1) < 0)
14973                       break;
14974                 }
14975             }
14976 #endif /* COMMENT */
14977             debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
14978             if (x > 0) {
14979                 tbuf_written += x;
14980                 write_pty_bytes += x;
14981             } else {
14982                 x = 0;
14983                 pty_err++;
14984                 if (pexitstat < 0) {
14985                     status = pty_get_status(ptyfd,pty_fork_pid);
14986                     debug(F101,"ttptycmd pty_get_status B","",status);
14987                     if (status > -1) pexitstat = status;
14988                     have_pty = 0;
14989                 }
14990                 debug(F100,"ttptycmd +++ ptyfd write error","",0);
14991             }
14992         }
14993         if (FD_ISSET(ttyfd, &in)) {     /* Can read from net? */
14994             tset++;
14995             debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
14996             n = in_chk(1,ttyfd);
14997             debug(F101,"ttptycmd in_chk(ttyfd)","",n); 
14998             if (n < 0 || ttyfd == -1) {
14999                 debug(F101,"ttptycmd +++ ttyfd errno","",errno);
15000                 net_err++;
15001             } else if (n > 0) {
15002                 if (n > PTY_TBUF_SIZE - tbuf_avail)
15003                   n = PTY_TBUF_SIZE - tbuf_avail;
15004                 debug(F101,"ttptycmd net read size adjusted","",n); 
15005                 if (xlocal && netconn) {
15006                     /*
15007                       We have to use a byte loop here because ttxin()
15008                       does not decrypt or, for that matter, handle Telnet.
15009                     */
15010                     int c;
15011                     CHAR * p;
15012                     p = tbuf + tbuf_avail;
15013                     for (x = 0; x < n; x++) {
15014                         if ((c = ttinc(0)) < 0)
15015                           break;
15016                         if (!is_tn) {   /* Not Telnet - keep all bytes */
15017                             *p++ = (CHAR)c;
15018                             debug(F000,"<<< char","",c);
15019 #ifdef TNCODE
15020                         } else {        /* Telnet - must handle IAC and NVT */
15021                             debug(F000,"<<< char",ckitoa(in_state),c);
15022                             switch (c) {
15023                               case 0x00: /* NUL */
15024                                 if (in_state == HAVE_CR) {
15025                                     debug(F000,"<<< SKIP","",c);
15026                                 } else {
15027                                     *p++ = c;
15028                                     debug(F000,"<<< Keep","",c);
15029                                 }
15030                                 in_state = 0;
15031                                 break;
15032                               case 0x0d: /* CR */
15033                                 if (!TELOPT_U(TELOPT_BINARY))
15034                                   in_state = HAVE_CR;
15035                                 *p++ = c;
15036                                 debug(F000,"<<< Keep","",c);
15037                                 break;
15038 #ifdef COMMENT
15039                               case 0x0f: /* Ctrl-O */
15040                               case 0x16: /* Ctrl-V */
15041                                 *p++ = 0x16;
15042                                 *p++ = c;
15043                                 debug(F000,"<<< QUOT","",c);
15044                                 break;
15045 #endif /* COMMENT */
15046                               case 0xff: /* IAC */
15047                                 if (in_state == HAVE_IAC) {
15048                                     debug(F000,"<<< KEEP","",c);
15049                                     *p++ = c;
15050                                     in_state = 0;
15051                                 } else {
15052                                     debug(F000,"<<< SKIP","",c);
15053                                     in_state = HAVE_IAC;
15054                                 }
15055                                 break;
15056                               default:  /* All others */
15057                                 if (in_state == HAVE_IAC) {
15058 #ifdef COMMENT
15059 /*
15060   tn_doop() will consume an unknown number of bytes and we'll overshoot
15061   the for-loop.  The only Telnet command I've ever seen arrive here is
15062   a Data Mark, which comes when the remote protocol exits and the remote
15063   job returns to its shell prompt.  On the assumption it's a 1-byte command,
15064   we don't write out the IAC or the command, and we clear the state.  If
15065   we called tn_doop() we'd have no way of knowing how many bytes it took
15066   from the input stream.
15067 */
15068                                     int xx;
15069                                     xx = tn_doop((CHAR)c,duplex,ttinc);
15070                                     debug(F111,"<<< DOOP",ckctoa(c),xx);
15071 #else
15072                                     debug(F101,"<<< DOOP","",c);
15073 #endif  /* COMMENT */
15074                                     in_state = 0;
15075                                 } else {
15076                                     *p++ = c;
15077                                     debug(F000,"<<< keep","",c);
15078                                     in_state = 0;
15079                                 }
15080                             }
15081 #endif  /* TNCODE */
15082                         }
15083                     }
15084                     ckmakmsg(msgbuf,500,
15085                              "ttptycmd read net [ttinc loop] errno=",
15086                              ckitoa(errno),
15087                              " count=",
15088                              ckitoa(x));
15089                     debug(F100,msgbuf,"",0);
15090                 } else {
15091                     x = ttxin(n,tbuf+tbuf_avail);
15092                     debug(F101,"ttptycmd ttxin x","",x); 
15093                 }
15094
15095                 if (x < 0) {
15096                     debug(F101,"ttptycmd read net error","",x);
15097                     net_err++;
15098                 }
15099                 tbuf_avail += x;
15100                 read_net_bytes += x;
15101             }
15102
15103         } else
15104           tnotset++;
15105
15106         if (FD_ISSET(ptyfd, &in)) {     /* Read from pty? */
15107             pset++;
15108             debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
15109 #ifdef PTY_USE_NDELAY
15110             n = PTY_PBUF_SIZE;
15111 #else
15112             /*
15113               This does not work on nonblocking channels
15114               on certain platforms such as NetBSD.
15115             */
15116             n = pty_chk(ptyfd);
15117 #endif /* PTY_USE_NDELAY */
15118             debug(F101,"ttptycmd pty_chk() n","",n); 
15119
15120             if (n < 0)
15121               n = 0;
15122             if (n > 0) {
15123                 if (n > PTY_PBUF_SIZE - pbuf_avail)
15124                   n = PTY_PBUF_SIZE - pbuf_avail;
15125                 debug(F101,"ttptycmd pty read size adjusted","",n); 
15126                 errno = 0;
15127                 x = read(ptyfd,pbuf+pbuf_avail,n);
15128 #ifdef DEBUG
15129                 if (deblog) {
15130                     ckmakmsg(msgbuf,500,
15131                              "ttptycmd read pty errno=",
15132                              ckitoa(errno),
15133                              " count=",
15134                              ckitoa(x));
15135                     debug(F100,msgbuf,"",0);
15136                 }
15137 #endif  /* DEBUG */
15138
15139                 if (x < 0 && errno == EAGAIN)
15140                   x = 0;
15141
15142                 if (x < 0) {            /* This works on Solaris and Linux */
15143                     pty_err++;          /* but not NetBSD */
15144                     debug(F100,"TERMINATION TEST A","",0);
15145 #ifdef COMMENT
15146                     if (errno == EIO)
15147                       rc = 1;
15148 #endif  /* COMMENT */
15149                     if (pexitstat < 0) {
15150                         status = pty_get_status(ptyfd,pty_fork_pid);
15151                         debug(F101,"ttptycmd pty_get_status C","",status);
15152                         if (status > -1) pexitstat = status;
15153                     }
15154                     have_pty = 0;
15155                     x = 0;
15156                 }
15157                 if (x == 0 && !pty_err) { /* This works on NetBSD but */
15158                     debug(F100,"TERMINATION TEST B","",0);
15159                     status = pexitstat > -1 ? pexitstat :
15160                         pty_get_status(ptyfd,pty_fork_pid);
15161                     debug(F101,"ttptycmd pty_get_status D","",status);
15162                     if (status > -1) {
15163                         pexitstat = status;
15164                         pty_err++;
15165                         have_pty = 0;
15166                     } else {            /* Select() lied */
15167                         pty_err = 0;    /* pty still there but has nothing */
15168                         msleep(100);    /* sleep a bit */
15169                     }
15170                     x = 0;
15171                 } 
15172                 /* Hopefully the next two are no longer needed... */
15173                 if (!pty_err && (
15174 #ifndef PTY_USE_NDELAY
15175                     x < 1 || errno
15176 #else
15177                     errno != 0 && errno != EAGAIN
15178 #endif /* PTY_USE_NDELAY */
15179                     )) {
15180                     debug(F100,"TERMINATION TEST C","",0);
15181                     pty_err++;
15182                     debug(F101,"ttptycmd SET pty_err","",pty_err);
15183                     if (errno == EIO)   /* errno == EIO is like EOF */
15184                       rc = 1;
15185                     if (x < 0)
15186                       x = 0;
15187                 }
15188 #ifdef COMMENT
15189 #ifdef DEBUG
15190                 if (deblog) {
15191                     pbuf[pbuf_avail + x] = '\0';
15192                     debug(F111,"ttptycmd added to pty buffer",
15193                           pbuf+pbuf_avail,x);
15194                 }
15195 #endif  /* DEBUG */
15196 #endif  /* COMMENT */
15197                 pbuf_avail += x;
15198                 read_pty_bytes += x;
15199             } else {                    /* n == 0 with blocking reads */
15200                 debug(F100,
15201                       "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
15202                       "",0);
15203             }
15204         } else
15205           pnotset++;
15206
15207         /* If writes have caught up to reads, reset the buffers */
15208
15209         if (pbuf_written == pbuf_avail)
15210           pbuf_written = pbuf_avail = 0;
15211         if (tbuf_written == tbuf_avail)
15212           tbuf_written = tbuf_avail = 0;
15213
15214         /* See if we can exit */
15215
15216         x1 = pbuf_avail - pbuf_written; 
15217         x2 = tbuf_avail - tbuf_written;
15218
15219         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
15220         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
15221         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
15222         debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
15223         debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
15224         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
15225
15226         if (net_err) {                  /* Net error? */
15227             debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
15228             if (have_net) {
15229                 if (local) {
15230                     ttclos(0);
15231                     printf("?Connection closed\n");
15232                 }
15233                 have_net = 0;
15234             }
15235             debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
15236             if (x1 == 0)
15237               break;
15238         }
15239         if (pty_err) {                  /* Pty error? */
15240             if (have_pty) {
15241                 if (pexitstat < 0) {            
15242                     status = pty_get_status(ptyfd,pty_fork_pid);
15243                     debug(F101,"ttptycmd pty_get_status E","",status);
15244                     if (status > -1) pexitstat = status;
15245                 }
15246                 have_pty = 0;
15247             }
15248             if (x1 == 0 && x2 == 0) {   /* If buffers are caught up */
15249                 rc = 1;                 /* set preliminary return to success */
15250                 debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
15251                 break;                  /* and exit the loop */
15252             }
15253         }
15254     }
15255     debug(F101,"ttptycmd +++ have_pty","",have_pty);
15256     if (have_pty) {                     /* In case select() failed */
15257 #ifdef USE_CKUPTY_C
15258         end_pty();
15259         close(ptyfd);
15260 #else
15261         close(slavefd);
15262         close(masterfd);
15263 #endif /* USE_CKUPTY_C */
15264     }
15265     pty_master_fd = -1;
15266     debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
15267     if (pexitstat < 0) {                /* Try one last time to get status */
15268         status = pty_get_status(ptyfd,pty_fork_pid);
15269         debug(F101,"ttptycmd pty_get_status F","",status);
15270         if (status > -1) pexitstat = status;
15271     }
15272     debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
15273     if (deblog) {                       /* Stats for debug log */
15274         debug(F101,"ttptycmd +++ pset   ","",pset);
15275         debug(F101,"ttptycmd +++ pnotset","",pnotset);
15276         debug(F101,"ttptycmd +++ tset   ","",tset);
15277         debug(F101,"ttptycmd +++ tnotset","",tnotset);
15278
15279         debug(F101,"ttptycmd +++  read_pty_bytes","",read_pty_bytes);
15280         debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
15281         debug(F101,"ttptycmd +++  read_net_bytes","",read_net_bytes);
15282         debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
15283     }
15284 /*
15285   If we got the external protocol's exit status from waitpid(), we use that
15286   to set our return code.  If not, we fall back on whatever rc was previously
15287   set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
15288 */
15289     if (save_sigchld) {                 /* Restore this if we changed it */
15290         (VOID) signal(SIGCHLD,save_sigchld);
15291         save_sigchld = NULL;
15292     }
15293     msleep(500);
15294     x = kill(pty_fork_pid,SIGHUP);      /* In case it's still there */
15295     pty_fork_pid = -1;
15296     debug(F101,"ttptycmd fork kill SIGHUP","",x);
15297     if (pexitstat > -1)
15298       rc = (pexitstat == 0 ? 1 : 0);
15299     debug(F101,"ttptycmd +++ rc","",rc);
15300     if (!local) {                       /* If in remote mode */
15301         conres();                       /* restore console to CBREAK mode */
15302         concb((char)escchr);
15303     }
15304     return(rc);
15305 }
15306 #endif  /* NETPTY */
15307 #endif  /* SELECT */
15308
15309 /* T T R U N C M D  --  Redirect an external command over the connection. */
15310
15311 /*
15312   TTRUNCMD is the routine that was originally used for running external
15313   protocols.  It is very simple and works fine provided (a) the connection
15314   is not encrypted, and (b) the external protocol uses standard i/o
15315   (file descriptors 0 and 1) for file transfer.
15316 */
15317
15318 int
15319 ttruncmd(s) char *s; {
15320     PID_T pid;                          /* pid of lower fork */
15321     int wstat;                          /* for wait() */
15322     int x;
15323     int statusp;
15324
15325     if (ttyfd == -1) {
15326         printf("?Sorry, device is not open\n");
15327         return(0);
15328     }
15329     if (nopush) {
15330         debug(F100,"ttruncmd fail: nopush","",0);
15331         return(0);
15332     }
15333
15334 #ifdef NETPTY
15335 /***************
15336   It might also be necessary to use the pty routine for other reasons,
15337   e.g. because the external program does not use stdio.
15338 */
15339 #ifdef NETCONN
15340 /*
15341   If we have a network connection we use a different routine because
15342   (a) if the connection is encrypted, the mechanism used here can't deal
15343   with it; and (b) it won't handle any network protocols either, e.g.
15344   Telnet, Rlogin, K5 U-to-U, etc.  However, this routine works much
15345   better (faster, more transparent) on serial connections and when
15346   C-Kermit is in remote mode (i.e. is on the far end).
15347 */
15348     /* For testing always use this */
15349     if (netconn)
15350       return(ttptycmd(s));
15351 #endif /* NETCONN */
15352
15353 /***************/
15354 #else  /* NETPTY */
15355     if (tt_is_secure()) {
15356         printf("?Sorry, \
15357 external protocols over secure connections not supported in this OS.\n"
15358               );
15359         return(0);
15360     }
15361 #endif  /* NETPTY */
15362
15363     conres();                           /* Make console normal  */
15364     pexitstat = -4;
15365     if ((pid = fork()) == 0) {          /* Make a child fork */
15366         if (priv_can())                 /* Child: turn off privs. */
15367           exit(1);
15368         dup2(ttyfd, 0);                 /* Give stdin/out to the line */
15369         dup2(ttyfd, 1);
15370         x = system(s);
15371         debug(F101,"ttruncmd system",s,x);
15372         _exit(x ? BAD_EXIT : 0);
15373     } else {
15374         SIGTYP (*istat)(), (*qstat)();
15375         if (pid == (PID_T) -1)          /* fork() failed? */
15376           return(0);
15377         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
15378         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
15379
15380 #ifdef COMMENT
15381         while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
15382 #else  /* Not COMMENT */
15383         while (1) {
15384             wstat = wait(&statusp);
15385             debug(F101,"ttruncmd wait","",wstat);
15386             if (wstat == pid || wstat == -1)
15387               break;
15388         }
15389 #endif /* COMMENT */
15390
15391         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
15392         debug(F101,"ttruncmd wait statusp","",statusp);
15393         debug(F101,"ttruncmd wait pexitstat","",pexitstat);
15394         signal(SIGINT,istat);           /* Restore interrupts */
15395         signal(SIGQUIT,qstat);
15396     }
15397     concb((char)escchr);                /* Restore console to CBREAK mode */
15398     return(statusp == 0 ? 1 : 0);
15399 }
15400 #endif  /* CK_REDIR */
15401
15402 struct tm *
15403 #ifdef CK_ANSIC
15404 cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
15405 #else
15406 cmdate2tm(date,gmt) char * date; int gmt;
15407 #endif
15408 {
15409     /* date as "yyyymmdd hh:mm:ss" */
15410     static struct tm _tm;
15411     time_t now;
15412
15413     if (strlen(date) != 17 ||
15414         date[8] != ' ' ||
15415         date[11] != ':' ||
15416         date[14] != ':')
15417       return(NULL);
15418
15419     time(&now);
15420     if (gmt)
15421       _tm = *gmtime(&now);
15422     else
15423       _tm = *localtime(&now);
15424     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
15425                   (date[2]-'0')*10   + (date[3]-'0')-1900;
15426     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
15427     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
15428     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
15429     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
15430     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
15431
15432     /* Should we set _tm.tm_isdst to -1 here? */
15433
15434     _tm.tm_wday = 0;
15435     _tm.tm_yday = 0;
15436
15437     return(&_tm);
15438 }
15439
15440 #ifdef OXOS
15441 #undef kill
15442 #endif /* OXOS */
15443
15444 #ifdef OXOS
15445 int
15446 priv_kill(pid, sig) int pid, sig; {
15447     int i;
15448
15449     if (priv_on())
15450         debug(F100,"priv_kill priv_on failed","",0);
15451     i = kill(pid, sig);
15452     if (priv_off())
15453         debug(F100,"priv_kill priv_off failed","",0);
15454     return(i);
15455 }
15456 #endif /* OXOS */
15457
15458 #ifdef BEOSORBEBOX
15459 /* #ifdef BE_DR_7 */
15460 /*
15461   alarm() function not supplied with Be OS DR7 - this one contributed by
15462   Neal P. Murphy.
15463 */
15464
15465 /*
15466   This should mimic the UNIX/POSIX alarm() function well enough, with the
15467   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
15468   and wait for the alarm thread to finish.
15469 */
15470 unsigned int
15471 alarm(unsigned int seconds) {
15472     long time_left = 0;
15473
15474 /* If an alarm is active, turn it off, saving the unused time */
15475     if (alarm_thread != -1) {
15476         /* We'll be generous and count partial seconds as whole seconds. */
15477         time_left = alarm_struct.time -
15478           ((system_time() - time_started) / 1000000.0);
15479
15480         /* Kill the alarm thread */
15481         kill_thread (alarm_thread);
15482
15483         /* We need to clean up as though the alarm occured. */
15484         time_started = 0;
15485         alarm_struct.thread = -1;
15486         alarm_struct.time = 0;
15487         alarm_expired();
15488     }
15489
15490 /* Set a new alarm clock, if requested. */
15491     if (seconds > 0) {
15492         alarm_struct.thread = find_thread(NULL);
15493         alarm_struct.time = seconds;
15494         time_started = system_time();
15495         alarm_thread = spawn_thread (do_alarm,
15496                                      "alarm_thread",
15497                                      B_NORMAL_PRIORITY,
15498                                      (void *) &alarm_struct
15499                                      );
15500         resume_thread (alarm_thread);
15501     }
15502
15503 /* Now return [unused time | 0] */
15504     return ((unsigned int) time_left);
15505 }
15506
15507 /*
15508   This function is the departure from UNIX/POSIX alarm handling. In the case
15509   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
15510   handler. When Be implements alarm(), this function call can be eliminated
15511   from user's SIGALRM signal handlers.
15512 */
15513
15514 void
15515 alarm_expired(void) {
15516     long ret_val;
15517
15518     if (alarm_thread != -1) {
15519         wait_for_thread (alarm_thread, &ret_val);
15520         alarm_thread = -1;
15521     }
15522 }
15523
15524 /*
15525   This is the function that snoozes the requisite number of seconds and then
15526   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
15527   uses thread_id; currently they are both typdef'ed as long, but I'll do the
15528   cast anyway. This function is run in a separate thread.
15529 */
15530
15531 long
15532 do_alarm (void *alarm_struct) {
15533     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
15534     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
15535     time_started = 0;
15536     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
15537     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
15538 }
15539 /* #endif */ /* BE_DR_7 */
15540 #endif /* BEOSORBEBOX */
15541
15542 #ifdef Plan9
15543
15544 int
15545 p9ttyctl(char letter, int num, int param) {
15546     char cmd[20];
15547     int len;
15548
15549     if (ttyctlfd < 0)
15550       return -1;
15551
15552     cmd[0] = letter;
15553     if (num)
15554       len = sprintf(cmd + 1, "%d", param) + 1;
15555     else {
15556         cmd[1] = param;
15557         len = 2;
15558     }
15559     if (write(ttyctlfd, cmd, len) == len) {
15560         cmd[len] = 0;
15561         /* fprintf(stdout, "wrote '%s'\n", cmd); */
15562         return 0;
15563     }
15564     return -1;
15565 }
15566
15567 int
15568 p9ttyparity(char l) {
15569     return p9ttyctl('p', 0, l);
15570 }
15571
15572 int
15573 p9tthflow(int flow, int status) {
15574     return p9ttyctl('m', 1, status);
15575 }
15576
15577 int
15578 p9ttsspd(int cps) {
15579     if (p9ttyctl('b', 1, cps * 10) < 0)
15580       return -1;
15581     ttylastspeed = cps * 10;
15582     return 0;
15583 }
15584
15585 int
15586 p9openttyctl(char *ttname) {
15587     char name[100];
15588
15589     if (ttyctlfd >= 0) {
15590         close(ttyctlfd);
15591         ttyctlfd = -1;
15592         ttylastspeed = -1;
15593     }
15594     sprintf(name, "%sctl", ttname);
15595     ttyctlfd = open(name, 1);
15596     return ttyctlfd;
15597 }
15598
15599 int
15600 p9concb() {
15601     if (consctlfd >= 0) {
15602         if (write(consctlfd, "rawon", 5) == 5)
15603           return 0;
15604     }
15605     return -1;
15606 }
15607
15608 int
15609 p9conbin() {
15610     return p9concb();
15611 }
15612
15613 int
15614 p9conres() {
15615     if (consctlfd >= 0) {
15616         if (write(consctlfd, "rawoff", 6) == 6)
15617           return 0;
15618     }
15619     return -1;
15620 }
15621
15622 int
15623 p9sndbrk(int msec) {
15624     if (ttyctlfd >= 0) {
15625         char cmd[20];
15626         int i = sprintf(cmd, "k%d", msec);
15627         if (write(ttyctlfd, cmd, i) == i)
15628           return 0;
15629     }
15630     return -1;
15631 }
15632
15633 int
15634 conwrite(char *buf, int n) {
15635     int x;
15636     static int length = 0;
15637     static int holdingcr = 0;
15638     int normal = 0;
15639     for (x = 0; x < n; x++) {
15640         char c = buf[x];
15641         if (c == 007) {
15642             if (normal) {
15643                 write(1, buf + (x - normal), normal);
15644                 length += normal;
15645                 normal = 0;
15646             }
15647             /* write(noisefd, "1000 300", 8); */
15648             holdingcr = 0;
15649         } else if (c == '\r') {
15650             if (normal) {
15651                 write(1, buf + (x - normal), normal);
15652                 length += normal;
15653                 normal = 0;
15654             }
15655             holdingcr = 1;
15656         } else if (c == '\n') {
15657             write(1, buf + (x - normal), normal + 1);
15658             normal = 0;
15659             length = 0;
15660             holdingcr = 0;
15661         } else if (c == '\b') {
15662             if (normal) {
15663                 write(1, buf + (x - normal), normal);
15664                 length += normal;
15665                 normal = 0;
15666             }
15667             if (length) {
15668                 write(1, &c, 1);
15669                 length--;
15670             }
15671             holdingcr = 0;
15672         } else {
15673             if (holdingcr) {
15674                 char b = '\b';
15675                 while (length-- > 0)
15676                   write(1, &b, 1);
15677                 length = 0;     /* compiler bug */
15678             }
15679             holdingcr = 0;
15680             normal++;
15681         }
15682     }
15683     if (normal) {
15684         write(1, buf + (x - normal), normal);
15685         length += normal;
15686     }
15687     return n;
15688 }
15689
15690 void
15691 conprint(char *fmt, ...) {
15692     static char buf[1000];              /* not safe if on the stack */
15693
15694     va_list ap;
15695     int i;
15696
15697     va_start(ap, fmt);
15698     i = vsprintf(buf, fmt, ap);
15699     conwrite(buf, i);
15700 }
15701 #endif /* Plan9 */
15702
15703 /* fprintf, printf, perror replacements... */
15704
15705 /* f p r i n t f */
15706
15707 #ifdef UNIX
15708 #ifdef CK_ANSIC
15709 #include <stdarg.h>
15710 #else /* CK_ANSIC */
15711 #ifdef __GNUC__
15712 #include <stdarg.h>
15713 #else
15714 #include <varargs.h>
15715 #endif  /* __GNUC__ */
15716 #endif /* CK_ANSIC */
15717 #ifdef fprintf
15718 #undef fprintf
15719 static char str1[4096];
15720 static char str2[4096];
15721 int
15722 #ifdef CK_ANSIC
15723 ckxfprintf(FILE * file, const char * format, ...)
15724 #else /* CK_ANSIC */
15725 ckxfprintf(va_alist) va_dcl
15726 #endif /* CK_ANSIC */
15727 /* ckxfprintf */ {
15728     int i, j, len, got_cr;
15729     va_list args;
15730     int rc = 0;
15731
15732 #ifdef CK_ANSIC
15733     va_start(args, format);
15734 #else /* CK_ANSIC */
15735     char * format;
15736     FILE * file;
15737     va_start(args);
15738     file = va_arg(args,FILE *);
15739     format = va_arg(args,char *);
15740 #endif /* CK_ANSIC */
15741
15742     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
15743         rc = vfprintf(file,format,args);
15744     } else {
15745         unsigned int c;
15746         rc = vsprintf(str1, format, args);
15747         len = strlen(str1);
15748         if (len >= sizeof(str1)) {
15749             debug(F101,"ckxfprintf() buffer overflow","",len);
15750             doexit(BAD_EXIT,1);
15751         }
15752         for (i = 0, j = 0, got_cr = 0;
15753              i < len && j < sizeof(str1)-2;
15754              i++, j++ ) {
15755             /* We can't use 255 as a case label because of signed chars */
15756             c = (unsigned)(str1[i] & 0xff);
15757 #ifdef TNCODE
15758             if (c == 255) {
15759                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15760                   str2[j++] = '\0';
15761                 str2[j++] = IAC;
15762                 str2[j] = IAC;
15763                 got_cr = 0;
15764             } else
15765 #endif /* TNCODE */
15766             switch (c) {
15767               case '\r':
15768                 if (got_cr
15769 #ifdef TNCODE
15770                     && !TELOPT_ME(TELOPT_BINARY)
15771 #endif /* TNCODE */
15772                     )
15773                   str2[j++] = '\0';
15774                 str2[j] = str1[i];
15775                 got_cr = 1;
15776                 break;
15777               case '\n':
15778                 if (!got_cr)
15779                   str2[j++] = '\r';
15780                 str2[j] = str1[i];
15781                 got_cr = 0;
15782                 break;
15783               default:
15784                 if (got_cr
15785 #ifdef TNCODE
15786                     && !TELOPT_ME(TELOPT_BINARY)
15787 #endif /* TNCODE */
15788                     )
15789                   str2[j++] = '\0';
15790                 str2[j] = str1[i];
15791                 got_cr = 0;
15792             }
15793         }
15794         if (got_cr
15795 #ifdef TNCODE
15796              && !TELOPT_ME(TELOPT_BINARY)
15797 #endif /* TNCODE */
15798              )
15799             str2[j++] = '\0';
15800 #ifdef CK_ENCRYPTION
15801 #ifdef TNCODE
15802         if (TELOPT_ME(TELOPT_ENCRYPTION))
15803           ck_tn_encrypt(str2,j);
15804 #endif /* TNCODE */
15805 #endif /* CK_ENCRYPTION */
15806 #ifdef CK_SSL
15807         if (inserver && (ssl_active_flag || tls_active_flag)) {
15808             /* Write using SSL */
15809             char * p = str2;
15810           ssl_retry:
15811             if (ssl_active_flag)
15812               rc = SSL_write(ssl_con, p, j);
15813             else
15814               rc = SSL_write(tls_con, p, j);
15815             debug(F111,"ckxfprintf","SSL_write",rc);
15816             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15817               case SSL_ERROR_NONE:
15818                 if (rc == j)
15819                   break;
15820                 p += rc;
15821                 j -= rc;
15822                 goto ssl_retry;
15823               case SSL_ERROR_WANT_WRITE:
15824               case SSL_ERROR_WANT_READ:
15825               case SSL_ERROR_SYSCALL:
15826                 if (rc != 0)
15827                   return(-1);
15828               case SSL_ERROR_WANT_X509_LOOKUP:
15829               case SSL_ERROR_SSL:
15830               case SSL_ERROR_ZERO_RETURN:
15831               default:
15832                 rc = 0;
15833             }
15834         } else
15835 #endif /* CK_SSL */
15836         fwrite(str2,sizeof(char),j,stdout);
15837     }
15838     va_end(args);
15839     return(rc);
15840 }
15841 #endif /* fprintf */
15842
15843 /* p r i n t f */
15844
15845 #ifdef printf
15846 #undef printf
15847 int
15848 #ifdef CK_ANSIC
15849 ckxprintf(const char * format, ...)
15850 #else /* CK_ANSIC */
15851 ckxprintf(va_alist) va_dcl
15852 #endif /* CK_ANSIC */
15853 /* ckxprintf */ {
15854     int i, j, len, got_cr;
15855     va_list args;
15856     int rc = 0;
15857
15858 #ifdef CK_ANSIC
15859     va_start(args, format);
15860 #else /* CK_ANSIC */
15861     char * format;
15862     va_start(args);
15863     format = va_arg(args,char *);
15864 #endif /* CK_ANSIC */
15865
15866     if (!inserver) {
15867         rc = vprintf(format, args);
15868     } else {
15869         unsigned int c;
15870         rc = vsprintf(str1, format, args);
15871         len = strlen(str1);
15872         if (len >= sizeof(str1)) {
15873             debug(F101,"ckxprintf() buffer overflow","",len);
15874             doexit(BAD_EXIT,1);
15875         }
15876         for (i = 0, j = 0, got_cr=0;
15877              i < len && j < sizeof(str1)-2;
15878              i++, j++ ) {
15879             c = (unsigned)(str1[i] & 0xff);
15880 #ifdef TNCODE
15881             if (c == 255) {
15882                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15883                   str2[j++] = '\0';
15884                 str2[j++] = IAC;
15885                 str2[j] = IAC;
15886                 got_cr = 0;
15887             } else
15888 #endif /* TNCODE */
15889             switch (c) {
15890               case '\r':
15891                 if (got_cr
15892 #ifdef TNCODE
15893                     && !TELOPT_ME(TELOPT_BINARY)
15894 #endif /* TNCODE */
15895                     )
15896                   str2[j++] = '\0';
15897                 str2[j] = str1[i];
15898                 got_cr = 1;
15899                 break;
15900               case '\n':
15901                 if (!got_cr)
15902                   str2[j++] = '\r';
15903                 str2[j] = str1[i];
15904                 got_cr = 0;
15905                 break;
15906               default:
15907                 if (got_cr
15908 #ifdef TNCODE
15909                     && !TELOPT_ME(TELOPT_BINARY)
15910 #endif /* TNCODE */
15911                     )
15912                   str2[j++] = '\0';
15913                 str2[j] = str1[i];
15914                 got_cr = 0;
15915                 break;
15916             }
15917         }
15918         if (got_cr
15919 #ifdef TNCODE
15920              && !TELOPT_ME(TELOPT_BINARY)
15921 #endif /* TNCODE */
15922              )
15923             str2[j++] = '\0';
15924 #ifdef CK_ENCRYPTION
15925 #ifdef TNCODE
15926         if (TELOPT_ME(TELOPT_ENCRYPTION))
15927           ck_tn_encrypt(str2,j);
15928 #endif /* TNCODE */
15929 #endif /* CK_ENCRYPTION */
15930 #ifdef CK_SSL
15931         if (inserver && (ssl_active_flag || tls_active_flag)) {
15932             char * p = str2;
15933             /* Write using SSL */
15934           ssl_retry:
15935             if (ssl_active_flag)
15936               rc = SSL_write(ssl_con, p, j);
15937             else
15938               rc = SSL_write(tls_con, p, j);
15939             debug(F111,"ckxprintf","SSL_write",rc);
15940             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15941               case SSL_ERROR_NONE:
15942                 if (rc == j)
15943                   break;
15944                 p += rc;
15945                 j -= rc;
15946                 goto ssl_retry;
15947               case SSL_ERROR_WANT_WRITE:
15948               case SSL_ERROR_WANT_READ:
15949               case SSL_ERROR_SYSCALL:
15950                 if (rc != 0)
15951                   return(-1);
15952               case SSL_ERROR_WANT_X509_LOOKUP:
15953               case SSL_ERROR_SSL:
15954               case SSL_ERROR_ZERO_RETURN:
15955               default:
15956                 rc = 0;
15957             }
15958         } else
15959 #endif /* CK_SSL */
15960           rc = fwrite(str2,sizeof(char),j,stdout);
15961     }
15962     va_end(args);
15963     return(rc);
15964 }
15965 #endif /* printf */
15966
15967 /*  p e r r o r  */
15968
15969 #ifdef perror
15970 #undef perror
15971 _PROTOTYP(char * ck_errstr,(VOID));
15972 #ifdef NEXT
15973 void
15974 #else
15975 #ifdef CK_SCOV5
15976 void
15977 #else
15978 int
15979 #endif /* CK_SCOV5 */
15980 #endif /* NEXT */
15981 #ifdef CK_ANSIC
15982 ckxperror(const char * str)
15983 #else /* CK_ANSIC */
15984 ckxperror(str) char * str;
15985 #endif /* CK_ANSIC */
15986 /* ckxperror */ {
15987     char * errstr = ck_errstr();
15988 #ifndef NEXT
15989 #ifndef CK_SCOV5
15990     return
15991 #endif /* CK_SCOV5 */
15992 #endif /* NEXT */
15993       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
15994 }
15995 #endif /* perror */
15996 #endif /* UNIX */
15997
15998 #ifdef MINIX2
15999
16000 /* Minix doesn't have a gettimeofday call (but MINIX3 does).
16001  * We fake one here using time(2)
16002  */
16003
16004 #ifndef MINIX3
16005 int
16006 gettimeofday(struct timeval *tp, struct timezone *tzp) {
16007     tp->tv_usec = 0L;                   /* Close enough for horseshoes */
16008     if(time(&(tp->tv_sec))==-1)
16009       return(-1);
16010     return(0);
16011 }
16012 #endif  /* MINIX3 */
16013
16014 #ifndef MINIX3
16015 int
16016 readlink(const char *path, void *buf, size_t bufsiz) {
16017     errno = ENOSYS;
16018     return(-1);
16019 }
16020 #endif  /* MINIX3 */
16021
16022 #endif /* MINIX2 */