apply 010_makefile-destdir-support
[ckermit.git] / ckutio.c
1 #ifdef aegis
2 char *ckxv = "Aegis Communications support, 8.0.303, 17 Apr 2004";
3 #else
4 #ifdef Plan9
5 char *ckxv = "Plan 9 Communications support, 8.0.303, 17 Apr 2004";
6 #else
7 char *ckxv = "UNIX Communications support, 8.0.303, 17 Apr 2004";
8 #endif /* Plan9 */
9 #endif /* aegis */
10
11 /*  C K U T I O  */
12
13 /* C-Kermit interrupt, communications control and I/O functions for UNIX */
14
15 /*
16   Author: Frank da Cruz (fdc@columbia.edu),
17   Columbia University Academic Information Systems, New York City.
18
19   Copyright (C) 1985, 2004,
20     Trustees of Columbia University in the City of New York.
21     All rights reserved.  See the C-Kermit COPYING.TXT file or the
22     copyright text in the ckcmai.c module for disclaimer and permissions.
23 */
24
25 /*
26   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
27   compatible with C preprocessors that support only #ifdef, #else, #endif,
28   #define, and #undef.  Please do not use #if, logical operators, or other
29   preprocessor features in any of the portable C-Kermit modules.  You can,
30   of course, use these constructions in platform-specific modules when they
31   are supported by all compilers/preprocessors that could be used on that
32   platform.
33 */
34
35 extern int nettype;                     /* Defined in ckcmai.c */
36
37 /* Includes */
38
39 #include "ckcsym.h"                     /* This must go first   */
40 #include "ckcdeb.h"                     /* This must go second  */
41
42 #ifdef OSF13
43 #ifdef CK_ANSIC
44 #ifdef _NO_PROTO
45 #undef _NO_PROTO
46 #endif /* _NO_PROTO */
47 #endif /* CK_ANSIC */
48 #endif /* OSF13 */
49
50 #include <errno.h>                      /* System error numbers */
51
52 #ifdef __386BSD__
53 #define ENOTCONN 57
54 #else
55 #ifdef __bsdi__
56 #define ENOTCONN 57
57 #else
58 #ifdef __FreeBSD__
59 #define ENOTCONN 57
60 #endif /* __FreeBSD__ */
61 #endif /* __bsdi__ */
62 #endif /* __386BSD__ */
63
64 #ifdef SCO_OSR504
65 #define NBBY 8
66 #endif /* SCO_OSR504 */
67
68 #ifdef Plan9
69 #define SELECT
70 #include <sys/time.h>
71 #include <select.h>
72 #define FD_SETSIZE (3 * sizeof(long) * 8)
73 static struct timeval tv;
74 #endif /* Plan9 */
75
76 #ifdef CLIX
77 #include <sys/time.h>
78 #endif /* CLIX */
79
80 #include "ckcnet.h"                     /* Symbols for network types. */
81 #ifdef CK_SSL
82 #include "ck_ssl.h"
83 #endif /* CK_SSL */
84
85 /*
86   The directory-related includes are here because we need to test some
87   file-system-related symbols to find out which system we're being compiled
88   under.  For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
89 */
90 #ifdef SDIRENT                          /* Directory bits... */
91 #define DIRENT
92 #endif /* SDIRENT */
93
94 #ifdef XNDIR
95 #include <sys/ndir.h>
96 #else /* !XNDIR */
97 #ifdef NDIR
98 #include <ndir.h>
99 #else /* !NDIR, !XNDIR */
100 #ifdef RTU
101 #include "/usr/lib/ndir.h"
102 #else /* !RTU, !NDIR, !XNDIR */
103 #ifdef DIRENT
104 #ifdef SDIRENT
105 #include <sys/dirent.h>
106 #else
107 #include <dirent.h>
108 #endif /* SDIRENT */
109 #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
110 #include <sys/dir.h>
111 #endif /* DIRENT */
112 #endif /* RTU */
113 #endif /* NDIR */
114 #endif /* XNDIR */
115
116 #ifdef QNX
117 #include <sys/dev.h>
118 #endif /* QNX */
119
120 #ifdef HPUX5
121 #ifndef TCPSOCKET
122 /* I don't know why this is needed here since we never reference bzero(). */
123 /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
124 void
125 bzero(s,n) char *s; int n; {
126     extern char * memset();
127     memset(s,0,n);
128 }
129 #endif /* TCPSOCKET */
130 #endif /* HPUX5 */
131
132 /* Definition of HZ, used in msleep() */
133
134 #ifdef MIPS
135 #define HZ ( 1000 / CLOCK_TICK )
136 #else  /* MIPS */
137 #ifdef ATTSV
138 #ifndef NAP
139 #ifdef TRS16
140 #define HZ ( 1000 / CLOCK_TICK )
141 #endif /* TRS16 */
142 #ifdef NAPHACK
143 #define nap(x) (void)syscall(3112, (x))
144 #define NAP
145 #endif /* NAPHACK */
146 #endif /* NAP */
147 #endif /* ATTSV */
148 #endif /* MIPS */
149
150 #ifdef M_UNIX
151 #undef NGROUPS_MAX              /* Prevent multiple definition warnings */
152 #endif /* M_UNIX */
153
154 /*
155   NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
156   library routine, so _poll comes up undefined at link time.
157 */
158 #ifdef CK_POLL
159 #ifndef AIXRS                   /* IBM AIX needs special handling */
160 #include <poll.h>               /* "standard" (SVID) i/o multiplexing, etc */
161 #else /* AIXRS */
162 #ifdef SVR4                     /* AIX 3.2 is like SVID... */
163 #include <poll.h>
164 #else                           /* But AIX 3.1 is not ... */
165 #include <sys/poll.h>           /* The include file is in include/sys */
166 #define events reqevents        /* And it does not map IBM-specific member */
167 #define revents rtnevents       /* names to the System V equivalents */
168 #endif /* SVR4 */
169 #endif /* AIXRS */
170 #endif /* CK_POLL */
171
172 #include <signal.h>                     /* Signals */
173
174 /* For setjmp and longjmp */
175
176 #ifndef ZILOG
177 #include <setjmp.h>
178 #else
179 #include <setret.h>
180 #endif /* ZILOG */
181
182 /*
183   The following test differentiates between 4.1 BSD and 4.2 & later.
184   If you have a 4.1BSD system with the DIRENT library, this test could
185   mistakenly diagnose 4.2BSD and then later enable the use of system calls
186   that aren't defined.  If indeed there are such systems, we can use some
187   other way of testing for 4.1BSD, or add yet another compile-time switch.
188 */
189 #ifdef BSD4
190 #ifdef MAXNAMLEN
191 #ifndef FT21                            /* Except for Fortune. */
192 #ifndef FT18
193 #ifndef BELLV10                         /* And Bell Labs Research UNIX V10 */
194 #define BSD42
195 #endif /* BELLV10 */
196 #endif /* FT18 */
197 #endif /* FT21 */
198 #endif /* MAXNAMLEN */
199 #endif /* BSD4 */
200 /*
201   Minix 2.0 support added by Terry McConnell,
202   Syracuse University <tmc@barnyard.syr.edu>
203   No more sgtty interface, posix compliant.
204 */
205 #ifdef MINIX2
206 #define _MINIX   /* Needed for some Minix header files */
207 #undef MINIX     /* Old minix 1.0: used sgtty interface */
208 #define BSD44ORPOSIX
209 #define SVORPOSIX
210 #define DCLTIMEVAL
211 #define NOFILEH
212 #include <sys/types.h>
213 #include <sys/ioctl.h>
214 #include <termios.h>
215 #include <limits.h>
216 #undef TIOCGETC    /* defined in sys/ioctl.h, but not really supported */
217 #define TANDEM 0
218 #endif /* MINIX2 */
219
220 /*
221  MINIX 1.0 support added by Charles Hedrick,
222  Rutgers University <hedrick@aramis.rutgers.edu>.
223  MINIX also has V7 enabled.
224 */
225 #ifdef MINIX
226 #define TANDEM 0
227 #define MYREAD
228 #define NOSYSIOCTLH
229 #include <limits.h>
230 #endif /* MINIX */
231
232 #ifdef CK_REDIR         /* <sys/wait.h> needed only for REDIRECT command. */
233 /*
234   If anybody can figure out how to make this work with NeXTSTEP, be
235   my guest!  (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
236 */
237 #ifndef CK_WAIT_H                       /* If wait.h not already included... */
238 #ifdef OSF                              /* force OSF to select POSIX wait */
239 #ifdef _BSD                             /* instead of BSD (see ckcdeb.h) */
240 #define CK_OSF_BSD
241 #undef _BSD
242 #endif /* _BSD */
243 #endif /* OSF */
244 #include <sys/wait.h>                   /* Include it */
245 #ifdef OSF
246 #ifdef CK_OSF_BSD
247 #define _BSD                            /* Restore it */
248 #undef CK_OSF_BSD
249 #endif /* CK_OSF_BSD */
250 #endif /* OSF */
251 #endif /* CK_WAIT_H */
252 #endif /* CK_REDIR */
253
254 #include "ckuver.h"                     /* Version herald */
255 char *ckxsys = HERALD;
256
257 #ifdef CK_UTSNAME
258 #include <sys/utsname.h>
259
260 #ifdef TRU64                            /* Tru64 UNIX 4.0 and later */
261 /* Verified on Tru64 4.0F - might break on 4.0E or earlier */
262 #include <sys/sysinfo.h>                /* (don't know about OSF/1 or DU) */
263 #include <machine/hal_sysinfo.h>
264 #endif /* TRU64 */
265
266 #ifdef SOLARIS25                        /* Solaris 2.5 and later */
267 #include <sys/systeminfo.h>             /* (don't know about earlier ones) */
268 #endif /* SOLARIS25 */
269
270 #ifdef UW7
271 #ifndef SYS_NMLN
272 #define SYS_NMLN 257
273 #endif /* NMLN */
274 #endif /* UW7 */
275 #ifdef HPUX9PLUS
276 static int hpis800 = 0;
277 #endif /* HPUX9PLUS */
278 #ifdef SYS_NMLN
279 #define CK_SYSNMLN SYS_NMLN
280 #else
281 #ifdef _SYS_NMLN
282 #define CK_SYSNMLN _SYS_NMLN
283 #else
284 #ifdef UTSLEN
285 #define CK_SYSNMLN UTSLEN
286 #else
287 #define CK_SYSNMLN 31
288 #endif /* UTSLEN */
289 #endif /* _SYS_NMLN */
290 #endif /* SYS_NMLN */
291 char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
292 char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
293 char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
294 char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
295 char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
296 #endif /* CK_UTSNAME */
297
298 #ifdef CIE
299 #include <stat.h>                       /* For chasing symlinks, etc. */
300 #else
301 #include <sys/stat.h>
302 #endif /* CIE */
303
304 /* UUCP lockfile material... */
305
306 #ifndef NOUUCP
307 #ifdef USETTYLOCK
308 #ifdef HAVE_BAUDBOY                     /* Red Hat baudboy/lockdev */
309 #include <baudboy.h>
310 #else
311 #ifdef USE_UU_LOCK
312 #ifdef __FreeBSD__
313 #include <libutil.h>                    /* FreeBSD */
314 #else
315 #include <util.h>                       /* OpenBSD */
316 #endif /* HAVE_BAUDBOY */
317 #endif /* __FreeBSD */
318 #endif /* USE_UU_LOCK */
319 #else  /* USETTYLOCK */
320
321 /* Name of UUCP tty device lockfile */
322
323 #ifdef LINUXFSSTND
324 #ifndef HDBUUCP
325 #define HDBUUCP
326 #endif /* HDBUUCP */
327 #endif /* LINUXFSSTND */
328
329 #ifdef ACUCNTRL
330 #define LCKDIR
331 #endif /* ACUCNTRL */
332
333 /*
334   PIDSTRING means use ASCII string to represent pid in lockfile.
335 */
336 #ifndef PIDSTRING
337 #ifdef HDBUUCP
338 #define PIDSTRING
339 #else
340 #ifdef BSD44
341 #define PIDSTRING
342 #else
343 #ifdef RTAIX
344 #define PIDSTRING
345 #else
346 #ifdef AIXRS
347 #define PIDSTRING
348 #else
349 #ifdef COHERENT
350 #define PIDSTRING
351 #endif /* COHERENT */
352 #endif /* AIXRS */
353 #endif /* RTAIX */
354 #endif /* BSD44 */
355 #endif /* HDBUUCP */
356 #endif /* PIDSTRING */
357
358 /* Now the PIDSTRING exceptions... */
359
360 #ifdef PIDSTRING
361 #ifdef HPUX
362 #undef PIDSTRING
363 #endif /* HPUX */
364 #endif /* PIDSTRING */
365
366 #ifdef __bsdi__                         /* BSDI (at least thru 1.1) */
367 #ifdef PIDSTRING
368 #undef PIDSTRING
369 #endif /* PIDSTRING */
370 #endif /* __bsdi__ */
371
372 #ifdef OSF32                            /* Digital UNIX (OSF/1) 3.2 */
373 #ifdef PIDSTRING
374 #undef PIDSTRING
375 #endif /* PIDSTRING */
376 #endif /* OSF32 */
377
378 /*
379   LOCK_DIR is the name of the lockfile directory.
380   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
381 */
382
383 #ifndef LOCK_DIR
384 #ifdef MACOSX
385 #define LOCK_DIR "/var/spool/lock"
386 #endif /* MACOSX */
387 #endif/* LOCK_DIR */
388
389 #ifndef LOCK_DIR
390 #ifdef BSD44
391 #ifdef __386BSD__
392 #define LOCK_DIR "/var/spool/lock"
393 #else
394 #ifdef __FreeBSD__
395 #define LOCK_DIR "/var/spool/lock"
396 #else
397 #ifdef __NetBSD__
398 #define LOCK_DIR "/var/spool/lock"
399 #else
400 #ifdef __OpenBSD__
401 #define LOCK_DIR "/var/spool/lock"
402 #else
403 /* So which ones is this for? */
404 /* Probably original 4.4BSD on Vangogh */
405 /* Plus who knows about Mac OS X... It doesn't even have a cu program */
406 #define LOCK_DIR "/var/spool/uucp"
407 #endif /* __OpenBSD__ */
408 #endif /* __NetBSD__ */
409 #endif /* __FreeBSD__ */
410 #endif /* __386BSD__ */
411 #else
412 #ifdef DGUX430
413 #define LOCK_DIR "/var/spool/locks"
414 #else
415 #ifdef HPUX10
416 #define LOCK_DIR "/var/spool/locks"
417 #else
418 #ifdef RTAIX                            /* IBM RT PC AIX 2.2.1 */
419 #define LOCK_DIR "/etc/locks"
420 #else
421 #ifdef AIXRS
422 #define LOCK_DIR "/etc/locks"
423 #else
424 #ifdef ISIII
425 #define LOCK_DIR "/etc/locks"
426 #else
427 #ifdef HDBUUCP
428 #ifdef M_SYS5
429 #define LOCK_DIR "/usr/spool/uucp"
430 #else
431 #ifdef M_UNIX
432 #define LOCK_DIR "/usr/spool/uucp"
433 #else
434 #ifdef SVR4
435 #define LOCK_DIR "/var/spool/locks"
436 #else
437 #ifdef SUNOS4
438 #define LOCK_DIR "/var/spool/locks"
439 #else
440 #ifdef LINUXFSSTND
441 #define LOCK_DIR "/var/lock";
442 #else
443 #define LOCK_DIR "/usr/spool/locks"
444 #endif /* LINUXFSSTND */
445 #endif /* SUNOS4 */
446 #endif /* SVR4 */
447 #endif /* M_UNIX */
448 #endif /* M_SYS5 */
449 #else
450 #ifdef LCKDIR
451 #define LOCK_DIR "/usr/spool/uucp/LCK"
452 #else
453 #ifdef COHERENT
454 #define LOCK_DIR "/usr/spool/uucp"
455 #else
456 #define LOCK_DIR "/usr/spool/uucp"
457 #endif /* COHERENT */
458 #endif /* LCKDIR */
459 #endif /* HDBUUCP */
460 #endif /* ISIII */
461 #endif /* AIXRS */
462 #endif /* RTAIX */
463 #endif /* HPUX10 */
464 #endif /* DGUX430 */
465 #endif /* BSD44 */
466 #endif /* !LOCK_DIR (outside ifndef) */
467
468 #ifdef OSF2                             /* OSF/1 2.0 or later */
469 #ifdef LOCK_DIR                         /* (maybe 1.x too, who knows...) */
470 #undef LOCK_DIR
471 #define LOCK_DIR "/var/spool/locks"
472 #endif /* LOCK_DIR */
473 #endif /* OSF2 */
474
475 #ifdef COMMENT
476 /* Sorry no more lockf() -- we lock first and THEN open the device. */
477 #ifdef SVR4
478 #ifndef BSD44
479 #ifndef LOCKF
480 #define LOCKF                           /* Use lockf() on tty device in SVR4 */
481 #endif /* LOCKF */
482 #endif /* BSD44 */
483 #endif /* SVR4 */
484 #endif /* COMMENT */
485
486 #ifdef NOLOCKF                          /* But NOLOCKF cancels LOCKF */
487 #ifdef LOCKF
488 #undef LOCKF
489 #endif /* LOCKF */
490 #endif /* NOLOCKF */
491
492 /* More about this below... */
493
494 #endif /* USETTYLOCK */
495 #endif /* NOUUCP */
496
497 /*
498   MYREAD means use our internally defined nonblocking buffered read routine.
499 */
500 #ifdef ATTSV
501 #define MYREAD
502 #endif /* ATTSV */
503
504 #ifdef ATT7300
505 #ifndef MYREAD
506 #define MYREAD
507 #endif /* MYREAD */
508 /* bits for attmodem: internal modem in use, restart getty */
509 #define ISMODEM 1
510 #define DOGETY 512
511 #endif  /* ATT7300 */
512
513 #ifdef BSD42
514 #define MYREAD
515 #endif /* BSD42 */
516
517 #ifdef POSIX
518 #define MYREAD
519 #endif /* POSIX */
520 #ifdef __bsdi__
521 #ifndef O_NDELAY
522 #define O_NDELAY O_NONBLOCK
523 #endif /* O_NDELAY */
524 #endif /* __bsdi__ */
525
526 /*
527  Variables available to outside world:
528
529    dftty  -- Pointer to default tty name string, like "/dev/tty".
530    dfloc  -- 0 if dftty is console, 1 if external line.
531    dfprty -- Default parity
532    dfflow -- Default flow control
533    ckxech -- Flag for who echoes console typein:
534      1 - The program (system echo is turned off)
535      0 - The system (or front end, or terminal).
536    functions that want to do their own echoing should check this flag
537    before doing so.
538
539    flfnam  -- Name of lock file, including its path, e.g.,
540                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
541    lkflfn  -- Name of link to lock file, including its paths
542    haslock -- Flag set if this kermit established a uucp lock.
543    lockpid -- PID of other process that has desired line open, as string.
544    backgrd -- Flag indicating program executing in background ( & on
545                 end of shell command). Used to ignore INT and QUIT signals.
546    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
547                 SIGTSTP)
548
549  Functions for assigned communication line (either external or console tty):
550
551    sysinit()               -- System dependent program initialization
552    syscleanup()            -- System dependent program shutdown
553    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
554    ttclos()                -- Close & reset the tty, releasing any access lock.
555    ttsspd(cps)             -- Set the transmission speed of the tty.
556    ttgspd()                -- Get (read) the the transmission speed of the tty.
557    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
558    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
559                                 or in DIALING or CONNECTED modem control state.
560    ttres()                 -- Restore original tty modes.
561    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
562    ttinl(dest,max,timo)    -- Timed read line from the tty.
563    ttinc(timo)             -- Timed read character from tty.
564    myread()                -- Raw mode bulk buffer read, gives subsequent
565                                 chars one at a time and simulates FIONREAD.
566    myunrd(c)               -- Places c back in buffer to be read (one only)
567    ttchk()                 -- See how many characters in tty input buffer.
568    ttxin(n,buf)            -- Read n characters from tty (untimed).
569    ttol(string,length)     -- Write a string to the tty.
570    ttoc(c)                 -- Write a character to the tty.
571    ttflui()                -- Flush tty input buffer.
572    ttsndb()                -- Send BREAK signal.
573    ttsndlb()               -- Send Long BREAK signal.
574
575    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
576    ttunlck()               -- Unlock tty device.
577
578                               For ATT7300/Unix PC, System V:
579    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
580    offgetty(ttname)        -- Turns off getty(1m) for comms line
581    ongetty(ttname)         -- Restores getty() to comms line
582 */
583
584 /*
585 Functions for console terminal:
586
587    congm()   -- Get console terminal modes.
588    concb(esc) -- Put the console in single-character wakeup mode with no echo.
589    conbin(esc) -- Put the console in binary (raw) mode.
590    conres()  -- Restore the console to mode obtained by congm().
591    conoc(c)  -- Unbuffered output, one character to console.
592    conol(s)  -- Unbuffered output, null-terminated string to the console.
593    conola(s) -- Unbuffered output, array of strings to the console.
594    conxo(n,s) -- Unbuffered output, n characters to the console.
595    conchk()  -- Check if characters available at console (bsd 4.2).
596                 Check if escape char (^\) typed at console (System III/V).
597    coninc(timo)  -- Timed get a character from the console.
598    congks(timo)  -- Timed get keyboard scan code.
599    conint()  -- Enable terminal interrupts on the console if not background.
600    connoi()  -- Disable terminal interrupts on the console if not background.
601
602 Time functions
603
604    msleep(m) -- Millisecond sleep
605    ztime(&s) -- Return pointer to date/time string
606    rtimer() --  Reset timer
607    gtimer()  -- Get elapsed time since last call to rtimer()
608 */
609
610 /* Conditional Includes */
611
612 /* Whether to include <sys/file.h> */
613
614 #ifdef RTU                              /* RTU doesn't */
615 #define NOFILEH
616 #endif /* RTU */
617
618 #ifdef CIE                              /* CIE does. */
619 #undef NOFILEH
620 #endif /* CIE */
621
622 #ifdef BSD41                            /* 4.1 BSD doesn't */
623 #define NOFILEH
624 #endif /* BSD41 */
625
626 #ifdef is68k                            /* Integrated Solutions 68000 UNIX  */
627 #define NOFILEH                         /* e.g. on Plexux P60 and Sun-1 */
628 #endif /* is68k */
629
630 #ifdef MINIX                            /* MINIX */
631 #define NOFILEH
632 #endif /* MINIX */
633
634 #ifdef COHERENT                         /* Coherent */
635 #define NOFILEH
636 #endif /* COHERENT */
637
638 #ifndef NOFILEH                         /* Now include if selected. */
639 #include <sys/file.h>
640 #endif /* NOFILEH */
641
642 /* POSIX */
643
644 #ifdef BSD44ORPOSIX                     /* POSIX uses termios.h */
645 #define TERMIOS
646 #ifdef __bsdi__
647 #ifdef POSIX
648 #undef _POSIX_SOURCE                    /* Get extra stuff from termios.h */
649 #endif /* POSIX */
650 #endif /* __bsdi__ */
651 #include <termios.h>
652 #ifdef LINUX
653 #include <sys/ioctl.h>
654 #endif /* LINUX */
655 #ifdef QNX16
656 #include <ioctl.h>
657 #else
658 #ifdef QNX6
659 #include <ioctl.h>
660 #endif /* QNX6 */
661 #endif /* QNX16 */
662 #ifdef __bsdi__
663 #ifdef POSIX
664 #define _POSIX_SOURCE
665 #endif /* POSIX */
666 #endif /* __bsdi__ */
667 #ifndef BSD44                           /* Really POSIX */
668 #ifndef CK_QNX32                        /* was CK_QNX32 */
669 #define NOSYSIOCTLH                     /* No ioctl's allowed. */
670 #undef ultrix                           /* Turn off any ultrix features. */
671 #endif /* CK_QNX32 */
672 #endif /* BSD44 */
673 #endif /* POSIX */
674
675 /* System III, System V */
676
677 #ifdef ATTSV
678 #ifndef BSD44
679 #ifndef POSIX
680 #include <termio.h>
681 #endif /* POSIX */
682 #endif /* BSD44 */
683 #ifdef TERMIOX
684 /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
685 #include <termiox.h>
686   struct termiox rctsx;
687 #else
688 #ifdef STERMIOX
689 #ifdef SCO_OSR504
690 /* Sorry, this is truly disgusting but it's SCO's fault. */
691 #ifndef _SVID3
692 #define _CK_SVID3_X
693 #define _SVID3
694 #endif /* _SVID3 */
695 #endif /* SCO_OSR504 */
696 #include <sys/termiox.h>
697   struct termiox rctsx;
698 #ifdef CK_SVID3_X
699 #undef _SVID3
700 #undef CK_SVID3_X
701 #endif /* CK_SVID3_X */
702 #endif /* STERMIOX */
703 #endif /* TERMIOX */
704 #endif /* ATTSV */
705
706 #ifdef COHERENT                 /* Use termio.h, not sgtty.h for Coherent */
707 #include <termio.h>
708 #endif /* COHERENT */
709
710 #ifdef MINIX                            /* MINIX uses ioctl's */
711 #define NOSYSIOCTLH                     /* but has no <sys/ioctl.h> */
712 #endif /* MINIX */
713
714 /* Others */
715
716 #ifndef NOSYSIOCTLH                     /* Others use ioctl() */
717 #ifdef SUN4S5
718 /*
719   This is to get rid of cpp warning messages that occur because all of
720   these symbols are defined by both termios.h and ioctl.h on the SUN.
721 */
722 #undef ECHO
723 #undef NL0
724 #undef NL1
725 #undef TAB0
726 #undef TAB1
727 #undef TAB2
728 #undef XTABS
729 #undef CR0
730 #undef CR1
731 #undef CR2
732 #undef CR3
733 #undef FF0
734 #undef FF1
735 #undef BS0
736 #undef BS1
737 #undef TOSTOP
738 #undef FLUSHO
739 #undef PENDIN
740 #undef NOFLSH
741 #endif /* SUN4S5 */
742 #include <sys/ioctl.h>
743 #endif /* NOSYSIOCTLH */
744 /*
745   We really, really, REALLY want FIONREAD, because it is the only way to find
746   out not just *if* stuff is waiting to be read, but how much, which is
747   critical to our sliding-window and streaming procedures, not to mention
748   efficiency of CONNECT, etc.
749 */
750 #ifdef BELLV10
751 #include <sys/filio.h>                  /* For FIONREAD */
752 #ifdef FIONREAD
753 #define MYREAD
754 #endif /* MYREAD */
755 #endif /* BELLV10 */
756
757 #ifndef FIONREAD
758 /* It wasn't found in ioctl.h or term*.h - try these places: */
759 #ifdef UNIXWARE
760 #include <sys/filio.h>
761 #else
762 #ifdef SOLARIS
763 #include <sys/filio.h>
764 #endif /* SOLARIS */
765 #endif /* UNIXWARE */
766 #endif /* FIONREAD */
767
768 #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
769 /*
770   <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
771   something.  Due to this, in_chk() uses the FIONREAD instead of RDCHK
772   and the hot keys during file transfer (X to cancel file etc) do not
773   work because FIONREAD doesn't work even though it is defined.
774
775   NOTE: This might also be true elsewhere.
776 */
777 #ifdef FIONREAD
778 #undef FIONREAD
779 #endif /* FIONREAD */
780 #endif /* XENIX */
781
782 #ifdef CK_SCOV5                         /* Ditto for SCO OpenServer 5.0 */
783 #ifdef FIONREAD
784 #undef FIONREAD
785 #endif /* FIONREAD */
786 #endif /* XENIX */
787
788 /* Whether to include <fcntl.h> */
789
790 #ifndef is68k                           /* Only a few don't have this one. */
791 #ifndef BSD41
792 #ifndef FT21
793 #ifndef FT18
794 #ifndef COHERENT
795 #include <fcntl.h>
796 #endif /* COHERENT */
797 #endif /* FT18 */
798 #endif /* FT21 */
799 #endif /* BSD41 */
800 #endif /* not is68k */
801
802 #ifdef COHERENT
803 #ifdef _I386
804 #include <fcntl.h>
805 #else
806 #include <sys/fcntl.h>
807 #endif /* _I386 */
808 #endif /* COHERENT */
809
810 #ifdef ATT7300                          /* Unix PC, internal modem dialer */
811 #include <sys/phone.h>
812 #endif /* ATT7300 */
813
814 #ifdef HPUX                             /* HP-UX variations. */
815 #define HPUXJOBCTL
816 #include <sys/modem.h>                  /* HP-UX modem signals */
817 #ifdef hp9000s500                       /* Model 500 */
818 #undef HPUXJOBCTL
819 #endif /* hp9000s500 */
820 #ifdef HPUXPRE65
821 #undef HPUXJOBCTL
822 typedef long mflag;
823 #endif /* HPUXPRE65 */
824 #ifdef HPUXJOBCTL
825 #include <sys/bsdtty.h>                 /* HP-UX Berkeley tty support */
826 #endif /* HPUXJOBCTL */
827 #endif /* HPUX */
828
829 /*
830   Which time.h files to include... See ckcdeb.h for defaults.
831   Note that 0, 1, 2, or all 3 of these can be included according to
832   the symbol definitions.
833 */
834 #ifndef NOTIMEH
835 #ifdef TIMEH
836 #include <time.h>
837 #endif /* TIMEH */
838 #endif /* NOTIMEH */
839
840 #ifndef NOSYSTIMEH
841 #ifdef SYSTIMEH
842 #include <sys/time.h>
843 #endif /* SYSTIMEH */
844 #endif /* NOSYSTIMEH */
845
846 #ifndef NOSYSTIMEBH
847 #ifdef SYSTIMEBH
848 #include <sys/timeb.h>
849 #endif /* SYSTIMEBH */
850 #endif /* NOSYSTIMEBH */
851
852 #ifndef NODCLTIMEVAL
853 #ifdef DCLTIMEVAL
854 /*
855   In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
856   define the structs we need to access the higher speeds, so we have to
857   do it ourselves.
858 */
859 struct timeval {
860     long tv_sec;
861     long tv_usec;
862 };
863 struct timezone {
864     int tz_minuteswest;
865     int tz_dsttime;
866 };
867 #endif /* DCLTIMEVAL */
868 #endif /* NODCLTIMEVAL */
869
870 #ifdef __linux__
871 /* THIS IS OBSOLETE since about Linux 0.92 */
872 #ifdef OLINUXHISPEED
873 #include <linux/serial.h>
874 #endif /* OLINUXHISPEED */
875 #ifdef __alpha__                        /* Linux on DEC Alpha */
876 #ifndef __GLIBC__                       /* But not with glibc */
877 #include <asm/termios.h>
878 #endif /* __GLIBC__ */
879 #endif /* __alpha__ */
880 #endif /* __linux__ */
881
882 #ifdef NOIEXTEN                         /* This is broken on some systems */
883 #undef IEXTEN                           /* like Convex/OS 9.1 */
884 #endif /* NOIEXTEN */
885 #ifndef IEXTEN                          /* Turn off ^O/^V processing. */
886 #define IEXTEN 0                        /* Needed, at least, on BSDI. */
887 #endif /* IEXTEN */
888 /*
889   Pick up definitions needed for select() if we don't have them already.
890   Normally they come from <sys/types.h> but some systems get them from
891   <sys/select.h>...  Rather than hardwire all of them into the source, we
892   include it if SELECT_H is defined in compile-time CFLAGS.
893 */
894 #ifndef SCO_OSR504
895 #ifdef SELECT_H
896 #include <sys/select.h>
897 #endif /* SELECT_H */
898 #endif /* SCO_OSR504 */
899
900 #ifdef aegis
901 #include "/sys/ins/base.ins.c"
902 #include "/sys/ins/error.ins.c"
903 #include "/sys/ins/ios.ins.c"
904 #include "/sys/ins/sio.ins.c"
905 #include "/sys/ins/pad.ins.c"
906 #include "/sys/ins/time.ins.c"
907 #include "/sys/ins/pfm.ins.c"
908 #include "/sys/ins/pgm.ins.c"
909 #include "/sys/ins/ec2.ins.c"
910 #include "/sys/ins/type_uids.ins.c"
911 #include <default_acl.h>
912 #undef TIOCEXCL
913 #undef FIONREAD
914 #endif /* aegis */
915
916 #ifdef sxaE50                           /* PFU Compact A SX/A TISP V10/L50 */
917 #undef FIONREAD
918 #endif /* sxaE50 */
919
920 /* The following #defines are catch-alls for those systems */
921 /* that didn't have or couldn't find <file.h>... */
922
923 #ifndef FREAD
924 #define FREAD 0x01
925 #endif /* FREAD */
926
927 #ifndef FWRITE
928 #define FWRITE 0x10
929 #endif /* FWRITE */
930
931 #ifndef O_RDONLY
932 #define O_RDONLY 000
933 #endif /* O_RDONLY */
934
935 #ifdef SVORPOSIX
936 /*
937   Modem signals are also forbidden in the POSIX world.  But some POSIX-based
938   platforms let us at them anyway if we know where to look.
939 */
940 #ifndef NEEDMDMDEFS
941 /* Doesn't work for Linux */
942 #ifdef UNIXWARE7
943 #define NEEDMDMDEFS
944 #endif /* UNIXWARE7 */
945 #endif /* NEEDMDMDEFS */
946
947 #ifdef NEEDMDMDEFS
948 #ifndef TIOCMGET
949 #define TIOCMGET (('t'<<8)|29)
950 #endif /* TIOCMGET */
951
952 #ifndef TIOCM_DTR
953 #define TIOCM_DTR 0x0002
954 #endif /* TIOCM_DTR */
955 #ifndef TIOCM_RTS
956 #define TIOCM_RTS 0x0004
957 #endif /* TIOCM_RTS */
958 #ifndef TIOCM_CTS
959 #define TIOCM_CTS 0x0020
960 #endif /* TIOCM_CTS */
961 #ifndef TIOCM_CAR
962 #define TIOCM_CAR 0x0040
963 #endif /* TIOCM_CAR */
964 #ifndef TIOCM_RNG
965 #define TIOCM_RNG 0x0080
966 #endif /* TIOCM_RNG */
967 #ifndef TIOCM_DSR
968 #define TIOCM_DSR 0x0100
969 #endif /* TIOCM_DSR */
970 #endif /* NEEDMDMDEFS */
971 #endif /* SVORPOSIX */
972
973 /* Declarations */
974
975 #ifdef OXOS
976 #undef TCGETA
977 #undef TCSETA
978 #undef TCSETAW
979 #undef TCSETAF
980 #define TCGETA TCGETS
981 #define TCSETA TCSETS
982 #define TCSETAW TCSETSW
983 #define TCSETAF TCSETSF
984 #define termio termios
985 #endif /* OXOS */
986
987 #ifdef SVORPOSIX                        /* AT&T Sys V or POSIX */
988 #ifdef UNIXWAREPOSIX                    /* UnixWare 7 POSIX build */
989 /*
990   In Unixware POSIX builds, <[sys/]time.h> refuses to define the
991   structs we need to access the higher speeds, so we have to do it
992   ourselves.
993 */
994 struct timeval {
995     long tv_sec;
996     long tv_usec;
997 };
998 struct timezone {
999     int tz_minuteswest;
1000     int tz_dsttime;
1001 };
1002 #endif /* UNIXWAREPOSIX */
1003 #endif /* SVORPOSIX */
1004
1005 #ifdef __GNUC__
1006 #ifdef XENIX
1007 /*
1008   Because Xenix <time.h> doesn't declare time() if we're using gcc.
1009 */
1010 time_t time();
1011 #endif /* XENIX */
1012 #endif /* __GNUC__ */
1013
1014 /* Special stuff for V7 input buffer peeking */
1015
1016 #ifdef  V7
1017 int kmem[2] = { -1, -1};
1018 char *initrawq(), *qaddr[2]={0,0};
1019 #define CON 0
1020 #define TTY 1
1021 #endif /* V7 */
1022
1023 /* dftty is the device name of the default device for file transfer */
1024 /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
1025
1026 #ifdef BEOS
1027     char * dftty = NULL;
1028     char * dfmdm = "none";
1029     int dfloc = 0;                  /* that goes in local mode by default */
1030 #else
1031 #ifndef DFTTY
1032 #ifdef PROVX1
1033     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
1034     char *dfmdm = "none";
1035     int dfloc = 1;                  /* that goes in local mode by default */
1036 #else
1037     char *dftty = CTTNAM;               /* Remote by default, use normal */
1038     char *dfmdm = "none";
1039     int dfloc = 0;                      /* controlling terminal name. */
1040 #endif /* PROVX1 */
1041 #else
1042     char *dftty = DFTTY;                /* Default location specified on */
1043     char *dfmdm = "none";               /* command line. */
1044     int dfloc = 1;                      /* controlling terminal name. */
1045 #endif /* DFTTY */
1046 #endif /* BEOS */
1047
1048 #define CON_RES 0                       /* Console state is "reset" */
1049 #define CON_CB  1                       /* Console state is CBREAK */
1050 #define CON_BIN 2                       /* Console state is binary */
1051     static int constate = CON_RES;
1052
1053 #define CONI_RES 0                      /* Console interrupts are "reset" */
1054 #define CONI_INT 1                      /* Console intterupts are set */
1055 #define CONI_NOI 2                      /* Console intterupts are disabled */
1056     static int conistate = CONI_RES;
1057
1058 #ifdef CK_SMALL
1059 #define CONBUFSIZ 15
1060 #else
1061 #define CONBUFSIZ 255
1062 #endif /* CK_SMALL */
1063     static char conbuf[CONBUFSIZ];      /* Console readahead buffer */
1064     static int  conbufn = 0;            /* Chars in readahead buffer */
1065     static char *conbufp = conbuf;      /* Next char in readahead buffer */
1066
1067     char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
1068
1069 #ifdef RTU
1070     int rtu_bug = 0;                /* set to 1 when returning from SIGTSTP */
1071 #endif /* RTU */
1072
1073     int dfprty = DEFPAR;                /* Default parity (0 = none) */
1074     int ttprty = 0;                     /* The parity that is in use. */
1075     static int ttpmsk = 0xff;           /* Parity stripping mask. */
1076     int ttmdm = 0;                      /* Modem in use. */
1077     int ttcarr = CAR_AUT;               /* Carrier handling mode. */
1078     int dfflow = FLO_NONE;              /* Default flow control is NONE */
1079     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
1080 #ifdef F_SETFL
1081     int iniflags = -1;                  /* fcntl flags for ttyfd */
1082 #endif /* F_SETFL */
1083     int fdflag = 0;                     /* Flag for redirected stdio */
1084     int ttfdflg = 0;                    /* Open File descriptor was given */
1085     int tvtflg = 0;                     /* Flag that ttvt has been called */
1086     long ttspeed = -1L;                 /* For saving speed */
1087     int ttflow = -9;                    /* For saving flow */
1088     int ttld = -1;                      /* Line discipline */
1089
1090 #ifdef sony_news
1091     static int km_con = -1;             /* Kanji mode for console tty */
1092     static int km_ext = -1;             /* Kanji mode for external device */
1093 #endif /* sony_news */
1094
1095 #ifdef PARSENSE
1096     static int needpchk = 1;            /* Need parity check */
1097 #else
1098     static int needpchk = 0;
1099 #endif /* PARSENSE */
1100
1101     extern int stopbits;                /* Stop bits */
1102 #ifdef HWPARITY
1103 /*
1104   Unfortunately we must do this with global variables rather than through the
1105   tt...() APIs to avoid changing the APIs and the many modules that use them.
1106   If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
1107   bits + parity or 8 data bits and no parity, and overrides the regular parity
1108   variable, which is communicated to this module thru ttpkt(), and represented
1109   locally by the ttprty variable.
1110 */
1111     extern int hwparity;                /* Hardware parity */
1112 #endif /* HWPARITY */
1113
1114 #ifdef TCPSOCKET
1115 #ifdef TCP_NODELAY
1116 static int nodelay_sav = -1;
1117 #endif /* TCP_NODELAY */
1118 #endif /* TCPSOCKET */
1119
1120 static int sigint_ign = 0;              /* SIGINT is ignored */
1121
1122 /*
1123   Having this module rely on external globals is bad, but fixing this
1124   requires overhaul of the ck*tio.c modules for all the different operating
1125   systems supported by C-Kermit.  Left for a future release.
1126 */
1127 extern int ttnproto;                    /* Defined in ckcnet.c */
1128 extern int ttnet;                       /* Defined in ckcnet.c */
1129 extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
1130 extern int xsuspend, wasclosed;
1131 extern int inserver, local;
1132
1133 int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
1134
1135 int ckmaxfiles = 0;                     /* Max number of open files */
1136
1137 #ifdef CK_ENCRYPTION                    /* Kerberos */
1138 #include "ckuath.h"
1139 extern int me_encrypt, u_encrypt;
1140 #endif /* CK_ENCRYPTION */
1141
1142 /* Declarations of variables global within this module */
1143
1144 #ifdef TTLEBUF                          /* See ckcnet.h */
1145 int ttpush = -1;
1146 #define LEBUFSIZ 4096
1147 static CHAR le_buf[LEBUFSIZ];
1148 static int le_start = 0, le_end = 0, le_data = 0;
1149 #endif /* TTLEBUF */
1150
1151 static int gotsigs = 0;
1152
1153 static time_t tcount = (time_t)0;       /* Elapsed time counter */
1154
1155 static SIGTYP (*saval)()     = NULL;    /* For saving alarm() handler */
1156 static SIGTYP (*savquit)()   = NULL;    /* and other signal handlers */
1157 #ifdef SIGUSR1
1158 static SIGTYP (*savusr1)()   = NULL;
1159 #endif /* SIGUSR1 */
1160 #ifdef SIGUSR2
1161 static SIGTYP (*savusr2)()   = NULL;
1162 #endif /* SIGUSR2 */
1163 #ifdef SIGPIPE
1164 static SIGTYP (*savpipe)()   = NULL;
1165 #endif /* SIGPIPE */
1166 #ifdef SIGDANGER
1167 static SIGTYP (*savdanger)() = NULL;
1168 #endif /* SIGDANGER */
1169
1170 #ifndef NOJC
1171 static SIGTYP (*jchdlr)()    = NULL;    /* For checking suspend handler */
1172 #endif /* NOJC */
1173 static int jcshell = -1;                /* And flag for result */
1174
1175 /*
1176   BREAKNULS is defined for systems that simulate sending a BREAK signal
1177   by sending a bunch of NUL characters at low speed.
1178 */
1179 #ifdef PROVX1
1180 #ifndef BREAKNULS
1181 #define BREAKNULS
1182 #endif /* BREAKNULS */
1183 #endif /* PROVX1 */
1184
1185 #ifdef V7
1186 #ifndef BREAKNULS
1187 #define BREAKNULS
1188 #endif /* BREAKNULS */
1189 #endif /* V7 */
1190
1191 #ifdef BREAKNULS
1192 static char                             /* A string of nulls */
1193 *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";
1194 #endif /* BREAKNULS */
1195
1196 #ifdef CK_POSIX_SIG                     /* Longjump buffers */
1197 static sigjmp_buf sjbuf;                /* POSIX signal handling */
1198 #else
1199 static jmp_buf sjbuf;
1200 #endif /* CK_POSIX_SIG */
1201
1202 #ifdef V7
1203 static jmp_buf jjbuf;
1204 #endif /* V7 */
1205
1206 /* static */                            /* (Not static any more) */
1207 int ttyfd = -1;                         /* TTY file descriptor */
1208
1209 int ttpipe = 0;                         /* NETCMD: Use pipe instead of ttyfd */
1210 int ttpty  = 0;                         /* NETPTY: Use pty instead of ttfyd */
1211
1212 #ifdef NETCMD
1213 #ifdef NETCONN
1214 static int pipe0[2], pipe1[2];          /* Pipes for net i/o */
1215 #endif /* NETCONN */
1216 static PID_T ttpid = 0;                 /* Process ID for fork */
1217 static int fdin, fdout;                 /* File descriptors for pipe */
1218 static FILE * ttout = NULL;             /* File pointer for output pipe */
1219 #ifdef DCLFDOPEN
1220 /* fdopen() needs declaring because it's not declared in <stdio.h> */
1221 _PROTOTYP( FILE * fdopen, (int, char *) );
1222 #endif /* DCLFDOPEN */
1223 #endif /* NETCMD */
1224
1225 extern int pexitstat, quiet;
1226
1227 #ifdef Plan9
1228 int ttyctlfd  = -1;   /* TTY control channel - What? UNIX doesn't have one? */
1229 int consctlfd = -1;                     /* Console control channel */
1230 int noisefd = -1;                       /* tone channel */
1231 static int ttylastspeed = -1;           /* So we can lie about the speed */
1232 #endif /* Plan9 */
1233
1234 int telnetfd = 0;                       /* File descriptor is for telnet */
1235 #ifdef NETCONN
1236 int x25fd = 0;                          /* File descriptor is for X.25 */
1237 #endif /* NETCONN */
1238
1239 char lockpid[16] = { '\0', '\0' };      /* PID stored in lockfile, as string */
1240
1241 static int lkf = 0,                     /* Line lock flag */
1242     cgmf = 0,                           /* Flag that console modes saved */
1243     xlocal = 0,                         /* Flag for tty local or remote */
1244     curcarr = 0;                        /* Carrier mode: require/ignore. */
1245
1246 static int netconn = 0;                 /* 1 if network connection active */
1247
1248 static char escchr;                     /* Escape or attn character */
1249
1250 #ifdef CK_SCO32V4
1251 #include <sys/time.h>
1252 #endif /* CK_SCO32V4 */
1253
1254 #ifdef HAVE_TV
1255     static struct timeval tv;           /* For getting time, from sys/time.h */
1256 #endif /* HAVE_TV */
1257 #ifdef HAVE_TZ
1258     static struct timezone tz;
1259 #endif /* HAVE_TZ */
1260
1261 #ifdef OSF
1262     static struct timeb ftp;            /* And from sys/timeb.h */
1263 #endif /* OSF */
1264
1265 #ifdef BSD29
1266     static long xclock;                 /* For getting time from sys/time.h */
1267     static struct timeb ftp;            /* And from sys/timeb.h */
1268 #endif /* BSD29 */
1269
1270 #ifdef BSD41
1271     static long xclock;                 /* For getting time from sys/time.h */
1272     static struct timeb ftp;            /* And from sys/timeb.h */
1273 #endif /* BSD41 */
1274
1275 #ifdef BELLV10
1276     static long xclock;                 /* For getting time from sys/time.h */
1277     static struct timeb ftp;            /* And from sys/timeb.h */
1278 #endif /* BELLV10 */
1279
1280 #ifdef FT21
1281     static long xclock;                 /* For getting time from sys/time.h */
1282     static struct timeb ftp;            /* And from sys/timeb.h */
1283 #endif /* FT21 */
1284
1285 #ifdef TOWER1
1286     static long xclock;                 /* For getting time from sys/time.h */
1287     static struct timeb ftp;            /* And from sys/timeb.h */
1288 #endif /* TOWER1 */
1289
1290 #ifdef COHERENT
1291     static long xclock;                 /* For getting time from sys/time.h */
1292     static struct timeb ftp;            /* And from sys/timeb.h */
1293 #endif /* COHERENT */
1294
1295 #ifdef V7
1296     static long xclock;
1297 #endif /* V7 */
1298
1299 /* sgtty/termio information... */
1300
1301 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
1302   static struct termios
1303     ttold, ttraw, tttvt, ttcur,
1304     ccold, ccraw, cccbrk;
1305 #else                                   /* BSD, V7, etc */
1306
1307 #ifdef COHERENT                         /* Hack alert... */
1308 #define ATTSV
1309 #endif /* COHERENT */
1310
1311 #ifdef ATTSV
1312   static struct termio ttold = {0};     /* Init'd for word alignment, */
1313   static struct termio ttraw = {0};     /* which is important for some */
1314   static struct termio tttvt = {0};     /* systems, like Zilog... */
1315   static struct termio ttcur = {0};
1316   static struct termio ccold = {0};
1317   static struct termio ccraw = {0};
1318   static struct termio cccbrk = {0};
1319 #else
1320   static struct sgttyb                  /* sgtty info... */
1321     ttold, ttraw, tttvt, ttcur,         /* for communication line */
1322     ccold, ccraw, cccbrk;               /* and for console */
1323 #ifdef BELLV10
1324   static struct ttydevb                 /* Device info... */
1325     tdold, tdcur;                       /* for communication device */
1326 #endif /* BELLV10 */
1327 #ifdef TIOCGETC
1328   static struct tchars tchold, tchnoi;
1329
1330   static int tcharf;
1331 #endif /* TIOCGETC */
1332 #ifdef TIOCGLTC
1333   static struct ltchars ltchold, ltchnoi;
1334   static int ltcharf;
1335 #endif /* TIOCGLTC */
1336   int lmodef = 0;                       /* Local modes */
1337   int lmode = 0;
1338 #endif /* ATTSV */
1339 #endif /* BSD44ORPOSIX */
1340
1341 #ifdef COMMENT
1342 /* It picks up the speeds but they don't work */
1343 #ifdef UNIXWARE                         /* For higher serial speeds */
1344 #ifdef UW7                              /* in Unixware 7.0 */
1345 #include <sys/asyc.h>                   /* This picks up 57600 and 115200 */
1346 #endif /* UW7 */
1347 #endif /* UNIXWARE */
1348 #endif /* COMMENT */
1349
1350 #ifdef PROVX1
1351   static struct sgttyb ttbuf;
1352 #endif /* PROVX1 */
1353
1354 #ifdef ultrix
1355 /* do we really need this? */
1356   static struct sgttyb vanilla;
1357 #endif /* ultrix */
1358
1359 #ifdef ATT7300
1360 static int attmodem = 0;                /* ATT7300 internal-modem status */
1361 struct updata dialer = {0};             /* Condition dialer for data call */
1362 #endif /* ATT7300 */
1363
1364 #ifndef NOUUCP
1365 #define FLFNAML 128
1366 #ifndef USETTYLOCK
1367 #ifdef RTAIX
1368 char lkflfn[FLFNAML] = { '\0', '\0' };  /* and possible link to it */
1369 #endif /* RTAIX */
1370 char lock2[FLFNAML] =  { '\0', '\0' };  /* Name of second lockfile */
1371 #endif /* USETTYLOCK */
1372 #else
1373 #define FLFNAML 7
1374 #endif /* NOUUCP */
1375 char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
1376
1377 int haslock = 0;                        /* =1 if this kermit locked uucp */
1378
1379 #ifndef OXOS
1380 #ifdef SVORPOSIX
1381 static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
1382 #else
1383 #ifdef V7
1384 static int conesc = 0;
1385 #else
1386 #ifdef C70
1387 static int conesc = 0;
1388 #endif /* C70 */
1389 #endif /* V7 */
1390 #endif /* SVORPOSIX */
1391 #endif /* OXOS */
1392
1393 /* Local copy of comm device name or network host */
1394 static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
1395 #ifdef USETTYLOCK
1396 static char lockname[DEVNAMLEN+1];      /* Ditto, the part after "/dev/". */
1397 #endif /* USETTYLOCK */
1398
1399 #ifdef aegis
1400 static status_$t st;                    /* error status return value */
1401 static short concrp = 0;                /* true if console is CRP pad */
1402 static uid_$t ttyuid;                   /* tty type uid */
1403 static uid_$t conuid;                   /* stdout type uid */
1404
1405 /* APOLLO Aegis main()
1406  * establish acl usage and cleanup handling
1407  *    this makes sure that CRP pads
1408  *    get restored to a usable mode
1409  */
1410 main(argc,argv) int argc; char **argv; {
1411         status_$t status;
1412         pfm_$cleanup_rec dirty;
1413
1414         PID_T pid = getpid();
1415
1416         /* acl usage according to invoking environment */
1417         default_acl(USE_DEFENV);
1418
1419         /* establish a cleanup continuation */
1420         status = pfm_$cleanup(dirty);
1421         if (status.all != pfm_$cleanup_set) {
1422                 /* only handle faults for the original process */
1423                 if (pid == getpid() && status.all > pgm_$max_severity) {
1424                     /* blew up in main process */
1425                     status_$t quo;
1426                     pfm_$cleanup_rec clean;
1427
1428                     /* restore the console in any case */
1429                     conres();
1430
1431                     /* attempt a clean exit */
1432                     debug(F101, "cleanup fault status", "", status.all);
1433
1434                     /* doexit(), then send status to continuation */
1435                     quo = pfm_$cleanup(clean);
1436                     if (quo.all == pfm_$cleanup_set)
1437                       doexit(pgm_$program_faulted,-1);
1438                     else if (quo.all > pgm_$max_severity)
1439                       pfm_$signal(quo); /* blew up in doexit() */
1440                 }
1441                 /* send to the original continuation */
1442                 pfm_$signal(status);
1443                 /*NOTREACHED*/
1444             }
1445         return(ckcmai(argc, argv));
1446 }
1447 #endif /* aegis */
1448
1449 /* ANSI-style prototypes for internal functions. */
1450 /* Functions used outside this module are prototyped in ckcker.h. */
1451
1452 #ifdef apollo
1453 _PROTOTYP( SIGTYP timerh, () );
1454 _PROTOTYP( SIGTYP cctrap, () );
1455 _PROTOTYP( SIGTYP esctrp, () );
1456 _PROTOTYP( SIGTYP sig_ign, () );
1457 #else
1458 _PROTOTYP( SIGTYP timerh, (int) );
1459 _PROTOTYP( SIGTYP cctrap, (int) );
1460 _PROTOTYP( SIGTYP esctrp, (int) );
1461 #endif /* apollo */
1462 _PROTOTYP( int do_open, (char *) );
1463 _PROTOTYP( static int in_chk, (int, int) );
1464 _PROTOTYP( static int ttrpid, (char *) );
1465 _PROTOTYP( static int ttchkpid, (char *) );
1466 _PROTOTYP( static int ttlock, (char *) );
1467 _PROTOTYP( static int ttunlck, (void) );
1468 _PROTOTYP( int mygetbuf, (void) );
1469 _PROTOTYP( int myfillbuf, (void) );
1470 _PROTOTYP( VOID conbgt, (int) );
1471 #ifdef ACUCNTRL
1472 _PROTOTYP( VOID acucntrl, (char *, char *) );
1473 #endif /* ACUCNTRL */
1474
1475 #ifdef BSD44ORPOSIX
1476 _PROTOTYP( int carrctl, (struct termios *, int) );
1477 #else
1478 #ifdef ATTSV
1479 _PROTOTYP( int carrctl, (struct termio *, int) );
1480 #else
1481 _PROTOTYP( int carrctl, (struct sgttyb *, int) );
1482 #endif /* ATTSV */
1483 #endif /* BSD44ORPOSIX */
1484
1485 #ifdef ATT7300
1486 _PROTOTYP( int attdial, (char *, long, char *) );
1487 _PROTOTYP( int offgetty, (char *) );
1488 _PROTOTYP( int ongetty, (char *) );
1489 #endif /* ATT7300 */
1490
1491 #ifdef BEOSORBEBOX
1492 #ifdef SELECT
1493     /* BeOS is not capable of using SELECT on anything but sockets */
1494 #undef SELECT
1495 #endif /* SELECT */
1496 #include <kernel/OS.h>
1497 /* #ifdef BE_DR_7 */
1498 static double time_started = 0.0;
1499 struct ALARM_STRUCT {
1500     thread_id thread;
1501     int time;
1502 };
1503 static thread_id alarm_thread = -1;
1504 static struct ALARM_STRUCT alarm_struct;
1505 _PROTOTYP( long do_alarm, (void *) );
1506 _PROTOTYP( unsigned int alarm, (unsigned int) );
1507 _PROTOTYP( void alarm_expired, (void) );
1508 /* #endif */ /* BE_DR_7 */
1509 #endif /* BEOSORBEBOX */
1510
1511 #ifndef xunchar
1512 #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
1513 #endif /* xunchar */
1514
1515 #ifdef CK_ANSIC
1516 static char *
1517 xxlast(char *s, char c)
1518 #else
1519 static char *
1520 xxlast(s,c) char *s; char c;
1521 #endif /* CK_ANSIC */
1522 /* xxlast */ {          /*  Last occurrence of character c in string s. */
1523     int i;
1524     for (i = (int)strlen(s); i > 0; i--)
1525       if (s[i-1] == c ) return(s + (i - 1));
1526     return(NULL);
1527 }
1528
1529 /* Timeout handler for communication line input functions */
1530
1531 /*ARGSUSED*/
1532 SIGTYP
1533 timerh(foo) int foo; {
1534     ttimoff();
1535 #ifdef BEOSORBEBOX
1536 /* #ifdef BE_DR_7 */
1537     alarm_expired();
1538 /* #endif */ /* BE_DR_7 */
1539 #endif /* BEOSORBEBOX */
1540 #ifdef CK_POSIX_SIG
1541     siglongjmp(sjbuf,1);
1542 #else
1543     longjmp(sjbuf,1);
1544 #endif /* CK_POSIX_SIG */
1545 }
1546
1547 /*ARGSUSED*/
1548 SIGTYP
1549 xtimerh(foo) int foo; {                 /* Like timerh() but does */
1550 #ifdef BEOSORBEBOX                      /* not reset the timer itslef */
1551 /* #ifdef BE_DR_7 */
1552     alarm_expired();
1553 /* #endif */ /* BE_DR_7 */
1554 #endif /* BEOSORBEBOX */
1555 #ifdef CK_POSIX_SIG
1556     siglongjmp(sjbuf,1);
1557 #else
1558     longjmp(sjbuf,1);
1559 #endif /* CK_POSIX_SIG */
1560 }
1561
1562
1563 /* Control-C trap for communication line input functions */
1564
1565 int cc_int;                             /* Flag */
1566 SIGTYP (* occt)();                      /* For saving old SIGINT handler */
1567
1568 /*ARGSUSED*/
1569 SIGTYP
1570 cctrap(foo) int foo; {                  /* Needs arg for ANSI C */
1571   cc_int = 1;                           /* signal() prototype. */
1572   return;
1573 }
1574
1575 /*  S Y S I N I T  --  System-dependent program initialization.  */
1576
1577 /*
1578  * ttgwsiz() returns:
1579  *      1    tt_rows and tt_cols are known, both altered, both > 0
1580  *      0    tt_rows and/or tt_cols are known, both altered, one or both <= 0
1581  *      -1   tt_rows and tt_cols are unknown and unaltered
1582  */
1583
1584 extern int tt_rows, tt_cols;
1585
1586 static int
1587 xttgwsiz() {
1588     char *p;
1589     int rows = 0, cols = 0;
1590     p = getenv("LINES");
1591     debug(F110,"xttgwsiz LINES",p,0);
1592     if (p) {
1593         rows = atol(p);
1594         if (rows > 0) {
1595             p = getenv("COLUMNS");
1596             debug(F110,"xttgwsiz COLUMNS",p,0);
1597             if (p) {
1598                 cols = atol(p);
1599                 if (cols > 0) {
1600                     tt_rows = rows;
1601                     tt_cols = cols;
1602                     return(1);
1603                 }
1604                 return(0);
1605             }
1606         }
1607     }
1608     return(-1);
1609 }
1610
1611 #ifdef TTLEBUF
1612 VOID
1613 le_init() {                             /* LocalEchoInit() */
1614     int i;
1615     for (i = 0; i < LEBUFSIZ; i++)
1616       le_buf[i] = '\0';
1617     le_start = 0;
1618     le_end = 0;
1619     le_data = 0;
1620 }
1621
1622 VOID
1623 le_clean() {                            /* LocalEchoCleanup() */
1624     le_init();
1625     return;
1626 }
1627
1628 int
1629 le_inbuf() {
1630     int rc = 0;
1631     if (le_start != le_end) {
1632         rc = (le_end -
1633               le_start +
1634               LEBUFSIZ) % LEBUFSIZ;
1635     }
1636     debug(F111,"le_inbuf","chars waiting",rc);
1637     return(rc);
1638 }
1639
1640 int
1641 #ifdef CK_ANSIC
1642 le_putchar(CHAR ch)
1643 #else
1644 le_putchar(ch) CHAR ch;
1645 #endif /* CK_ANSIC */
1646 /* le_putchar */ {
1647 #ifdef COMMENT
1648     /* In UNIX we do not have another thread taking chars out of the buffer */
1649     while ((le_start - le_end == 1) ||
1650             (le_start == 0 && le_end == LEBUFSIZ - 1)) {
1651         /* Buffer is full */
1652         debug(F111,"le_putchar","Buffer is Full",ch);
1653         ReleaseLocalEchoMutex() ;
1654         msleep(250);
1655         RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
1656     }
1657 #else
1658     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
1659         debug(F110,"le_putchar","buffer is full",0);
1660         return(-1);
1661     }
1662 #endif /* COMMENT */
1663     le_buf[le_end++] = ch;
1664     if (le_end == LEBUFSIZ)
1665       le_end = 0;
1666     le_data = 1;
1667     return(0);
1668 }
1669
1670 int
1671 #ifdef CK_ANSIC
1672 le_puts(CHAR * s, int n)
1673 #else
1674 le_puts(s,n) CHAR * s; int n;
1675 #endif /* CK_ANSIC */
1676 /* le_puts */ {
1677     int rc = 0;
1678     int i = 0;
1679     CHAR * p = (CHAR *)"le_puts";
1680     hexdump(p,s,n);
1681     for (i = 0; i < n; i++)
1682       rc = le_putchar((char)s[i]);
1683     debug(F101,"le_puts","",rc);
1684     return(rc);
1685 }
1686
1687 int
1688 #ifdef CK_ANSIC
1689 le_putstr(CHAR * s)
1690 #else
1691 le_putstr(s) CHAR * s;
1692 #endif /* CK_ANSIC */
1693 /* le_puts */ {
1694     CHAR * p;
1695     int rc = 0;
1696     p = (CHAR *)"le_putstr";
1697     hexdump(p,s,(int)strlen((char *)s));
1698     for (p = s; *p && !rc; p++)
1699       rc = le_putchar(*p);
1700     return(rc);
1701 }
1702
1703 int
1704 #ifdef CK_ANSIC
1705 le_getchar(CHAR * pch)
1706 #else /* CK_ANSIC */
1707 le_getchar(pch) CHAR * pch;
1708 #endif /* CK_ANSIC */
1709 /* le_gatchar */ {
1710     int rc = 0;
1711     if (le_start != le_end) {
1712         *pch = le_buf[le_start];
1713         le_buf[le_start] = 0;
1714         le_start++;
1715
1716         if (le_start == LEBUFSIZ)
1717           le_start = 0;
1718
1719         if (le_start == le_end) {
1720             le_data = 0;
1721         }
1722         rc++;
1723     } else {
1724         *pch = 0;
1725     }
1726     return(rc);
1727 }
1728 #endif /* TTLEBUF */
1729
1730 #ifdef COMMENT
1731 /*
1732   Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
1733   But as far as I know, whenever TIOCGSIZE is defined, it is
1734   equated to TIOCGWINSZ.  For cases where this is not done, try this:
1735 */
1736 #ifndef TIOCGWINSZ
1737 #ifdef TIOCGSIZE
1738 #define TIOCGWINSZ TIOCGSIZE
1739 #endif /* TIOCGSIZE */
1740 #endif /* TIOCGWINSZ */
1741 #endif /* COMMENT */
1742
1743 static int tt_xpixel = 0, tt_ypixel = 0;
1744
1745 int
1746 ttgwsiz() {
1747     int x = 0;
1748 #ifndef NONAWS
1749 #ifdef QNX
1750 /*
1751   NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
1752   This code works for both the 16- and 32-bit versions.
1753 */
1754     extern int dev_size(int, int, int, int *, int *);
1755     int r, c;
1756
1757     if (dev_size(0, -1, -1, &r, &c) == 0) {
1758         debug(F101,"ttgwsiz QNX r","",r);
1759         debug(F101,"ttgwsiz QNX c","",c);
1760         tt_rows = r;
1761         tt_cols = c;
1762         return ((r > 0 && c > 0) ? 1 : 0);
1763     } else return(xttgwsiz());
1764 #else /* QNX */
1765 #ifdef TIOCGWINSZ
1766
1767 /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
1768 #ifdef XENIX                            /* SCO UNIX 3.2v4.0 */
1769 #include <sys/stream.h>                 /* typedef mblk_t needed by ptem.h */
1770 #include <sys/ptem.h>                   /* for ttgwsiz() */
1771 #endif /* XENIX */
1772
1773 #ifdef I386IX                           /* Ditto for Interactive */
1774 #include <sys/stream.h>
1775 #include <sys/ptem.h>
1776 #endif /* I386IX */
1777
1778 /* Note, the above might be needed for some other older SVR3 Intel makes... */
1779
1780     struct winsize w;
1781     tt_xpixel = 0;
1782     tt_ypixel = 0;
1783
1784 #ifdef IKSD
1785     if (inserver)
1786       return(xttgwsiz());
1787 #endif /* IKSD */
1788     x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
1789     debug(F101,"ttgwsiz TIOCGWINSZ","",x);
1790     if (x < 0) {
1791         return(xttgwsiz());
1792     } else if (w.ws_row > 0 && w.ws_col > 0) {
1793         tt_rows = w.ws_row;
1794         tt_cols = w.ws_col;
1795         tt_xpixel = w.ws_xpixel;
1796         tt_ypixel = w.ws_ypixel;
1797         debug(F101,"ttgwsiz tt_rows","",tt_rows);
1798         debug(F101,"ttgwsiz tt_cols","",tt_cols);
1799         return(1);
1800     } else {
1801         debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
1802         return(xttgwsiz());
1803     }
1804 #else
1805     return(xttgwsiz());
1806 #endif /* TIOCGWINSZ */
1807 #endif /* QNX */
1808 #endif /* NONAWS */
1809 }
1810
1811
1812 #ifndef NOSIGWINCH
1813 #ifdef SIGWINCH
1814 SIGTYP
1815 winchh(foo) int foo; {                  /* SIGWINCH handler */
1816     int x = 0;
1817 #ifdef NETPTY
1818     extern int pty_fork_pid;
1819 #endif /* NETPTY */
1820 #ifdef CK_TTYFD
1821 #ifndef VMS
1822     extern int ttyfd;
1823 #endif /* VMS */
1824 #endif /* CK_TTYFD */
1825     extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
1826 #ifdef DEBUG
1827     if (deblog) {
1828         debug(F100,"***************","",0);
1829         debug(F100,"SIGWINCH caught","",0);
1830         debug(F100,"***************","",0);
1831 #ifdef NETPTY
1832         debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
1833 #endif /* NETPTY */
1834     }
1835 #endif /* DEUB */
1836     signal(SIGWINCH,winchh);            /* Re-arm the signal */
1837     x = ttgwsiz();                      /* Get new window size */
1838     cmd_rows = tt_rows;                 /* Adjust command screen too */
1839     cmd_cols = tt_cols;
1840
1841 #ifdef CK_TTYFD
1842     if                                  /* If we don't have a connection */
1843 #ifdef VMS                              /* we're done. */
1844       (vmsttyfd() == -1)
1845 #else
1846       (ttyfd == -1)
1847 #endif /* VMS */
1848 #else
1849       (!local)
1850 #endif /* CK_TTYFD */
1851         return;
1852
1853 #ifdef NETPTY
1854     if (pty_fork_pid > -1) {            /* "set host" to a PTY? */
1855         int x;
1856
1857 #ifdef TIOCSWINSZ
1858         struct winsize w;               /* Resize the PTY */
1859         errno = 0;
1860         w.ws_col = tt_cols;
1861         w.ws_row = tt_rows;
1862         w.ws_xpixel = tt_xpixel;
1863         w.ws_ypixel = tt_ypixel;
1864         x = ioctl(ttyfd,TIOCSWINSZ,&w);
1865         debug(F101,"winchh TIOCSWINSZ","",x);
1866         debug(F101,"winchh TIOCSWINSZ errno","",errno);
1867 #endif /* TIOCSWINSZ */
1868
1869         errno = 0;
1870         x = kill(pty_fork_pid,SIGWINCH);
1871         debug(F101,"winchh kill","",x);
1872         debug(F101,"winchh kill errno","",errno);
1873     }
1874 #endif /* NETPTY */
1875
1876 /*
1877   This should be OK.  It might seem that sending this from
1878   interrupt level could interfere with another TELNET IAC string
1879   that was in the process of being sent.  But we always send
1880   TELNET strings with a single write(), which should prevent mixups.
1881   blah_snaws() should protect themselves from being called on the
1882   wrong kind of connection.
1883 */
1884 #ifdef TCPSOCKET
1885 #ifndef NOTTGWSIZ
1886     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
1887         tn_snaws();
1888 #ifdef RLOGCODE
1889         rlog_naws();
1890 #endif /* RLOGCODE */
1891     }
1892 #endif /* NOTTGWSIZ */
1893 #endif /* TCPSOCKET */
1894     SIGRETURN;
1895 }
1896 #endif /* SIGWINCH */
1897 #endif /* NOSIGWINCH */
1898
1899 SIGTYP
1900 sighup(foo) int foo; {                  /* SIGHUP handler */
1901     backgrd = 1;
1902     debug(F100,"***************","",0);
1903     debug(F100,"SIGHUP received","",0);
1904     debug(F100,"***************","",0);
1905     doexit(BAD_EXIT,-1);
1906     /*NOTREACHED*/
1907     SIGRETURN;                          /* Shut picky compilers up... */
1908 }
1909
1910 #ifdef CK_SCO32V4
1911 /* Exists but there is no prototype in the header files */
1912 _PROTOTYP( char * ttyname, (int) );
1913 #else
1914 #ifdef SV68R3V6
1915 _PROTOTYP( char * ttyname, (int) );
1916 #else
1917 #ifdef ultrix
1918 _PROTOTYP( char * ttyname, (int) );
1919 #else
1920 #ifdef HPUX6
1921 _PROTOTYP( char * ttyname, (int) );
1922 #else
1923 #ifdef HPUX5
1924 _PROTOTYP( char * ttyname, (int) );
1925 #else
1926 #ifdef PS2AIX10
1927 _PROTOTYP( char * ttyname, (int) );
1928 #else
1929 #ifdef BSD42
1930 _PROTOTYP( char * ttyname, (int) );
1931 #endif /* BSD42 */
1932 #endif /* PS2AIX10 */
1933 #endif /* HPUX5 */
1934 #endif /* HPUX6 */
1935 #endif /* ultrix */
1936 #endif /* SV68R3V6 */
1937 #endif /* CK_SCO32V4 */
1938
1939 #ifndef SIGUSR1                         /* User-defined signals */
1940 #define SIGUSR1 30
1941 #endif /* SIGUSR1 */
1942
1943 #ifndef SIGUSR2
1944 #define SIGUSR2 31
1945 #endif /* SIGUSR2 */
1946
1947 /*
1948   ignorsigs() sets certain signals to SIG_IGN.  But when a signal is
1949   ignored, it remains ignored across exec(), so we have to restore these
1950   signals before exec(), which is the purpose of restorsigs().
1951 */
1952 static VOID
1953 ignorsigs() {                           /* Ignore these signals */
1954     savquit = signal(SIGQUIT,SIG_IGN);  /* Ignore Quit signal */
1955
1956 #ifdef SIGDANGER                        /* Ignore danger signals */
1957 /*
1958   This signal is sent when the system is low on swap space.  Processes
1959   that don't handle it are candidates for termination.  If swap space doesn't
1960   clear out enough, we still might be terminated via kill() -- nothing we can
1961   do about that!  Conceivably, this could be improved by installing a real
1962   signal handler that warns the user, but that would be pretty complicated,
1963   since we are not always in control of the screen -- e.g. during remote-mode
1964   file transfer.
1965 */
1966     savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
1967 #endif /* SIGDANGER */
1968 #ifdef SIGPIPE
1969 /*
1970   This one comes when a TCP/IP connection is broken by the remote.
1971   We prefer to catch this situation by examining error codes from write().
1972 */
1973     savpipe = signal(SIGPIPE,SIG_IGN);
1974 #endif /* SIGPIPE */
1975     savusr1 = signal(SIGUSR1,SIG_IGN);  /* Ignore user-defined signals */
1976     savusr2 = signal(SIGUSR2,SIG_IGN);
1977 }
1978
1979 VOID
1980 restorsigs() {                          /* Restore these signals */
1981     (VOID) signal(SIGQUIT,savquit);     /* (used in ckufio.c) */
1982 #ifdef SIGDANGER
1983     (VOID) signal(SIGDANGER,savdanger);
1984 #endif /* SIGDANGER */
1985 #ifdef SIGPIPE
1986     (VOID) signal(SIGPIPE,savpipe);
1987 #endif /* SIGPIPE */
1988     (VOID) signal(SIGUSR1,savusr1);
1989     (VOID) signal(SIGUSR2,savusr2);
1990 }
1991
1992 int
1993 sysinit() {
1994     int x;
1995     char * s;
1996 #ifdef CK_UTSNAME
1997     struct utsname name;
1998 #endif /* CK_UTSNAME */
1999
2000     extern char startupdir[];
2001 /*
2002   BEFORE ANYTHING ELSE: Initialize the setuid package.
2003   Change to the user's real user and group ID.
2004   If this can't be done, don't run at all.
2005 */
2006     x = priv_ini();
2007 #ifdef SUIDDEBUG
2008     fprintf(stderr,"PRIV_INI=%d\n",x);
2009 #endif /* SUIDDEBUG */
2010     if (x) {
2011         if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
2012         if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
2013         if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
2014         exit(1);
2015     }
2016     signal(SIGINT,SIG_IGN);             /* Ignore interrupts at first */
2017     signal(SIGFPE,SIG_IGN);             /* Ignore floating-point exceptions */
2018     signal(SIGHUP,sighup);              /* Catch SIGHUP */
2019 #ifndef NOSIGWINCH
2020 #ifdef SIGWINCH
2021     signal(SIGWINCH,winchh);            /* Catch window-size change */
2022 #endif /* SIGWINCH */
2023 #endif /* NOSIGWINCH */
2024
2025 #ifndef NOJC
2026 /*
2027   Get the initial job control state.
2028   If it is SIG_IGN, that means the shell does not support job control,
2029   and so we'd better not suspend ourselves.
2030 */
2031 #ifdef SIGTSTP
2032     jchdlr = signal(SIGTSTP,SIG_IGN);
2033     if (jchdlr == SIG_IGN) {
2034         jcshell = 0;
2035         debug(F100,"sysinit jchdlr: SIG_IGN","",0);
2036     } else if (jchdlr == SIG_DFL) {
2037         debug(F100,"sysinit jchdlr: SIG_DFL","",0);
2038         jcshell = 1;
2039     } else {
2040         debug(F100,"sysinit jchdlr: other","",0);
2041         jcshell = 3;
2042     }
2043     (VOID) signal(SIGTSTP,jchdlr);      /* Put it back... */
2044 #endif /* SIGTSTP */
2045 #endif /* NOJC */
2046
2047     conbgt(0);                          /* See if we're in the background */
2048     congm();                            /* Get console modes */
2049
2050     (VOID) signal(SIGALRM,SIG_IGN);     /* Ignore alarms */
2051
2052     ignorsigs();                        /* Ignore some other signals */
2053
2054 #ifdef F_SETFL
2055     iniflags = fcntl(0,F_GETFL,0);      /* Get stdin flags */
2056 #endif /* F_SETFL */
2057
2058 #ifdef ultrix
2059     gtty(0,&vanilla);                   /* Get sgtty info */
2060 #else
2061 #ifdef AUX
2062     set42sig();                         /* Don't ask! (hakanson@cs.orst.edu) */
2063 #endif /* AUX */
2064 #endif /* ultrix */
2065 /*
2066   Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
2067   never closes it.  If it is called often enough, we run out of file
2068   descriptors and subsequent open()'s of other devices or files can fail.
2069 */
2070     s = NULL;
2071 #ifndef MINIX
2072     if (isatty(0))                      /* Name of controlling terminal */
2073       s = ttyname(0);
2074     else if (isatty(1))
2075       s = ttyname(1);
2076     else if (isatty(2))
2077       s = ttyname(2);
2078     debug(F110,"sysinit ttyname(0)",s,0);
2079 #endif /* MINIX */
2080
2081 #ifdef BEOS
2082     if (!dftty)
2083       makestr(&dftty,s);
2084 #endif /* BEOS */
2085
2086     if (s)
2087       ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
2088 #ifdef SVORPOSIX
2089     if (!cttnam[0])
2090       ctermid(cttnam);
2091 #endif /* SVORPOSIX */
2092     if (!cttnam[0])
2093       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
2094     debug(F110,"sysinit CTTNAM",CTTNAM,0);
2095     debug(F110,"sysinit cttnam",cttnam,0);
2096
2097     ttgwsiz();                          /* Get window (screen) dimensions. */
2098
2099 #ifndef NOSYSCONF
2100 #ifdef _SC_OPEN_MAX
2101     ckmaxfiles = sysconf(_SC_OPEN_MAX);
2102 #endif /* _SC_OPEN_MAX */
2103 #endif /* NOSYSCONF */
2104
2105 #ifdef Plan9
2106     if (!backgrd) {
2107         consctlfd = open("/dev/consctl", O_WRONLY);
2108         /*noisefd = open("/dev/noise", O_WRONLY)*/
2109     }
2110     ckxech = 1;
2111 #endif /* Plan9 */
2112
2113 #ifdef CK_UTSNAME
2114     if (uname(&name) > -1) {
2115         ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
2116         ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
2117         ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
2118         ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
2119 #ifdef DEBUG
2120         if (deblog) {
2121             debug(F110,"sysinit uname machine",unm_mch,0);
2122             debug(F110,"sysinit uname sysname",unm_nam,0);
2123             debug(F110,"sysinit uname release",unm_rel,0);
2124             debug(F110,"sysinit uname version",unm_ver,0);
2125         }
2126 #endif /* DEBUG */
2127
2128 #ifdef HPUX9PLUS
2129         if (name.machine[5] == '8')
2130           hpis800 = 1;
2131         else
2132           hpis800 = 0;
2133         debug(F101,"sysinit hpis800","",hpis800);
2134 #endif /* HPUX9PLUS */
2135 #ifdef TRU64
2136         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
2137         debug(F110,"sysinit getsysinfo model",unm_mod,0);
2138 #endif /* TRU64 */
2139 #ifdef SOLARIS25
2140         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
2141         debug(F110,"sysinit sysinfo model",unm_mod,0);
2142 #endif /* SOLARIS25 */
2143     }
2144 #endif /* CK_UTSNAME */
2145
2146 #ifdef CK_ENVIRONMENT
2147     {
2148 #ifdef TNCODE
2149         extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
2150         tn_env_prnt[], tn_env_sys[];
2151 #endif /* TNCODE */
2152         extern char uidbuf[];
2153         extern char * whoami();
2154         char *p;
2155 #ifdef CKSENDUID
2156         uidbuf[0] = '\0';
2157 #ifdef IKSD
2158         if (!inserver) {
2159 #endif /* IKSD */
2160             p = getenv("USER");
2161             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
2162             if (!p) p = "";
2163             if (!*p) {
2164                 p = getenv("LOGNAME");
2165                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
2166             }
2167             if (!p) p = "";
2168             if (!*p) {
2169                 p = whoami();
2170                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
2171             }
2172             if (!p) p = "";
2173             ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
2174 #ifdef IKSD
2175         }
2176 #endif /* IKSD */
2177         debug(F110,"sysinit final uidbuf",uidbuf,0);
2178 #endif /* CKSENDUID */
2179
2180 #ifdef TNCODE
2181         if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
2182         if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
2183         if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
2184         if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
2185 #ifdef aegis
2186         ckstrncpy(tn_env_sys,"Aegis",64);
2187 #else
2188 #ifdef Plan9
2189         ckstrncpy(tn_env_sys,"Plan9",64);
2190 #else
2191         ckstrncpy(tn_env_sys,"UNIX",64);
2192 #endif /* Plan9 */
2193 #endif /* aegis */
2194 #endif /* TNCODE */
2195     }
2196 #endif /* CK_ENVIRONMENT */
2197 #ifdef CK_SNDLOC
2198     {
2199         extern char * tn_loc;
2200         char *p;
2201         if (p = getenv("LOCATION"))
2202           if (tn_loc = (char *)malloc((int)strlen(p)+1))
2203             strcpy(tn_loc,p);           /* safe */
2204     }
2205 #endif /* CK_SNDLOC */
2206
2207     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
2208     startupdir[CKMAXPATH] = '\0';
2209     x = strlen(startupdir);
2210     if (x <= 0) {
2211         startupdir[0] = '/';
2212         startupdir[1] = '\0';
2213     } else if (startupdir[x-1] != '/') {
2214         startupdir[x] = '/';
2215         startupdir[x+1] = '\0';
2216     }
2217     debug(F110,"sysinit startupdir",startupdir,0);
2218 #ifdef TTLEBUF
2219     le_init();
2220 #endif /* TTLEBUF */
2221 #ifdef BSD44ORPOSIX
2222     /* This should catch the ncurses platforms */
2223     /* Some platforms don't have putenv(), like NeXTSTEP */
2224     putenv("NCURSES_NO_SETBUF=1");
2225 #endif /* BSD44ORPOSIX */
2226     return(0);
2227 }
2228
2229 /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
2230
2231 int
2232 syscleanup() {
2233 #ifdef F_SETFL
2234     if (iniflags > -1)
2235       fcntl(0,F_SETFL,iniflags);        /* Restore stdin flags */
2236 #endif /* F_SETFL */
2237 #ifdef ultrix
2238     stty(0,&vanilla);                   /* Get sgtty info */
2239 #endif /* ultrix */
2240 #ifdef NETCMD
2241     if (ttpid) kill(ttpid,9);
2242 #endif /* NETCMD */
2243     return(0);
2244 }
2245
2246 /*  T T O P E N  --  Open a tty for exclusive access.  */
2247
2248 /*
2249   Call with:
2250     ttname: character string - device name or network host name.
2251     lcl:
2252   If called with lcl < 0, sets value of lcl as follows:
2253   0: the terminal named by ttname is the job's controlling terminal.
2254   1: the terminal named by ttname is not the job's controlling terminal.
2255   But watch out: if a line is already open, or if requested line can't
2256   be opened, then lcl remains (and is returned as) -1.
2257     modem:
2258   Less than zero: ttname is a network host name.
2259   Zero or greater: ttname is a terminal device name.
2260   Zero means a local connection (don't use modem signals).
2261   Positive means use modem signals.
2262    timo:
2263   0 = no timer.
2264   nonzero = number of seconds to wait for open() to return before timing out.
2265
2266   Returns:
2267     0 on success
2268    -5 if device is in use
2269    -4 if access to device is denied
2270    -3 if access to lock directory denied
2271    -2 upon timeout waiting for device to open
2272    -1 on other error
2273 */
2274 static int ttotmo = 0;                  /* Timeout flag */
2275 /* Flag kept here to avoid being clobbered by longjmp.  */
2276
2277 int
2278 ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
2279
2280 #ifdef BSD44
2281 #define ctermid(x) strcpy(x,"")
2282 #else
2283 #ifdef SVORPOSIX
2284 #ifndef CIE
2285     extern char *ctermid();             /* Wish they all had this! */
2286 #else                                   /* CIE Regulus */
2287 #define ctermid(x) strcpy(x,"")
2288 #endif /* CIE */
2289 #endif /* SVORPOSIX */
2290 #endif /* BSD44 */
2291
2292 #ifdef ultrix
2293     int temp = 0;
2294 #endif /* ultrix */
2295
2296 #ifndef OPENFIRST
2297     char fullname[DEVNAMLEN+1];
2298 #endif /* OPENFIRST */
2299
2300     char * fnam;                        /* Full name after expansion */
2301
2302     int y;
2303
2304 #ifndef pdp11
2305 #define NAMEFD   /* Feature to allow name to be an open file descriptor */
2306 #endif /* pdp11 */
2307
2308 #ifdef NAMEFD
2309     char *p;
2310     debug(F101,"ttopen telnetfd","",telnetfd);
2311 #endif /* NAMEFD */
2312
2313     debug(F110,"ttopen ttname",ttname,0);
2314     debug(F110,"ttopen ttnmsv",ttnmsv,0);
2315     debug(F101,"ttopen modem","",modem);
2316     debug(F101,"ttopen netconn","",netconn);
2317     debug(F101,"ttopen ttyfd","",ttyfd);
2318     debug(F101,"ttopen *lcl","",*lcl);
2319     debug(F101,"ttopen ttmdm","",ttmdm);
2320     debug(F101,"ttopen ttnet","",ttnet);
2321
2322     ttpmsk = 0xff;
2323     lockpid[0] = '\0';
2324
2325     if (ttyfd > -1) {                   /* If device already opened */
2326         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
2327           return(0);                    /* Yes, nothing to do - just return */
2328         ttnmsv[0] = '\0';               /* No, clear out old name */
2329         ttclos(ttyfd);                  /* close old connection.  */
2330     }
2331     wasclosed = 0;                      /* New connection, not closed yet. */
2332     ttpipe = 0;                         /* Assume it's not a pipe */
2333     ttpty = 0;                          /* or a pty... */
2334
2335 #ifdef NETCONN
2336 /*
2337   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
2338   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
2339   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
2340   this point we've obliterated the negative modem type hack, and so would
2341   treat the IP hostname as a device name, and would then fail because of "No
2342   such device or directory".  But the previous connection has left behind some
2343   clues, so let's use them...
2344 */
2345     if (ttyfd < 0) {                    /* Connection is not open */
2346         if (!strcmp(ttname,ttnmsv)) {   /* Old and new names the same? */
2347             if (((netconn > 0) && (ttmdm < 0)) ||
2348                 ((ttnet > 0) &&
2349                  (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
2350                 ) {
2351                 int x, rc;
2352                 x = (ttmdm < 0) ? -ttmdm : ttnet;
2353                 rc = netopen(ttname, lcl, x);
2354                 debug(F111,"ttopen REOPEN netopen",ttname,rc);
2355                 if (rc > -1) {
2356                     netconn = 1;
2357                     xlocal = *lcl = 1;
2358                 } else {
2359                     netconn = 0;
2360                 }
2361                 gotsigs = 0;
2362                 return(rc);
2363             }
2364         }
2365     }
2366 #endif /* NETCONN */
2367
2368 #ifdef MAXNAMLEN
2369     debug(F100,"ttopen MAXNAMLEN defined","",0);
2370 #else
2371     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
2372 #endif
2373
2374 #ifdef BSD4
2375     debug(F100,"ttopen BSD4 defined","",0);
2376 #else
2377     debug(F100,"ttopen BSD4 *NOT* defined","",0);
2378 #endif /* BSD4 */
2379
2380 #ifdef BSD42
2381     debug(F100,"ttopen BSD42 defined","",0);
2382 #else
2383     debug(F100,"ttopen BSD42 *NOT* defined","",0);
2384 #endif /* BSD42 */
2385
2386 #ifdef MYREAD
2387     debug(F100,"ttopen MYREAD defined","",0);
2388 #else
2389     debug(F100,"ttopen MYREAD *NOT* defined","",0);
2390 #endif /* MYREAD */
2391
2392 #ifdef  NETCONN
2393     if (modem < 0) {                    /* modem < 0 = code for network */
2394         int x;
2395         ttmdm = modem;
2396         modem = -modem;                 /* Positive network type number */
2397         fdflag = 0;                     /* Stdio not redirected. */
2398         netconn = 1;                    /* And it's a network connection */
2399         debug(F111,"ttopen net",ttname,modem);
2400 #ifdef NAMEFD
2401         for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
2402         if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
2403             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2404             ttfdflg = 1;                /* We got an open file descriptor */
2405             debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
2406             debug(F101,"ttopen net ttyfd","",ttyfd);
2407             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2408             x = 1;                      /* Return code is "good". */
2409             if (telnetfd) {
2410                 ttnet = NET_TCPB;
2411                 if (ttnproto != NP_TCPRAW)
2412                   ttnproto = NP_TELNET;
2413 #ifdef SUNX25
2414             } else if (x25fd) {
2415                 ttnet = NET_SX25;
2416                 ttnproto = NP_NONE;
2417 #endif /* SUNX25 */
2418             }
2419         } else {                        /* Host name or address given */
2420 #ifdef NETPTY
2421             if (modem == NET_PTY) {
2422                 int x;
2423                 if (nopush) {
2424                     debug(F100,"ttopen PTY: nopush","",0);
2425                     return(-1);
2426                 }
2427                 ttnet = NET_PTY;
2428                 ttnproto = NP_NONE;
2429                 netconn = 1;            /* but we don't use network i/o */
2430                 ttpty = 1;
2431                 debug(F110,"ttopen PTY",ttname,0);
2432                 x = do_pty(ttname);
2433                 if (x > -1) {
2434                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2435                     xlocal = *lcl = 1;  /* It's local */
2436                 } else {
2437                     ttpty = 0;
2438                     netconn = 0;
2439                 }
2440                 gotsigs = 0;
2441                 return(x);
2442             }
2443 #endif /* NETPTY */
2444 #ifdef NETCMD
2445 /*
2446   dup2() is not available on older System V platforms like AT&T 3Bx.  For
2447   those systems we punt by not defining NETCMD, but we might be able to do
2448   better -- see workarounds for this problem in ckufio.c (search for dup2).
2449 */
2450             if (modem == NET_CMD) {
2451                 if (nopush) {
2452                     debug(F100,"ttopen pipe: nopush","",0);
2453                     return(-1);
2454                 }
2455                 if (pipe(pipe0) || pipe(pipe1)) {
2456                     perror("Pipe error");
2457                     return(-1);
2458                 }
2459                 ttpid = fork();         /* Make a fork */
2460
2461                 switch (ttpid) {
2462                   case -1:              /* Error making fork */
2463                     close(pipe0[0]);
2464                     close(pipe0[1]);
2465                     close(pipe1[0]);
2466                     close(pipe1[1]);
2467                     perror("Fork error");
2468                     return(-1);
2469                   case 0:               /* Child. */
2470                     close(pipe0[0]);
2471                     close(pipe1[1]);
2472                     dup2(pipe0[1], 1);
2473                     close(pipe0[1]);
2474                     dup2(pipe1[0], 0);
2475                     close(pipe1[0]);
2476                     system(ttname);
2477                     _exit(0);
2478                   default:              /* Parent */
2479                     close(pipe0[1]);
2480                     close(pipe1[0]);
2481                     fdin = pipe0[0];    /* Read from pipe */
2482                     fdout = pipe1[1];   /* Write to pipe */
2483                     ttout = fdopen(fdout,"w"); /* Get stream so we can */
2484                     if (!ttout) {       /* make it unbuffered. */
2485                         perror("fdopen failure");
2486                         return(-1);
2487                     }
2488                     setbuf(ttout,NULL);
2489                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2490                     xlocal = *lcl = 1;  /* It's local */
2491                     netconn = 1;        /* Call it a network connection */
2492                     ttmdm = modem;      /* Remember network type */
2493                     ttyfd = fdin;
2494                     ttpipe = 1;
2495                     gotsigs = 0;
2496                     return(0);
2497                 }
2498             }
2499 #endif /* NETCMD */
2500 #endif /* NAMEFD */
2501             x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
2502             if (x > -1) {
2503                 ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2504             } else netconn = 0;
2505 #ifdef NAMEFD
2506         }
2507 #endif /* NAMEFD */
2508
2509 #ifdef sony_news                        /* Sony NEWS */
2510         if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
2511             perror("ttopen error getting Kanji mode (network)");
2512             debug(F111,"ttopen error getting Kanji mode","network",0);
2513             km_ext = -1;                /* Make sure this stays undefined. */
2514         }
2515 #endif /* sony_news */
2516
2517         xlocal = *lcl = 1;              /* Network connections are local. */
2518         debug(F101,"ttopen net x","",x);
2519 #ifdef COMMENT
2520 /* Let netopen() do this */
2521         if (x > -1 && !x25fd)
2522           x = tn_ini();                 /* Initialize TELNET protocol */
2523 #endif /* COMMENT */
2524         gotsigs = 0;
2525         return(x);
2526     } else {                            /* Terminal device */
2527 #endif  /* NETCONN */
2528
2529 #ifdef NAMEFD
2530 /*
2531   This code lets you give Kermit an open file descriptor for a serial
2532   communication device, rather than a device name.  Kermit assumes that the
2533   line is already open, locked, conditioned with the right parameters, etc.
2534 */
2535         for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
2536         if (*p == '\0') {
2537             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2538             debug(F111,"ttopen got open fd",ttname,ttyfd);
2539             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2540             if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
2541               xlocal = *lcl = 0;        /* we're in remote mode */
2542             else                        /* otherwise */
2543               xlocal = *lcl = 1;        /* local mode. */
2544             netconn = 0;                /* Assume it's not a network. */
2545             tvtflg = 0;                 /* Might need to initialize modes. */
2546             ttmdm = modem;              /* Remember modem type. */
2547             fdflag = 0;                 /* Stdio not redirected. */
2548             ttfdflg = 1;                /* Flag we were opened this way. */
2549             debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
2550             debug(F101,"ttopen non-net ttyfd","",ttyfd);
2551
2552 #ifdef sony_news                        /* Sony NEWS */
2553             /* Get device Kanji mode */
2554             if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
2555                 perror("ttopen error getting Kanji mode");
2556                 debug(F101,"ttopen error getting Kanji mode","",0);
2557                 km_ext = -1;            /* Make sure this stays undefined. */
2558             }
2559 #endif /* sony_news */
2560             gotsigs = 0;
2561             return(0);                  /* Return success */
2562         }
2563 #endif /* NAMEFD */
2564 #ifdef NETCONN
2565     }
2566 #endif /* NETCONN */
2567
2568 /* Here we have to open a serial device of the given name. */
2569
2570     netconn = 0;                        /* So it's not a network connection */
2571     occt = signal(SIGINT, cctrap);      /* Set Control-C trap, save old one */
2572     sigint_ign = 0;
2573
2574     tvtflg = 0;                 /* Flag for use by ttvt(). */
2575                                 /* 0 = ttvt not called yet for this device */
2576
2577     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
2578     debug(F101,"ttopen fdflag","",fdflag);
2579
2580     ttmdm = modem;                      /* Make this available to other fns */
2581     xlocal = *lcl;                      /* Make this available to other fns */
2582
2583 /* Code for handling bidirectional tty lines goes here. */
2584 /* Use specified method for turning off logins and suppressing getty. */
2585
2586 #ifdef ACUCNTRL
2587     /* Should put call to priv_on() here, but that would be very risky! */
2588     acucntrl("disable",ttname);         /* acucntrl() program. */
2589     /* and priv_off() here... */
2590 #else
2591 #ifdef ATT7300
2592     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
2593       attmodem |= offgetty(ttname);     /* Remember response.  */
2594 #endif /* ATT7300 */
2595 #endif /* ACUCNTRL */
2596
2597 #ifdef OPENFIRST
2598 /*
2599  1985-2001: opens device first then gets lock; reason:
2600  Kermit usually has to run setuid or setgid in order to create a lockfile.
2601  If you give a SET LINE command for a device that happens to be your job's
2602  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
2603  should not create one, and would fail if it tried to if it did not have the
2604  required privileges.  But you can't find out if two tty device names are
2605  equivalent until you have a file descriptor that you can give to ttyname().
2606  But this can cause a race condition between Kermit and [m]getty.  So see
2607  the [#]else part...
2608 */ 
2609
2610 /*
2611  In the following section, we open the tty device for read/write.
2612  If a modem has been specified via "set modem" prior to "set line"
2613  then the O_NDELAY parameter is used in the open, provided this symbol
2614  is defined (e.g. in fcntl.h), so that the program does not hang waiting
2615  for carrier (which in most cases won't be present because a connection
2616  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
2617  would make more sense to first determine if the line is local before
2618  doing this, but because ttyname() requires a file descriptor, we have
2619  to open it first.  See do_open().
2620
2621  Now open the device using the desired treatment of carrier.
2622  If carrier is REQUIRED, then open could hang forever, so an optional
2623  timer is provided.  If carrier is not required, the timer should never
2624  go off, and should do no harm...
2625 */
2626     ttotmo = 0;                         /* Flag no timeout */
2627     debug(F101,"ttopen timo","",timo);
2628     debug(F101,"ttopen xlocal","",xlocal);
2629     if (timo > 0) {
2630         int xx;
2631         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2632         xx = alarm(timo);               /* Timed open() */
2633         debug(F101,"ttopen alarm","",xx);
2634         if (
2635 #ifdef CK_POSIX_SIG
2636             sigsetjmp(sjbuf,1)
2637 #else
2638             setjmp(sjbuf)
2639 #endif /* CK_POSIX_SIG */
2640             ) {
2641             ttotmo = 1;                 /* Flag timeout. */
2642         } else ttyfd = do_open(ttname);
2643         ttimoff();
2644         debug(F111,"ttopen","modem",modem);
2645         debug(F101,"ttopen ttyfd","",ttyfd);
2646         debug(F101,"ttopen alarm return","",ttotmo);
2647     } else {
2648         errno = 0;
2649         ttyfd = do_open(ttname);
2650     }
2651     debug(F111,"ttopen ttyfd",ttname,ttyfd);
2652     if (ttyfd < 0) {                    /* If couldn't open, fail. */
2653         debug(F101,"ttopen errno","",errno);
2654         if (errno > 0 && !quiet)
2655           perror(ttname);               /* Print message */
2656
2657 #ifdef ATT7300
2658         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
2659           ongetty(ttnmsv);              /* yes, restart on tty line */
2660         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
2661 #else
2662 #ifdef ACUCNTRL
2663         /* Should put call to priv_on() here, but that would be risky! */
2664         acucntrl("enable",ttname);      /* acucntrl() program. */
2665         /* and priv_off() here... */
2666 #endif /* ACUNTRL */
2667 #endif /* ATT7300 */
2668
2669         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
2670         if (errno == EACCES) {          /* Device is protected against user */
2671             debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
2672             return(-4);
2673         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2674     }
2675
2676 #ifdef QNX
2677     {
2678         extern int qnxportlock;
2679         x = qnxopencount();
2680         debug(F101,"ttopen qnxopencount","",x);
2681         debug(F101,"ttopen qnxportlock","",qnxportlock);
2682         if (x < 0 && qnxportlock) {
2683             ttclos(0);
2684             printf("?Can't get port open count\n");
2685             printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
2686             return(-1);                 /* Indicate device is in use */
2687         }
2688         if (x > 1) {                    /* 1 == me */
2689             if (qnxportlock)
2690               ttclos(0);
2691               return(-2);               /* Indicate device is in use */
2692             else if (!quiet)
2693               printf("WARNING: \"%s\" looks busy...\n",ttdev);
2694         }
2695     }
2696 #endif /* QNX */
2697
2698 #ifdef Plan9
2699     /* take this opportunity to open the control channel */
2700     if (p9openttyctl(ttname) < 0)
2701 #else
2702     /* Make sure it's a real tty. */
2703     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
2704 #endif /* Plan9 */
2705       {
2706         fprintf(stderr,"%s is not a terminal device\n",ttname);
2707         debug(F111,"ttopen not a tty",ttname,errno);
2708         close(ttyfd);
2709         ttyfd = -1;
2710         wasclosed = 1;
2711         signal(SIGINT,occt);
2712         return(-1);
2713     }
2714
2715 #ifdef aegis
2716         /* Apollo C runtime claims that console pads are tty devices, which
2717          * is reasonable, but they aren't any good for packet transfer. */
2718         ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2719         if (st.all != status_$ok) {
2720             fprintf(stderr, "problem getting tty object type: ");
2721             error_$print(st);
2722         } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
2723             close(ttyfd); ttyfd = -1;
2724             wasclosed = 1;
2725             errno = ENOTTY; perror(ttname);
2726             signal(SIGINT,occt);
2727             return(-1);
2728         }
2729 #endif /* aegis */
2730
2731     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2732
2733     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
2734
2735 /* Caller wants us to figure out if line is controlling tty */
2736
2737     if (*lcl < 0) {
2738         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
2739             xlocal = 0;
2740             debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
2741         } else if (strcmp(ttname,cttnam) == 0) {
2742             xlocal = 0;
2743             debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
2744         } else if (cttnam[0]) {
2745 #ifdef BEBOX_DR7
2746             x = ttnmsv;                 /* ttyname() is broken */
2747 #else
2748             x = ttyname(ttyfd);         /* Get real name of ttname. */
2749 #endif /* BEBOX_DR7 */
2750             if (!x) x = "";
2751             if (*x)
2752               xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
2753             else
2754               xlocal = 1;
2755             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
2756         }
2757     }
2758
2759 #ifndef NOFDZERO
2760 /* Note, the following code was added so that Unix "idle-line" snoopers */
2761 /* would not think Kermit was idle when it was transferring files, and */
2762 /* maybe log people out. */
2763     if (xlocal == 0) {                  /* Remote mode */
2764         if (fdflag == 0) {              /* Standard i/o is not redirected */
2765             debug(F100,"ttopen setting ttyfd = 0","",0);
2766 #ifdef LYNXOS
2767             /* On Lynx OS, fd 0 is open for read only. */
2768             dup2(ttyfd,0);
2769 #endif /* LYNXOS */
2770             close(ttyfd);               /* Use file descriptor 0 */
2771             ttyfd = 0;
2772         } else {                        /* Standard i/o is redirected */
2773             debug(F101,"ttopen stdio redirected","",ttyfd);
2774         }
2775     }
2776 #endif /* NOFDZERO */
2777
2778 /* Now check if line is locked -- if so fail, else lock for ourselves */
2779 /* Note: After having done this, don't forget to delete the lock if you */
2780 /* leave ttopen() with an error condition. */
2781
2782     lkf = 0;                            /* Check lock */
2783     if (xlocal > 0) {
2784         int xx; int xpid;
2785         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
2786             debug(F111,"ttopen ttlock fails",ttname,xx);
2787             /* WARNING - This close() can hang if tty is an empty socket... */
2788             close(ttyfd);               /* Close the device. */
2789             ttyfd = -1;                 /* Erase its file descriptor. */
2790             wasclosed = 1;
2791             signal(SIGINT,occt);        /* Put old SIGINT back. */
2792             sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2793             if (xx == -2) {             /* If lockfile says device in use, */
2794 #ifndef NOUUCP
2795                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2796                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2797                 if (xpid > -1) {        /* If we got a pid */
2798                     if (!quiet)
2799                       printf("Locked by process %d\n",xpid); /* tell them. */
2800                     sprintf(lockpid,"%d",xpid); /* Record it too */
2801                     debug(F110,"ttopen lockpid",lockpid,0);
2802                 } else if (*flfnam) {
2803                     extern char *DIRCMD;
2804                     char *p = NULL;
2805                     int x;
2806                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2807                     p = malloc(x);      /* Print a directory listing. */
2808 /*
2809   Note: priv_on() won't help here, because we do not pass privs along to
2810   to inferior processes, in this case ls.  So if the real user does not have
2811   directory-listing access to the lockfile directory, this will result in
2812   something like "not found".  That's why we try this only as a last resort.
2813 */
2814                     if (p) {            /* If we got the space... */
2815                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2816                         zsyscmd(p);     /* Get listing. */
2817                         if (p) {        /* free the space */
2818                             free(p);
2819                             p = NULL;
2820                         }
2821                     }
2822                 }
2823 #endif /* NOUUCP */
2824                 return(-5);             /* Code for device in use */
2825             } else return(-3);          /* Access denied */
2826         } else lkf = 1;
2827     }
2828 #else  /* OPENFIRST */
2829
2830 /*
2831   27 Oct 2001: New simpler code that gets the lock first and then opens the
2832   device, which eliminates the race condition.  The downside is you can no
2833   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
2834   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
2835   privs, and if it succeeds, it has created a lockfile where it didn't create
2836   one before.
2837 */
2838     xlocal = *lcl;                      /* Is the device my login terminal? */
2839     debug(F111,"ttopen xlocal","A",xlocal);
2840     fnam = ttname;
2841     if (strcmp(ttname,CTTNAM) && netconn == 0) {
2842         if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
2843             if ((int)strlen(fullname) > 0)
2844               fnam = fullname;
2845         }
2846     }
2847     debug(F110,"ttopen fnam",fnam,0);
2848     if (xlocal < 0) {
2849         xlocal = (strcmp(fnam,CTTNAM) != 0);
2850     }
2851     debug(F111,"ttopen xlocal","B",xlocal);
2852
2853     lkf = 0;                            /* No lock yet */
2854     if (xlocal > 0) {                   /* If not... */
2855         int xx; int xpid;
2856         xx = ttlock(fnam);              /* Try to lock it. */
2857         debug(F101,"ttopen ttlock","",xx);
2858         if (xx < 0) {                   /* Can't lock it. */
2859             debug(F111,"ttopen ttlock fails",fnam,xx);
2860             if (xx == -2) {             /* If lockfile says device in use, */
2861 #ifndef NOUUCP
2862                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2863                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2864                 if (xpid > -1) {        /* If we got a pid */
2865                     if (!quiet)
2866                       printf("Locked by process %d\n",xpid); /* tell them. */
2867                     ckstrncpy(lockpid,ckitoa(xpid),16);
2868                     debug(F110,"ttopen lockpid",lockpid,0);
2869 #ifndef NOPUSH
2870                 } else if (flfnam[0] && !nopush) {
2871                     extern char *DIRCMD;
2872                     char *p = NULL;
2873                     int x;
2874                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2875                     p = malloc(x);      /* Print a directory listing. */
2876 /*
2877   Note: priv_on() won't help here, because we do not pass privs along to
2878   to inferior processes, in this case ls.  So if the real user does not have
2879   directory-listing access to the lockfile directory, this will result in
2880   something like "not found".  That's why we try this only as a last resort.
2881 */
2882                     if (p) {            /* If we got the space... */
2883                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2884                         zsyscmd(p);     /* Get listing. */
2885                         if (p) {        /* free the space */
2886                             free(p);
2887                             p = NULL;
2888                         }
2889                     }
2890 #endif /* NOPUSH */
2891                 }
2892 #endif /* NOUUCP */
2893                 return(-5);             /* Code for device in use */
2894             } else return(-3);          /* Access denied */
2895         } else lkf = 1;
2896     }
2897     /* Have lock -- now it's safe to open the device */
2898
2899     debug(F101,"ttopen lkf","",lkf);
2900     debug(F101,"ttopen timo","",timo);
2901
2902     ttotmo = 0;                         /* Flag no timeout */
2903     if (timo > 0) {
2904         int xx;
2905         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2906         xx = alarm(timo);               /* Timed open() */
2907         debug(F101,"ttopen alarm","",xx);
2908         if (
2909 #ifdef CK_POSIX_SIG
2910             sigsetjmp(sjbuf,1)
2911 #else
2912             setjmp(sjbuf)
2913 #endif /* CK_POSIX_SIG */
2914             ) {
2915             ttotmo = 1;                 /* Flag timeout. */
2916         } else {
2917             ttyfd = do_open(fnam);
2918         }
2919         ttimoff();
2920         debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
2921     } else {
2922         errno = 0;
2923         ttyfd = do_open(fnam);
2924         debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
2925     }
2926     if (ttyfd < 0) {                    /* If couldn't open, fail. */
2927         debug(F111,"ttopen errno",fnam,errno);
2928         debug(F111,"ttopen xlocal","C",xlocal);
2929         if (xlocal == 0) {
2930             debug(F100,"ttopen substituting 0","",0);
2931             ttyfd = 0;
2932         } else {
2933             if (errno > 0 && !quiet) {
2934                 debug(F111,"ttopen perror",fnam,errno);
2935                 perror(fnam);           /* Print message */
2936             }
2937             if (ttunlck())                  /* Release the lock file */
2938               fprintf(stderr,"Warning, problem releasing lock\r\n");
2939         }
2940     }
2941
2942     if (ttyfd < 0) {                    /* ttyfd is still < 0? */
2943 #ifdef ATT7300
2944         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
2945           ongetty(ttnmsv);              /* yes, restart on tty line */
2946         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
2947 #else
2948 #ifdef ACUCNTRL
2949         /* Should put call to priv_on() here, but that would be risky! */
2950         acucntrl("enable",fnam);        /* acucntrl() program. */
2951         /* and priv_off() here... */
2952 #endif /* ACUNTRL */
2953 #endif /* ATT7300 */
2954
2955         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
2956         if (errno == EACCES) {          /* Device is protected against user */
2957             debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
2958             return(-4);
2959         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2960     }
2961
2962 /* Make sure it's a real tty. */
2963
2964 #ifdef Plan9
2965     /* take this opportunity to open the control channel */
2966     if (p9openttyctl(fnam) < 0)       
2967 #else
2968       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
2969 #endif /* Plan9 */
2970         {
2971             fprintf(stderr,"%s is not a terminal device\n",fnam);
2972             debug(F111,"ttopen not a tty",fnam,errno);
2973             if (ttunlck())              /* Release the lock file */
2974               fprintf(stderr,"Warning, problem releasing lock\r\n");
2975             close(ttyfd);
2976             ttyfd = -1;
2977             wasclosed = 1;
2978             signal(SIGINT,occt);
2979             return(-1);
2980         }
2981
2982 #ifdef aegis
2983     /*
2984       Apollo C runtime claims that console pads are tty devices, which
2985       is reasonable, but they aren't any good for packet transfer.
2986     */
2987     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2988     if (st.all != status_$ok) {
2989         fprintf(stderr, "problem getting tty object type: ");
2990         error_$print(st);
2991     } else if (ttyuid != sio_$uid) {    /* Reject non-SIO lines */
2992         close(ttyfd); ttyfd = -1;
2993         wasclosed = 1;
2994         errno = ENOTTY; perror(fnam);
2995         signal(SIGINT,occt);
2996         return(-1);
2997     }
2998 #endif /* aegis */
2999
3000     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3001
3002     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
3003
3004 /* Caller wants us to figure out if line is controlling tty */
3005
3006     if (*lcl < 0) {
3007         char * s;
3008         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
3009             xlocal = 0;
3010             debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
3011         } else if (strcmp(fnam,cttnam) == 0) {
3012             xlocal = 0;
3013             debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
3014         } else if (cttnam[0]) {
3015 #ifdef BEBOX_DR7
3016             s = ttnmsv;                 /* ttyname() is broken */
3017 #else
3018             s = ttyname(ttyfd);         /* Get real name of ttname. */
3019 #endif /* BEBOX_DR7 */
3020             if (!s) s = "";
3021             if (*s)
3022               xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
3023             else
3024               xlocal = 1;
3025             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
3026         }
3027     }
3028
3029 #ifndef NOFDZERO
3030 /* Note, the following code was added so that Unix "idle-line" snoopers */
3031 /* would not think Kermit was idle when it was transferring files, and */
3032 /* maybe log people out. */
3033     if (xlocal == 0) {                  /* Remote mode */
3034         if (fdflag == 0) {              /* Standard i/o is not redirected */
3035             debug(F100,"ttopen setting ttyfd = 0","",0);
3036 #ifdef LYNXOS
3037             /* On Lynx OS, fd 0 is open for read only. */
3038             dup2(ttyfd,0);
3039 #endif /* LYNXOS */
3040             close(ttyfd);               /* Use file descriptor 0 */
3041             ttyfd = 0;
3042         } else {                        /* Standard i/o is redirected */
3043             debug(F101,"ttopen stdio redirected","",ttyfd);
3044         }
3045     }
3046 #endif /* NOFDZERO */
3047 #endif /* OPENFIRST */
3048
3049 /* Got the line, now set the desired value for local. */
3050
3051     if (*lcl != 0) *lcl = xlocal;
3052
3053 /* Some special stuff for v7... */
3054
3055 #ifdef  V7
3056 #ifndef MINIX
3057     if (kmem[TTY] < 0) {                /*  If open, then skip this.  */
3058         qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
3059         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
3060             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
3061             perror("/dev/kmem");
3062             exit(1);
3063         }
3064     }
3065 #endif /* !MINIX */
3066 #endif /* V7 */
3067
3068 /* No failure returns after this point */
3069
3070 #ifdef ultrix
3071     ioctl(ttyfd, TIOCMODEM, &temp);
3072 #ifdef TIOCSINUSE
3073     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
3074         if (!quiet)
3075           perror(fnam);
3076     }
3077 #endif /* TIOCSINUSE */
3078 #endif /* ultrix */
3079
3080 /* Get tty device settings  */
3081
3082 #ifdef BSD44ORPOSIX                     /* POSIX */
3083     tcgetattr(ttyfd,&ttold);
3084     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
3085     tcgetattr(ttyfd,&ttraw);
3086     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
3087     tcgetattr(ttyfd,&tttvt);
3088     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
3089 #else                                   /* BSD, V7, and all others */
3090 #ifdef ATTSV                            /* AT&T UNIX */
3091     ioctl(ttyfd,TCGETA,&ttold);
3092     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
3093     ioctl(ttyfd,TCGETA,&ttraw);
3094     ioctl(ttyfd,TCGETA,&tttvt);
3095 #else
3096 #ifdef BELLV10
3097     ioctl(ttyfd,TIOCGETP,&ttold);
3098     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
3099     ioctl(ttyfd,TIOCGDEV,&tdold);
3100     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
3101 #else
3102     gtty(ttyfd,&ttold);
3103     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
3104 #endif /* BELLV10 */
3105
3106 #ifdef sony_news                        /* Sony NEWS */
3107     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
3108         perror("ttopen error getting Kanji mode");
3109         debug(F101,"ttopen error getting Kanji mode","",0);
3110         km_ext = -1;                    /* Make sure this stays undefined. */
3111     }
3112 #endif /* sony_news */
3113
3114 #ifdef TIOCGETC
3115     debug(F100,"ttopen TIOCGETC","",0);
3116     tcharf = 0;                         /* In remote mode, also get */
3117     if (xlocal == 0) {                  /* special characters */
3118         if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
3119             debug(F100,"ttopen TIOCGETC failed","",0);
3120         } else {
3121             tcharf = 1;                 /* It worked. */
3122             ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
3123             debug(F100,"ttopen TIOCGETC ok","",0);
3124         }
3125     }
3126 #else
3127     debug(F100,"ttopen TIOCGETC not defined","",0);
3128 #endif /* TIOCGETC */
3129
3130 #ifdef TIOCGLTC
3131     debug(F100,"ttopen TIOCGLTC","",0);
3132     ltcharf = 0;                        /* In remote mode, also get */
3133     if (xlocal == 0) {                  /* local special characters */
3134         if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
3135             debug(F100,"ttopen TIOCGLTC failed","",0);
3136         } else {
3137             ltcharf = 1;                /* It worked. */
3138             ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
3139             debug(F100,"ttopen TIOCGLTC ok","",0);
3140         }
3141     }
3142 #else
3143     debug(F100,"ttopen TIOCGLTC not defined","",0);
3144 #endif /* TIOCGLTC */
3145
3146 #ifdef TIOCLGET
3147     debug(F100,"ttopen TIOCLGET","",0);
3148     lmodef = 0;
3149     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
3150         debug(F100,"ttopen TIOCLGET failed","",0);
3151     } else {
3152         lmodef = 1;
3153         debug(F100,"ttopen TIOCLGET ok","",0);
3154     }
3155 #endif /* TIOCLGET */
3156
3157 #ifdef BELLV10
3158     ioctl(ttyfd,TIOCGETP,&ttraw);
3159     ioctl(ttyfd,TIOCGETP,&tttvt);
3160 #else
3161     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
3162     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
3163 #endif /* BELLV10 */
3164
3165 #endif /* ATTSV */
3166 #endif /* BSD44ORPOSIX */
3167
3168 /* Section for changing line discipline.  It's restored in ttres(). */
3169
3170 #ifdef AIXRS
3171 #ifndef AIX41
3172     { union txname ld_name; int ld_idx = 0;
3173       ttld = 0;
3174         do {
3175           ld_name.tx_which = ld_idx++;
3176           ioctl(ttyfd, TXGETCD, &ld_name);
3177           if (!strncmp(ld_name.tx_name, "rts", 3))
3178             ttld |= 1;
3179         } while (*ld_name.tx_name);
3180         debug(F101,"AIX line discipline","",ttld);
3181       }
3182 #endif /* AIX41 */
3183 #endif /* AIXRS */
3184
3185 #ifdef BSD41
3186 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
3187     { int k;
3188       ioctl(ttyfd, TIOCGETD, &ttld);    /* Get and save line discipline */
3189       debug(F101,"4.1bsd line discipline","",ttld);
3190       k = OTTYDISC;                     /* Switch to "old" discipline */
3191       k = ioctl(ttyfd, TIOCSETD, &k);
3192       debug(F101,"4.1bsd tiocsetd","",k);
3193     }
3194 #endif /* BSD41 */
3195
3196 #ifdef aegis
3197     /* This was previously done before the last two TCGETA or gtty above,
3198      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
3199      * one copy if it here instead, give us a shout!
3200      */
3201     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
3202     if (xlocal) {       /* ignore breaks from local line */
3203         sio_$control((short)ttyfd, sio_$int_enable, false, st);
3204         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
3205     }
3206 #endif /* aegis */
3207
3208 #ifdef VXVE
3209     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
3210     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
3211     ioctl(ttyfd,TCSETA,&ttraw);
3212 #endif /* vxve */
3213
3214 /* If O_NDELAY was used during open(), then remove it now. */
3215
3216 #ifdef O_NDELAY
3217     debug(F100,"ttopen O_NDELAY","",0);
3218     if (xlocal > 0) {
3219       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
3220         debug(F100,"ttopen fcntl O_NDELAY","",0);
3221 #ifndef aegis
3222         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
3223             debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
3224             perror("Can't unset O_NDELAY");
3225         }
3226 #endif /* aegis */
3227         /* Some systems, notably Xenix (don't know how common this is in
3228          * other systems), need special treatment to get rid of the O_NDELAY
3229          * behaviour on read() with respect to carrier presence (i.e. read()
3230          * returning 0 when carrier absent), even though the above fcntl()
3231          * is enough to make read() wait for input when carrier is present.
3232          * This magic, in turn, requires CLOCAL for working when the carrier
3233          * is absent. But if xlocal == 0, presumably you already have CLOCAL
3234          * or you have a carrier, otherwise you wouldn't be running this.
3235          */
3236         debug(F101,"ttopen xlocal","",xlocal);
3237 #ifdef ATTSV
3238 #ifdef BSD44ORPOSIX
3239 #ifdef COMMENT                          /* 12 Aug 1997 */
3240 #ifdef __bsdi__
3241         if (xlocal)
3242           ttraw.c_cflag |= CLOCAL;
3243 #else
3244 #ifdef __FreeBSD__
3245         if (xlocal)
3246           ttraw.c_cflag |= CLOCAL;
3247 #endif /* __FreeBSD__ */
3248 #endif /* __bsdi__ */
3249 #else /* Not COMMENT */
3250 #ifdef CLOCAL
3251         if (xlocal)                     /* Unset this if it's defined. */
3252           ttraw.c_cflag |= CLOCAL;
3253 #endif /* CLOCAL */
3254 #endif /* COMMENT */
3255         debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
3256         if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
3257             debug(F100,"ttopen POSIX tcseattr fails","",0);
3258             perror("tcsetattr");
3259         }
3260 #else /* !BSD44ORPOSIX */
3261         if (xlocal) {
3262             ttraw.c_cflag |= CLOCAL;
3263             debug(F100,"ttopen calling ioctl(TCSETA)","",0);
3264             errno = 0;
3265             if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
3266                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
3267                 perror("ioctl(TCSETA)");
3268             }
3269         }
3270 #endif /* BSD44ORPOSIX */
3271 #endif /* ATTSV */
3272 #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
3273 /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
3274         debug(F100,"ttopen executing close/open","",0);
3275         close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
3276 #endif /* NOCOTFMC */
3277       }
3278     }
3279 #endif /* O_NDELAY */
3280
3281 /* Instruct the system how to treat the carrier, and set a few other tty
3282  * parameters.
3283  *
3284  * This also undoes the temporary setting of CLOCAL that may have been done
3285  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
3286  * prevent the other end of the line from sitting there talking to itself,
3287  * producing garbage when the user performs a connect.
3288  *
3289  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
3290  * Now it thinks CLOCAL is always on. It seems the only real solution for
3291  * Xenix is to switch between the lower and upper case device names.
3292  *
3293  * This section may at some future time expand into setting a complete
3294  * collection of tty parameters, or call a function shared with ttpkt()/
3295  * ttvt() that does so.  On the other hand, the initial parameters are not
3296  * that important, since ttpkt() or ttvt() should always fix that before
3297  * any communication is done.  Well, we'll see...
3298  */
3299     if (xlocal) {
3300         curcarr = -2;
3301         debug(F100,"ttopen calling carrctl","",0);
3302         carrctl(&ttraw, ttcarr == CAR_ON);
3303         debug(F100,"ttopen carrctl ok","",0);
3304
3305 #ifdef COHERENT
3306 #define SVORPOSIX
3307 #endif /* COHERENT */
3308
3309 #ifdef SVORPOSIX
3310         ttraw.c_lflag &= ~ECHO;
3311         ttold.c_lflag &= ~ECHO;
3312 #ifdef BSD44ORPOSIX
3313         y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
3314         debug(F101,"ttopen tcsetattr","",y);
3315 #else
3316         y = ioctl(ttyfd, TCSETA, &ttraw);
3317         debug(F100,"ttopen ioctl","",y);
3318 #endif /* BSD44ORPOSIX */
3319
3320 #else /* BSD, etc */
3321         ttraw.sg_flags &= ~ECHO;
3322         ttold.sg_flags &= ~ECHO;
3323 #ifdef BELLV10
3324         y = ioctl(ttyfd,TIOCSETP,&ttraw);
3325         debug(F100,"ttopen ioctl","",y);
3326 #else
3327         y = stty(ttyfd,&ttraw);
3328         debug(F100,"ttopen stty","",y);
3329 #endif /* BELLV10 */
3330 #endif /* SVORPOSIX */
3331
3332 #ifdef COHERENT
3333 #undef SVORPOSIX
3334 #endif /* COHERENT */
3335
3336         /* ttflui(); */  /*  This fails for some reason.  */
3337     }
3338
3339     /* Get current speed */
3340
3341 #ifndef BEBOX
3342     ttspeed = ttgspd();
3343 #else
3344     ttspeed = 19200;
3345 #endif /* !BEBOX */
3346     debug(F101,"ttopen ttspeed","",ttspeed);
3347
3348     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
3349
3350     debug(F101,"ttopen ttyfd","",ttyfd);
3351     debug(F101,"ttopen *lcl","",*lcl);
3352     debug(F111,"ttopen lock file",flfnam,lkf);
3353     signal(SIGINT,occt);
3354     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3355     gotsigs = 0;
3356     return(0);
3357 }
3358
3359
3360 /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
3361
3362 int
3363 do_open(ttname) char *ttname; {
3364     int flags;
3365
3366 #ifdef QNX6
3367     /* O_NONBLOCK on /dev/tty makes open() fail */
3368     return(priv_opn(ttname, O_RDWR |
3369                     (
3370                      ((int)strcmp(ttname,"/dev/tty") == 0) ?
3371                      0 :
3372                      (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
3373                     )
3374            ); 
3375 #else  /* !QNX6 */
3376
3377 #ifndef O_NDELAY                        /* O_NDELAY not defined */
3378     return(priv_opn(ttname,2));
3379 #else                                   /* O_NDELAY defined */
3380
3381 #ifdef ATT7300
3382 /*
3383  Open comms line without waiting for carrier so initial call does not hang
3384  because state of "modem" is likely unknown at the initial call  -jrd.
3385  If this is needed for the getty stuff to work, and the open would not work
3386  without O_NDELAY when getty is still on, then this special case is ok.
3387  Otherwise, get rid of it. -ske
3388 */
3389     return(priv_opn(ttname, O_RDWR | O_NDELAY));
3390
3391 #else   /* !ATT7300 */
3392
3393     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
3394     flags = O_RDWR;
3395     debug(F101,"do_open xlocal","",xlocal);
3396     debug(F111,"do_open flags A",ttname,flags);
3397     if (xlocal && (ttcarr != CAR_ON))
3398       flags |= O_NDELAY;
3399     debug(F111,"do_open flags B",ttname,flags);
3400     return(priv_opn(ttname, flags));
3401 #endif /* !ATT7300 */
3402 #endif /* O_NDELAY */
3403 #endif /* QNX6 */
3404 }
3405
3406 /*  T T C L O S  --  Close the TTY, releasing any lock.  */
3407
3408 static int ttc_state = 0;               /* ttclose() state */
3409 static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
3410
3411 int
3412 ttclos(foo) int foo; {                  /* Arg req'd for signal() prototype */
3413     int xx, x = 0;
3414     extern int exithangup;
3415
3416     debug(F101,"ttclos ttyfd","",ttyfd);
3417     debug(F101,"ttclos netconn","",netconn);
3418     debug(F101,"ttclos xlocal","",xlocal);
3419 #ifdef NOFDZERO
3420     debug(F100,"ttclos NOFDZERO","",0);
3421 #endif /* NOFDZERO */
3422
3423 #ifdef COMMENT
3424 #ifdef TTLEBUF
3425     le_init();                          /* No need for any of this */
3426 #endif /* TTLEBUF */
3427 #endif /* COMMENT */
3428
3429     if (ttyfd < 0)                      /* Wasn't open. */
3430       return(0);
3431
3432     if (ttfdflg)                        /* If we inherited ttyfd from */
3433       return(0);                        /* another process, don't close it. */
3434
3435     tvtflg = 0;                         /* (some day get rid of this...) */
3436     gotsigs = 0;
3437
3438 #ifdef IKSD
3439     if (inserver) {
3440 #ifdef TNCODE
3441           tn_push();                    /* Place any waiting data into input*/
3442           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
3443           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
3444           tn_reset();                   /* The Reset Telnet Option table.  */
3445 #endif /* TNCODE */
3446 #ifdef CK_SSL
3447           if (ssl_active_flag) {
3448               if (ssl_debug_flag)
3449                 BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
3450               SSL_shutdown(ssl_con);
3451               SSL_free(ssl_con);
3452               ssl_con = NULL;
3453               ssl_active_flag = 0;
3454           }
3455           if (tls_active_flag) {
3456               if (ssl_debug_flag)
3457                 BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
3458               SSL_shutdown(tls_con);
3459               SSL_free(tls_con);
3460               tls_con = NULL;
3461               tls_active_flag = 0;
3462           }
3463 #endif /* CK_SSL */
3464     }
3465 #endif /* IKSD */
3466 #ifdef NETCMD
3467     if (ttpipe) {                       /* We've been using a pipe */
3468         /* ttpipe = 0; */
3469         if (ttpid > 0) {
3470             int wstat;
3471             int statusp;
3472             close(fdin);                /* Close these. */
3473             close(fdout);
3474             fdin = fdout = -1;
3475             kill(ttpid,1);              /* Kill fork with SIGHUP */
3476             while (1) {
3477                 wstat = wait(&statusp);
3478                 if (wstat == ttpid || wstat == -1)
3479                   break;
3480                 pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
3481             }
3482             ttpid = 0;
3483         }
3484         netconn = 0;
3485         wasclosed = 1;
3486         ttyfd = -1;
3487         return(0);
3488     }
3489 #endif /* NETCMD */
3490 #ifdef NETPTY
3491     if (ttpty) {
3492 #ifndef NODOPTY
3493         end_pty();
3494 #endif /* NODOPTY */
3495         close(ttyfd);
3496         netconn = 0;
3497         wasclosed = 1;
3498         ttpty = 0;
3499         ttyfd = -1;
3500         return(0);
3501     }
3502 #endif /* NETPTY */
3503
3504 #ifdef  NETCONN
3505     if (netconn) {                      /* If it's a network connection. */
3506         debug(F100,"ttclos closing net","",0);
3507         netclos();                      /* Let the network module close it. */
3508         netconn = 0;                    /* No more network connection. */
3509         debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
3510         return(0);
3511     }
3512 #endif  /* NETCONN */
3513
3514     if (xlocal) {                       /* We're closing a SET LINE device */
3515 #ifdef FT21                             /* Fortune 2.1-specific items ... */
3516         ioctl(ttyfd,TIOCHPCL, NULL);
3517 #endif /* FT21 */
3518 #ifdef ultrix                           /* Ultrix-specific items ... */
3519 #ifdef TIOCSINUSE
3520         /* Unset the INUSE flag that we set in ttopen() */
3521         ioctl(ttyfd, TIOCSINUSE, NULL);
3522 #endif /* TIOCSINUSE */
3523         ioctl(ttyfd, TIOCNMODEM, &x);
3524 #ifdef COMMENT
3525         /* What was this? */
3526         ioctl(ttyfd, TIOCNCAR, NULL);
3527 #endif /* COMMENT */
3528 #endif /* ultrix */
3529     }
3530
3531     /* This is to prevent us from sticking in tthang() or close(). */
3532
3533 #ifdef O_NDELAY
3534 #ifndef aegis
3535     if (ttyfd > 0) {                    /* But skip it on stdin. */
3536         debug(F100,"ttclos setting O_NDELAY","",0);
3537         x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
3538 #ifdef DEBUG
3539         if (deblog && x == -1) {
3540             perror("Warning - Can't set O_NDELAY");
3541             debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
3542         }
3543 #endif /* DEBUG */
3544     }
3545 #endif /* aegis */
3546 #endif /* O_NDELAY */
3547
3548     x = 0;
3549     ttc_state = 0;
3550     if (xlocal
3551 #ifdef NOFDZERO
3552         || ttyfd > 0
3553 #endif /* NOFDZERO */
3554         ) {
3555         saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
3556         xx = alarm(8);                  /* Allow 8 seconds. */
3557         debug(F101,"ttclos alarm","",xx);
3558         if (
3559 #ifdef CK_POSIX_SIG
3560             sigsetjmp(sjbuf,1)
3561 #else
3562             setjmp(sjbuf)
3563 #endif /* CK_POSIX_SIG */
3564             ) {                         /* Timer went off? */
3565             x = -1;
3566 #ifdef DEBUG
3567             debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
3568             printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
3569 #endif /* DEBUG */
3570         }
3571         /* Hang up the device (drop DTR) */
3572
3573         errno = 0;
3574         debug(F111,"ttclos A",ckitoa(x),ttc_state);
3575         if (ttc_state < 1) {
3576             ttc_state = 1;
3577             debug(F101,"ttclos exithangup","",exithangup);
3578             if (exithangup) {
3579                 alarm(8);               /* Re-arm the timer */
3580                 debug(F101,"ttclos calling tthang()","",x);
3581                 x = tthang();           /* Hang up first, then... */
3582                 debug(F101,"ttclos tthang()","",x);
3583             }
3584         }
3585         /* Put back device modes as we found them */
3586
3587         errno = 0;
3588         debug(F111,"ttclos B",ckitoa(x),ttc_state);
3589         if (ttc_state < 2) {
3590             ttc_state = 2;
3591             /* Don't try to mess with tty modes if tthang failed() */
3592             /* since it probably won't work. */
3593             if (x > -1) {
3594                 debug(F101,"ttclos calling ttres()","",x);
3595                 signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
3596                 alarm(8);               /* Re-arm the timer */
3597                 x = ttres();            /* Reset device modes. */
3598                 debug(F101,"ttclos ttres()","",x);
3599                 alarm(0);
3600             }
3601         }
3602         /* Close the device */
3603
3604         errno = 0;
3605         debug(F101,"ttclos C","",ttc_state);
3606         if (ttc_state < 3) {
3607             ttc_state = 3;
3608             errno = 0;
3609             debug(F101,"ttclos calling close","",x);
3610             signal(SIGALRM,xtimerh);    /* Re-enable alarm. */
3611             alarm(8);                   /* Re-arm the timer */
3612             x = close(ttyfd);           /* Close the device. */
3613             debug(F101,"ttclos close()","",x);
3614             if (x > -1)
3615               ttc_state = 3;
3616         }
3617         debug(F101,"ttclos D","",ttc_state);
3618         ttimoff();                      /* Turn off timer. */
3619         if (x < 0) {
3620             printf("?WARNING - close failed: %s\n",ttnmsv);
3621 #ifdef DEBUG
3622             if (deblog) {
3623                 printf("errno = %d\n", errno);
3624                 debug(F101,"ttclos failed","",errno);
3625             }
3626 #endif /* DEBUG */
3627         }
3628         /* Unlock after closing but before any getty mumbo jumbo */
3629
3630         debug(F100,"ttclos about to call ttunlck","",0);
3631         if (ttunlck())                  /* Release uucp-style lock */
3632           fprintf(stderr,"Warning, problem releasing lock\r\n");
3633     }
3634
3635 /* For bidirectional lines, restore getty if it was there before. */
3636
3637 #ifdef ACUCNTRL                         /* 4.3BSD acucntrl() method. */
3638     if (xlocal) {
3639         debug(F100,"ttclos ACUCNTRL","",0);
3640         acucntrl("enable",ttnmsv);      /* Enable getty on the device. */
3641     }
3642 #else
3643 #ifdef ATT7300                          /* ATT UNIX PC (3B1, 7300) method. */
3644     if (xlocal) {
3645         debug(F100,"ttclos ATT7300 ongetty","",0);
3646         if (attmodem & DOGETY)          /* Was getty(1m) running before us? */
3647           ongetty(ttnmsv);              /* Yes, restart getty on tty line */
3648         attmodem &= ~DOGETY;            /* No phone in use, getty restored */
3649     }
3650 #endif /* ATT7300 */
3651 #endif /* System-dependent getty-restoring methods */
3652
3653 #ifdef sony_news
3654     km_ext = -1;                        /* Invalidate device's Kanji-mode */
3655 #endif /* sony_news */
3656
3657     ttyfd = -1;                         /* Invalidate the file descriptor. */
3658     wasclosed = 1;
3659     debug(F100,"ttclos done","",0);
3660     return(0);
3661 }
3662
3663 /*  T T H A N G  --  Hangup phone line or network connection.  */
3664 /*
3665   Returns:
3666   0 if it does nothing.
3667   1 if it believes that it hung up successfully.
3668  -1 if it believes that the hangup attempt failed.
3669 */
3670
3671 #define HUPTIME 500                     /* Milliseconds for hangup */
3672
3673 #ifdef COMMENT
3674 /* The following didn't work but TIOCSDTR does work */
3675 #ifdef UNIXWARE
3676 /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
3677 #ifndef POSIX                           /* Such as Unixware 1.x, 2.x */
3678 #ifndef HUP_POSIX
3679 #define HUP_POSIX
3680 #endif /* HUP_POSIX */
3681 #endif /* POSIX */
3682 #endif /* UNIXWARE */
3683 #endif /* COMMENT */
3684
3685 #ifndef USE_TIOCSDTR
3686 #ifdef __NetBSD__
3687 /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
3688 #ifdef TIOCSDTR
3689 #ifdef TIOCCDTR
3690 #define USE_TIOCSDTR
3691 #endif /* TIOCCDTR */
3692 #endif /* TIOCSDTR */
3693 #endif /* __NetBSD__ */
3694 #endif /* USE_TIOCSDTR */
3695
3696 #ifndef HUP_CLOSE_POSIX
3697 #ifdef OU8
3698 #define HUP_CLOSE_POSIX
3699 #else
3700 #ifdef CK_SCOV5
3701 #define HUP_CLOSE_POSIX
3702 #endif /* CK_SCOV5 */
3703 #endif /* OU8 */
3704 #endif /* HUP_CLOSE_POSIX */
3705
3706 #ifdef NO_HUP_CLOSE_POSIX
3707 #ifdef HUP_CLOSE_POSIX
3708 #undef HUP_CLOSE_POSIX
3709 #endif /* HUP_CLOSE_POSIX */
3710 #endif /* NO_HUP_CLOSE_POSIX */
3711
3712 int
3713 tthang() {
3714 #ifdef NOLOCAL
3715     return(0);
3716 #else
3717     int x = 0;                          /* Sometimes used as return code. */
3718 #ifndef POSIX
3719     int z;                              /* worker */
3720 #endif /* POSIX */
3721
3722 #ifdef COHERENT
3723 #define SVORPOSIX
3724 #endif /* COHERENT */
3725
3726 #ifdef SVORPOSIX                        /* AT&T, POSIX, HPUX declarations. */
3727     int spdsav;                         /* for saving speed */
3728 #ifdef HUP_POSIX
3729     int spdsavi;
3730 #else
3731 #ifdef BSD44ORPOSIX
3732     int spdsavi;
3733 #endif /* BSD44ORPOSIX */
3734 #endif /* HUP_POSIX */
3735 #ifdef HPUX
3736 /*
3737   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
3738   about it, just change it to long (or better still, unsigned long).
3739 */
3740     mflag
3741       dtr_down = 00000000000,
3742       modem_rtn,
3743       modem_sav;
3744     char modem_state[64];
3745 #endif /* HPUX */
3746     int flags;                          /* fcntl flags */
3747     unsigned short ttc_save;
3748 #endif /* SVORPOSIX */
3749
3750     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
3751     if (xlocal < 1) return(0);          /* Don't do this if not local */
3752
3753 #ifdef NETCMD
3754     if (ttpipe)
3755       return((ttclos(0) < 0) ? -1 : 1);
3756 #endif /* NETCMD */
3757 #ifdef NETPTY
3758     if (ttpty)
3759       return((ttclos(0) < 0) ? -1 : 1);
3760 #endif /* NETPTY */
3761 #ifdef NETCONN
3762     if (netconn) {                      /* Network connection. */
3763 #ifdef TN_COMPORT
3764         if (istncomport()) {
3765             int rc = tnc_set_dtr_state(0);
3766             if (rc >= 0) {
3767                 msleep(HUPTIME);
3768                 rc = tnc_set_dtr_state(1);
3769             }
3770             return(rc >= 0 ? 1 : -1);
3771         } else
3772 #endif /* TN_COMPORT */
3773           return((netclos() < 0) ? -1 : 1); /* Just close it. */
3774   }
3775 #endif /* NETCONN */
3776
3777 /* From here down, we handle real tty devices. */
3778 #ifdef HUP_POSIX
3779 /*
3780   e.g. for Unixware 2, where we don't have a full POSIX build, we
3781   still have to use POSIX-style hangup.  Thus the duplication of this
3782   and the next case, the only difference being we use a local termios
3783   struct here, since a different model is used elsewhere.
3784
3785   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
3786   even though it compiles and executes without error, doesn't actually
3787   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
3788 */
3789     {
3790         struct termios ttcur;
3791         int x;
3792         debug(F100,"tthang HUP_POSIX style","",0);
3793         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3794         debug(F111,"tthang tcgetattr",ckitoa(errno),x);
3795         if (x < 0) return(-1);
3796         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
3797         debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
3798         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
3799         debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
3800         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
3801         debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
3802         if (x < 0) return(-1);
3803         x = cfsetispeed(&ttcur,B0);
3804         debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
3805         if (x < 0) return(-1);
3806         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3807         debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
3808         if (x < 0) return(-1);
3809         msleep(HUPTIME);                /* Sleep 0.5 sec */
3810         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3811         if (x < 0) return(-1);
3812         debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
3813         x = cfsetispeed(&ttcur,spdsavi);
3814         debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
3815         if (x < 0) return(-1);
3816         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3817         debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
3818         if (x < 0) return(-1);
3819         return(1);
3820     }
3821 #else
3822 #ifdef BSD44ORPOSIX
3823 #ifdef QNX
3824     {
3825         int x;
3826         x = tcdropline(ttyfd,500);
3827         debug(F101,"tthang QNX tcdropline","",x);
3828         ttcur.c_cflag |= CLOCAL;
3829         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3830         debug(F101,"tthang QNX tcsetattr restore","",x);
3831         if (x < 0) {
3832             debug(F101,"tthang QNX tcsetattr restore errno","",errno);
3833             return(-1);
3834         }
3835         /* Fix flags - ensure O_NONBLOCK is off */
3836
3837         errno = 0;
3838         debug(F101,"tthang QNX iniflags","",iniflags);
3839         if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
3840             debug(F101,"tthang QNX F_SETFL errno","",errno);
3841             return(-1);
3842         }
3843         return(x);
3844     }
3845 #else  /* QNX */
3846     {
3847         int x;
3848 #ifdef USE_TIOCSDTR
3849         debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
3850         errno = 0;
3851         x = ioctl(ttyfd, TIOCCDTR, NULL);
3852         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
3853         if (x < 0) return(-1);
3854         msleep(HUPTIME);                /* Sleep 0.5 sec */
3855         errno = 0;
3856         x = ioctl(ttyfd, TIOCSDTR, NULL);
3857         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
3858         if (x < 0) return(-1);
3859 #else  /* USE_TIOCSDTR */
3860
3861 #ifdef HUP_CLOSE_POSIX
3862 /*
3863   In OSR5 versions where TIOCSDTR is not defined (up to and including at
3864   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
3865   don't work, and no other APIs are available that do work.  In this case
3866   we have to drop DTR by brute force: close and reopen the port.  This
3867   code actually works, but all the steps are crucial: setting CLOCAL, the
3868   O_NDELAY manipulations, etc.
3869 */
3870         debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
3871         debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
3872         debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
3873         errno = 0;
3874         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3875         debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
3876         if (x < 0) {
3877             debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
3878             return(-1);
3879         }
3880         errno = 0;
3881
3882         x = close(ttyfd);               /* Close without releasing lock */
3883         if (x < 0) {
3884             debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
3885             return(-1);
3886         }
3887         errno = 0;
3888         x = msleep(500);                /* Pause half a second */
3889         if (x < 0) {                    /* Or if that doesn't work, 1 sec */
3890             debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
3891             sleep(1);
3892         }
3893         errno = 0;
3894         ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
3895         debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
3896         if (ttyfd < 0) {
3897             debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
3898             return(-1);
3899         }
3900         debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
3901
3902         /* Restore previous attributes */
3903
3904         errno = 0;
3905         tvtflg = 0;
3906         ttcur.c_cflag |= CLOCAL;
3907         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3908         debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
3909         if (x < 0) {
3910             debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
3911                   "",errno);
3912             return(-1);
3913         }
3914         /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
3915
3916         errno = 0;
3917         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
3918             debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
3919             return(-1);
3920         }
3921         debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
3922         errno = 0;
3923         x &= ~(O_NONBLOCK|O_NDELAY);
3924         debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
3925         debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
3926         if (fcntl(ttyfd, F_SETFL, x) == -1) {
3927             debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
3928             return(-1);
3929         }
3930 #ifdef DEBUG
3931         if (deblog) {
3932             if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
3933                 debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
3934                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
3935                       "",x&O_NONBLOCK);
3936                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
3937                       "",x&O_NDELAY);
3938             }
3939         }
3940 #endif /* DEBUG */
3941
3942 #else  /* HUP_CLOSE_POSIX */
3943         
3944         /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
3945
3946         debug(F100,"tthang BSD44ORPOSIX B0","",0);
3947         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3948         debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
3949         if (x < 0) return(-1);
3950         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
3951         debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
3952         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
3953         debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
3954         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
3955         debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
3956         if (x < 0) return(-1);
3957         x = cfsetispeed(&ttcur,B0);
3958         debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
3959         if (x < 0) return(-1);
3960         /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
3961         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3962         debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
3963         if (x < 0) return(-1);
3964         msleep(HUPTIME);                /* Sleep 0.5 sec */
3965         debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
3966         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3967         debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
3968         if (x < 0) return(-1);
3969         debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
3970         x = cfsetispeed(&ttcur,spdsavi);
3971         debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
3972         if (x < 0) return(-1);
3973         ttcur.c_cflag |= CLOCAL;        /* Don't expect CD after hangup */
3974         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3975         debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
3976         if (x < 0) return(-1);
3977
3978 #endif /* HUP_CLOSE_POSIX */
3979 #endif /* USE_TIOCSDTR */
3980
3981         return(1);
3982     }
3983
3984 #endif /* QNX */
3985 #else /* BSD44ORPOSIX */
3986
3987 #ifdef aegis                            /* Apollo Aegis */
3988     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
3989     msleep(HUPTIME);                                    /* pause */
3990     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
3991     return(1);
3992 #endif /* aegis */
3993
3994 #ifdef ANYBSD                           /* Any BSD version. */
3995 #ifdef TIOCCDTR                         /* Except those that don't have this */
3996     debug(F100,"tthang BSD style","",0);
3997     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {  /* Clear DTR. */
3998         debug(F101,"tthang TIOCCDTR fails","",errno);
3999         return(-1);
4000     }
4001     msleep(HUPTIME);                    /* For about 1/2 sec */
4002     errno = 0;
4003     x = ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
4004     if (x < 0) {
4005         /*
4006           For some reason, this tends to fail with "no such device or address"
4007           but the operation still works, probably because of the close/open
4008           later on.  So let's not scare the user unnecessarily here.
4009         */
4010         debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
4011         x = 1;                          /* Pretend we succeeded */
4012     } else if (x == 0) x = 1;           /* Success */
4013 #ifdef COMMENT
4014 #ifdef FT21
4015     ioctl(ttyfd, TIOCSAVEMODES, 0);
4016     ioctl(ttyfd, TIOCHPCL, 0);
4017     close(ttyfd);                       /* Yes, must do this twice */
4018     if ((ttyfd = open(ttnmsv,2)) < 0)   /* on Fortune computers... */
4019       return(-1);                       /* (but why?) */
4020     else x = 1;
4021 #endif /* FT21 */
4022 #endif /* COMMENT */
4023 #endif /* TIOCCDTR */
4024     close(do_open(ttnmsv));             /* Clear i/o error condition */
4025     errno = 0;
4026 #ifdef COMMENT
4027 /* This is definitely dangerous.  Why was it here? */
4028     z = ttvt(ttspeed,ttflow);           /* Restore modes. */
4029     debug(F101,"tthang ttvt returns","",z);
4030     return(z < 0 ? -1 : 1);
4031 #else
4032     return(x);
4033 #endif /* COMMENT */
4034 #endif /* ANYBSD */
4035
4036 #ifdef ATTSV
4037 /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
4038
4039 #ifdef HPUX
4040 /* Hewlett Packard allows explicit manipulation of modem signals. */
4041
4042 #ifdef COMMENT
4043 /* Old way... */
4044     debug(F100,"tthang HP-UX style","",0);
4045     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
4046       return(-1);                                  /* oops, can't. */
4047     msleep(HUPTIME);                               /* Pause half a second. */
4048     x = 1;                                         /* Set return code */
4049     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
4050         if ((modem_rtn & MDCD) != 0)               /* Check if CD is low. */
4051           x = -1;                                  /* CD didn't drop, fail. */
4052     } else x = -1;
4053
4054     /* Even if above calls fail, RTS & DTR should be turned back on. */
4055     modem_rtn = MRTS | MDTR;
4056     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
4057     return(x);
4058 #else
4059 /* New way, from Hellmuth Michaelis */
4060     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
4061     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
4062         debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
4063         return(-1);
4064     }
4065     sprintf(modem_state,"%#lx",modem_rtn);
4066     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
4067     modem_sav = modem_rtn;              /* Save current modem signals */
4068     modem_rtn &= ~MDTR;                 /* Turn DTR bit off */
4069     sprintf(modem_state,"%#lx",modem_rtn);
4070     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
4071     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
4072         debug(F100,"tthang HP-UX: can't lower DTR!","",0);
4073         return(-1);                     /* oops, can't. */
4074     }
4075     msleep(HUPTIME);                    /* Pause half a second. */
4076     x = 1;                              /* Set return code */
4077     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
4078         sprintf(modem_state,"%#lx",modem_rtn);
4079         debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
4080         if ((modem_rtn & MDCD) != 0) {  /* Check if CD is low. */
4081             debug(F100,"tthang HP-UX: DCD not down","",0);
4082             x = -1;                     /* CD didn't drop, fail. */
4083         } else {
4084             debug(F100,"tthang HP-UX: DCD down","",0);
4085         }
4086     } else {
4087         x = -1;
4088         debug(F100,"tthang HP-UX: can't get DCD status !","",0);
4089     }
4090
4091     /* Even if above calls fail, DTR should be turned back on. */
4092
4093     modem_sav |= MDTR;
4094     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
4095         x = -1;
4096         debug(F100,"tthang HP-UX: can't set saved state","",0);
4097     } else {
4098         sprintf(modem_state,"%#lx",modem_sav);
4099         debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
4100     }
4101     return(x);
4102 #endif /* COMMENT */
4103
4104 #else /* AT&T but not HP-UX */
4105
4106 /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
4107 /* It is not known how many, if any, systems actually implement them, */
4108 /* so we include them here in ifdef's. */
4109
4110 /*
4111   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
4112   gives error 22 (invalid argument).
4113 */
4114 #ifndef _IBMR2
4115 /*
4116   No modem-signal twiddling for IBM RT PC or RS/6000.
4117   In AIX 3.1 and earlier, the ioctl() call is broken.
4118   This code could be activated for AIX 3.1 with PTF 2006 or later
4119   (e.g. AIX 3.2), but close/open does the job too, so why bother.
4120 */
4121 #ifdef TIOCMBIS                         /* Bit Set */
4122 #ifdef TIOCMBIC                         /* Bit Clear */
4123 #ifdef TIOCM_DTR                        /* DTR */
4124
4125 /* Clear DTR, sleep 300 msec, turn it back on. */
4126 /* If any of the ioctl's return failure, go on to the next section. */
4127
4128     z = TIOCM_DTR;                      /* Code for DTR. */
4129 #ifdef COMMENT
4130 /*
4131   This was the cause of the troubles with the Solaris Port Monitor.
4132   The problem is: RTS never comes back on.  Moral: Don't do it!
4133   (But why doesn't it come back on?  See the TIOCMBIS call...)
4134 */
4135 #ifdef TIOCM_RTS                        /* Lower RTS too if symbol is known. */
4136     z |= TIOCM_RTS;
4137 #endif /* TIOCM_RTS */
4138 #endif /* COMMENT */
4139
4140     debug(F101,"tthang TIOCM signal mask","",z);
4141     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
4142         debug(F100,"tthang TIOCMBIC ok","",0);
4143         msleep(HUPTIME);                   /* Pause half a second. */
4144         if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
4145             debug(F100,"tthang TIOCMBIS ok","",0);
4146 #ifndef CLSOPN
4147             return(1);                  /* Success, done. */
4148 #endif /* CLSOPN */
4149         } else {                        /* Couldn't raise, continue. */
4150             debug(F101,"tthang TIOCMBIS errno","",errno);
4151         }
4152     } else {                            /* Couldn't lower, continue. */
4153         debug(F101,"tthang TIOCMBIC errno","",errno);
4154     }
4155 #endif /* TIOCM_DTR */
4156 #endif /* TIOCMBIC */
4157 #endif /* TIOCMBIS */
4158 #endif /* _IBMR2 */
4159
4160 /*
4161   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
4162   two AT&T-based systems seem to do this the same way.  The object is simply
4163   to turn off DTR and then turn it back on.  SVID says the universal method
4164   for turning off DTR is to set the speed to zero, and this does seem to do
4165   the trick in all cases.  But neither SVID nor any known man pages say how to
4166   turn DTR back on again.  Some variants, like most Xenix implementations,
4167   raise DTR again when the speed is restored to a nonzero value.  Others
4168   require the device to be closed and opened again, but this is risky because
4169   getty could seize the device during the instant it is closed.
4170 */
4171
4172 /* Return code for ioctl failures... */
4173 #ifdef ATT6300
4174     x = 1;                              /* ATT6300 doesn't want to fail... */
4175 #else
4176     x = -1;
4177 #endif /* ATT6300 */
4178
4179     debug(F100,"tthang get settings","",0);
4180     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
4181       return(x);                        /* Fail if this doesn't work. */
4182     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
4183       return(x);
4184     ttc_save = ttcur.c_cflag;           /* Remember current speed. */
4185     spdsav = ttc_save & CBAUD;
4186     debug(F101,"tthang speed","",spdsav);
4187
4188 #ifdef O_NDELAY
4189     debug(F100,"tthang turning O_NDELAY on","",0);
4190     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
4191 #endif /* O_NDELAY */
4192
4193 #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
4194     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4195 #else
4196 #ifdef RTAIX
4197     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4198 #else          /* This way really works but may be dangerous */
4199 #ifdef u3b2
4200     ttcur.c_cflag = ~(CBAUD|CLOCAL);    /* Special for AT&T 3B2s */
4201                                         /* (CLOCAL must be OFF) */
4202 #else
4203 #ifdef SCO3R2                           /* SCO UNIX 3.2 */
4204 /*
4205   This is complete nonsense, but an SCO user claimed this change made
4206   hanging up work.  Comments from other SCO UNIX 3.2 users would be
4207   appreciated.
4208 */
4209     ttcur.c_cflag = CBAUD|B0;
4210 #else
4211 #ifdef AIXRS                            /* AIX on RS/6000 */
4212 /*
4213   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
4214   even though you can do it on the built-in port and the 8- and 16-port
4215   adapters.  (Untested on 128-port adapter.)
4216 */
4217     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
4218 #else                                   /* None of the above */
4219 /*
4220   Set everything, including the speed, to zero, except for the CLOCAL
4221   and HUPCL bits.
4222 */
4223     ttcur.c_cflag = CLOCAL|HUPCL;
4224 #endif /* AIXRS */
4225 #endif /* SCO3R2 */
4226 #endif /* u3b2 */
4227 #endif /* RTAIX */
4228 #endif /* ATT7300 */
4229
4230 #ifdef COMMENT
4231     /* and if none of those work, try one of these... */
4232     ttcur.c_cflag = 0;
4233     ttcur.c_cflag = CLOCAL;
4234     ttcur.c_cflag &= ~(CBAUD|HUPCL);
4235     ttcur.c_cflag &= ~(CBAUD|CREAD);
4236     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
4237     /* or other combinations */
4238 #endif /* COMMENT */
4239
4240 #ifdef TCXONC
4241     debug(F100,"tthang TCXONC","",0);
4242     if (ioctl(ttyfd, TCXONC, 1) < 0) {
4243         debug(F101,"tthang TCXONC failed","",errno);
4244     }
4245 #endif /* TCXONC */
4246
4247 #ifdef TIOCSTART
4248     debug(F100,"tthang TIOCSTART","",0);
4249     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
4250         debug(F101,"tthang TIOCSTART failed","",errno);
4251     }
4252 #endif /* TIOCSTART */
4253
4254     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
4255         debug(F101,"tthang TCSETAF failed","",errno);
4256         fcntl(ttyfd, F_SETFL, flags);   /* Restore flags */
4257         return(-1);                     /* before returning. */
4258     }
4259     msleep(300);                        /* Give modem time to notice. */
4260
4261 #ifndef NOCOTFMC
4262
4263 /* Now, even though it doesn't say this in SVID or any man page, we have */
4264 /* to close and reopen the device.  This is not necessary for all systems, */
4265 /* but it's impossible to predict which ones need it and which ones don't. */
4266
4267 #ifdef ATT7300
4268 /*
4269   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
4270   related ioctl's for their internal modems.  attmodem has getty status and
4271   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
4272   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
4273   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
4274   The only way to undo the damage is to close the fd and then reopen it.
4275 */
4276     if (attmodem & ISMODEM) {
4277         debug(F100,"tthang attmodem close/open","",0);
4278         ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
4279         ioctl(ttyfd,PIOCDISC,&dialer);  /* Disconnect phone. */
4280         close(ttyfd);                   /* Close and reopen the fd. */
4281         ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
4282         attmodem &= ~ISMODEM;           /* Phone no longer in use. */
4283     }
4284 #else /* !ATT7300 */
4285 /* It seems we have to close and open the device for other AT&T systems */
4286 /* too, and this is the place to do it.  The following code does the */
4287 /* famous close(open(...)) magic by default.  If that doesn't work for you, */
4288 /* then try uncommenting the following statement or putting -DCLSOPN in */
4289 /* the makefile CFLAGS. */
4290
4291 /* #define CLSOPN */
4292
4293 #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
4294
4295 #ifdef O_NDELAY
4296 #define OPENFLGS O_RDWR | O_NDELAY
4297 #else
4298 #define OPENFLGS O_RDWR
4299 #endif
4300
4301 #ifndef CLSOPN
4302 /* This method is used by default, i.e. unless CLSOPN is defined. */
4303 /* It is thought to be safer because there is no window where getty */
4304 /* can seize control of the device.  The drawback is that it might not work. */
4305
4306     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
4307     close(priv_opn(ttnmsv, OPENFLGS));
4308
4309 #else
4310 /* This method is used if you #define CLSOPN.  It is more likely to work */
4311 /* than the previous method, but it's also more dangerous. */
4312
4313     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
4314     close(ttyfd);
4315     msleep(10);
4316     ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
4317 #endif /* CLSOPN */
4318 #undef OPENFLGS
4319
4320 #endif /* SCO32 */
4321 #endif /* ATT7300 */
4322
4323 #endif /* NOCOTFMC */
4324
4325 /* Now put all flags & modes back the way we found them. */
4326 /* (Does the order of ioctl & fcntl matter ? ) */
4327
4328     debug(F100,"tthang restore settings","",0);
4329     ttcur.c_cflag = ttc_save;           /* Get old speed back. */
4330     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
4331       return(-1);
4332 #ifdef O_NDELAY
4333 /*
4334   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
4335   After closing a modem line, the modem will probably not be asserting
4336   carrier any more, so we should not require carrier any more.  If this
4337   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
4338   than O_NDELAY.
4339 */
4340     flags &= ~O_NDELAY;                 /* Don't require carrier on reopen */
4341 #endif /* O_NDELAY */
4342     if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
4343       return(-1);
4344
4345     return(1);
4346 #endif /* not HPUX */
4347 #endif /* ATTSV */
4348 #endif /* BSD44ORPOSIX */
4349 #endif /* HUP_POSIX */
4350 #endif /* NOLOCAL */
4351 }
4352
4353 /*
4354   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
4355   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
4356   LPASS8 business seems to have been causing trouble for everybody but me!
4357   For example, Annex terminal servers, commonly used with Encore computers,
4358   do not support LPASS8 even though the Encore itself does.  Ditto for many
4359   other terminal servers, TELNET connections, rlogin connections, etc etc.
4360   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
4361   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
4362   off for everybody.  That means we goes back to using raw mode, with no
4363   flow control.  Phooey.
4364
4365   NOTE: This must be done before the first reference to LPASS8 in this file,
4366   and after the last #include statment.
4367 */
4368 #ifdef LPASS8
4369 #undef LPASS8
4370 #endif /* LPASS8 */
4371
4372 /*  T T R E S  --  Restore terminal to "normal" mode.  */
4373
4374 /* ske@pkmab.se: There are two choices for what this function should do.
4375  * (1) Restore the tty to current "normal" mode, with carrier treatment
4376  * according to ttcarr, to be used after every kermit command. (2) Restore
4377  * the tty to the state it was in before kermit opened it. These choices
4378  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
4379  * is currently being called as in choice (1), but ttold basically holds
4380  * the initial parameters, as in (2), and the description at the beginning
4381  * of this file says (2).
4382  *
4383  * I don't think restoring tty parameters after all kermit commands makes
4384  * much of a difference.  Restoring them upon exit from kermit may be of
4385  * some use in some cases (when the line is not restored automatically on
4386  * close, by the operating system).
4387  *
4388  * I can't choose which one it should be, so I haven't changed it. It
4389  * probably works as it is, too. It would probably even work even with
4390  * ttres() entirely deleted...
4391  *
4392  * (from fdc: Actually, this function operates in remote mode too, so
4393  * it restores the console (command) terminal to whatever mode it was
4394  * in before packet operations began, so that commands work right again.)
4395  */
4396 int
4397 ttres() {                               /* Restore the tty to normal. */
4398     int x;
4399
4400     if (ttyfd < 0) return(-1);          /* Not open. */
4401
4402     if (ttfdflg) return(0);             /* Don't mess with terminal modes if */
4403                                         /* we got ttyfd from another process */
4404 #ifdef  NETCONN
4405     if (netconn) {                      /* Network connection */
4406         tvtflg = 0;
4407 #ifdef TCPSOCKET
4408 #ifdef TCP_NODELAY
4409         {
4410             extern int tcp_nodelay;     /* Just put this back if necessary */
4411             if (ttnet == NET_TCPB) {
4412                 if (nodelay_sav > -1) {
4413                     no_delay(ttyfd,nodelay_sav);
4414                     nodelay_sav = -1;
4415                 }
4416             }
4417         }
4418 #endif /* TCP_NODELAY */
4419 #ifdef TN_COMPORT
4420         if (istncomport()) {
4421             int rc = -1;
4422             if ((rc = tnsetflow(ttflow)) < 0)
4423               return(rc);
4424             if (ttspeed <= 0) 
4425               ttspeed = tnc_get_baud();
4426             else if ((rc = tnc_set_baud(ttspeed)) < 0)
4427               return(rc);
4428             tnc_set_datasize(8);
4429             tnc_set_stopsize(stopbits);
4430
4431 #ifdef HWPARITY
4432             if (hwparity) {
4433                 switch (hwparity) {
4434                   case 'e':                     /* Even */
4435                     debug(F100,"ttres 8 bits + even parity","",0);
4436                     tnc_set_parity(3);
4437                     break;
4438                   case 'o':                     /* Odd */
4439                     debug(F100,"ttres 8 bits + odd parity","",0);
4440                     tnc_set_parity(2);
4441                     break;
4442                   case 'm':                     /* Mark */
4443                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
4444                     tnc_set_parity(4);
4445                     break;
4446                   case 's':                     /* Space */
4447                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
4448                     tnc_set_parity(5);
4449                     break;
4450                 }
4451             } else
4452 #endif /* HWPARITY */
4453             {
4454                 tnc_set_parity(1);              /* None */
4455             }
4456             tvtflg = 0;
4457             return(0);
4458         }
4459 #endif /* TN_COMPORT */
4460 #endif /* TCPSOCKET */
4461         return(0);
4462     }
4463 #endif  /* NETCONN */
4464 #ifdef NETCMD
4465     if (ttpipe) return(0);
4466 #endif /* NETCMD */
4467 #ifdef NETPTY
4468     if (ttpty) return(0);
4469 #endif /* NETPTY */
4470
4471 /* Real terminal device, so restore its original modes */
4472
4473 #ifdef BSD44ORPOSIX                     /* For POSIX like this */
4474     debug(F100,"ttres BSD44ORPOSIX","",0);
4475     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
4476 #else                                   /* For all others... */
4477 #ifdef ATTSV                            /* For AT&T versions... */
4478     debug(F100,"ttres ATTSV","",0);
4479     x = ioctl(ttyfd,TCSETAW,&ttold);    /* Restore tty modes this way. */
4480 #else
4481 /* Here we restore the modes for BSD */
4482
4483 #ifdef LPASS8                           /* Undo "pass8" if it were done */
4484     if (lmodef) {
4485         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4486           debug(F100,"ttres TIOCLSET failed","",0);
4487         else
4488           debug(F100,"ttres TIOCLSET ok","",0);
4489     }
4490 #endif /* LPASS8 */
4491
4492 #ifdef CK_DTRCTS                   /* Undo hardware flow if it were done */
4493     if (lmodef) {
4494         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4495           debug(F100,"ttres TIOCLSET failed","",0);
4496         else
4497           debug(F100,"ttres TIOCLSET ok","",0);
4498     }
4499 #endif /* CK_DTRCTS */
4500
4501 #ifdef TIOCGETC                         /* Put back special characters */
4502     if (tcharf && (xlocal == 0)) {
4503         if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
4504           debug(F100,"ttres TIOCSETC failed","",0);
4505         else
4506           debug(F100,"ttres TIOCSETC ok","",0);
4507     }
4508 #endif /* TIOCGETC */
4509
4510 #ifdef TIOCGLTC                         /* Put back local special characters */
4511     if (ltcharf && (xlocal == 0)) {
4512         if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
4513           debug(F100,"ttres TIOCSLTC failed","",0);
4514         else
4515           debug(F100,"ttres TIOCSLTC ok","",0);
4516     }
4517 #endif /* TIOCGLTC */
4518
4519 #ifdef BELLV10
4520     debug(F100,"ttres BELLV10","",0);
4521     x = ioctl(ttyfd,TIOCSETP,&ttold);   /* Restore both structs */
4522     x = ioctl(ttyfd,TIOCSDEV,&tdold);
4523 #else
4524     debug(F100,"ttres stty","",0);
4525     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
4526 #endif /* BELLV10 */
4527
4528     if (!xlocal)
4529       msleep(100);                      /* This replaces sleep(1)... */
4530                                         /* Put back sleep(1) if tty is */
4531                                         /* messed up after close. */
4532 #endif /* ATTSV */
4533 #endif /* BSD44ORPOSIX */
4534
4535     debug(F101,"ttres result","",x);
4536 #ifndef QNX
4537     if (x < 0) debug(F101,"ttres errno","",errno);
4538 #endif /* QNX */
4539
4540 #ifdef AIXRS
4541 #ifndef AIX41
4542     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
4543     debug(F101,"ttres AIX line discipline rts restore","",x);
4544 #endif /* AIX41 */
4545 #endif /* AIXRS */
4546
4547 #ifdef BSD41
4548     if (ttld > -1) {                    /* Put back line discipline */
4549         x = ioctl(ttyfd, TIOCSETD, &ttld);
4550         debug(F101,"ttres BSD41 line discipline restore","",x);
4551         if (x < 0) debug(F101,"...ioctl errno","",errno);
4552         ttld = -1;
4553     }
4554 #endif /* BSD41 */
4555
4556 #ifdef sony_news
4557     x = xlocal ? km_ext : km_con;       /* Restore Kanji mode. */
4558     if (x != -1) {                      /* Make sure we know original modes. */
4559         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
4560             perror("ttres can't set Kanji mode");
4561             debug(F101,"ttres error setting Kanji mode","",x);
4562             return(-1);
4563         }
4564     }
4565     debug(F100,"ttres set Kanji mode ok","",0);
4566 #endif /* sony_news */
4567
4568     tvtflg = 0;                         /* Invalidate terminal mode settings */
4569     debug(F101,"ttres return code","",x);
4570     return(x);
4571 }
4572
4573 #ifndef NOUUCP
4574
4575 /*  T T C H K P I D  --  Check lockfile pid  */
4576 /*
4577   Read pid from lockfile named f, check that it's still valid.
4578   If so, return 1.
4579   On failure to read pid, return 1.
4580   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
4581 */
4582 static int
4583 ttchkpid(f) char *f; {
4584     int pid, mypid, x;
4585     pid = ttrpid(f);                    /* Read pid from file. */
4586     if (pid > -1) {                     /* If we were able to read the pid.. */
4587         debug(F101,"ttchkpid lock pid","",pid);
4588         errno = 0;                      /* See if process still exists. */
4589         mypid = (int)getpid();          /* Get my own pid. */
4590         debug(F101,"ttchkpid my pid","",mypid);
4591         if (pid == mypid) {             /* It's me! */
4592             x = -1;                     /* So I can delete it */
4593             errno = ESRCH;              /* pretend it's invalid */
4594         } else {                        /* It's not me */
4595             x = kill((PID_T)pid, 0);    /* See if it's a live process */
4596             debug(F101,"ttchkpid kill errno","",errno);
4597         }
4598         debug(F101,"ttchkpid pid test","",x);
4599         if (x < 0 && errno == ESRCH) { /* pid is invalid */
4600             debug(F111,"removing stale lock",f,pid);
4601             if (!backgrd)
4602               printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
4603             priv_on();
4604             x = unlink(f);              /* Remove the lockfile. */
4605             priv_off();
4606             debug(F111,"ttchkpid unlink",f,x);
4607             if (x > -1)
4608               return(0);                /* Device is not locked after all */
4609             else if (!backgrd)
4610               perror(f);
4611         }
4612         return(1);
4613     }
4614     return(1);                          /* Failure to read pid */
4615 }
4616
4617 #ifdef HPUX
4618
4619 /* Aliases (different drivers) for HP-UX dialout devices: */
4620
4621 static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
4622 static int ttydexists = 0;
4623
4624 #endif /* HPUX */
4625
4626 /*  T T R P I D  --  Read pid from lockfile "name" */
4627
4628 static int
4629 ttrpid(name) char *name; {
4630     long len;
4631     int x, fd, pid;
4632     short spid;
4633     char buf[32];
4634
4635     debug(F110,"ttrpid",name,0);
4636     if (!name) return(-1);
4637     if (!*name) return(-1);
4638     priv_on();
4639     len = zchki(name);                  /* Get file length */
4640     priv_off();
4641     debug(F101,"ttrpid zchki","",len);
4642     if (len < 0)
4643       return(-1);
4644     if (len > 31)
4645       return(-1);
4646     priv_on();
4647     fd = open(name,O_RDONLY);           /* Try to open lockfile. */
4648     priv_off();
4649     debug(F101,"ttrpid fd","",fd);
4650     if (fd <= 0)
4651       return(-1);
4652 /*
4653   Here we try to be flexible and allow for all different binary and string
4654   formats at runtime, rather than a specific format for each configuration
4655   hardwired at compile time.
4656 */
4657     pid = -1;
4658 #ifndef COHERENT
4659 /*
4660   COHERENT uses a string PID but without leading spaces or 0's, so there is
4661   no way to tell from the file's length whether it contains a string or binary
4662   pid.  So for COHERENT only, we only allow string pids.  For all others, we
4663   decide based on the size of the lockfile.
4664 */
4665     if (len > 4) {                      /* If file > 4 bytes it's a string */
4666 #endif /* COHERENT */
4667         x = read(fd,buf,(int)len);
4668         debug(F111,"ttrpid string read",buf,x);
4669         if (x < 0) {
4670             pid = -1;
4671         } else {
4672             buf[31] = '\0';
4673             x = sscanf(buf,"%d",&pid);  /* Get the integer pid from it. */
4674         }
4675 #ifndef COHERENT
4676     } else if (len == 4) {              /* 4 bytes so binary */
4677         x = read(fd, (char *)&pid, 4);  /* Read the bytes into an int */
4678         debug(F101,"ttrpid integer read","",x);
4679         if (x < 4)
4680           pid = -1;
4681     } else if (len == 2) {              /* 2 bytes binary */
4682         x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
4683         debug(F101,"ttrpid short read","",x);
4684         if (x < 2)
4685           pid = -1;
4686         else
4687           pid = spid;
4688     } else
4689       pid = -1;
4690 #endif /* COHERENT */
4691     close(fd);                          /* Close the lockfile */
4692     debug(F101,"ttrpid pid","",pid);
4693     return(pid);
4694 }
4695 #endif /* NOUUCP */
4696
4697 /*  T T L O C K  */
4698
4699 /*
4700   This function attempts to coordinate use of the communication device with
4701   other copies of Kermit and any other program that follows the UUCP
4702   device-locking conventions, which, unfortunately, vary among different UNIX
4703   implementations.  The idea is to look for a file of a certain name, the
4704   "lockfile", in a certain directory.  If such a file is found, then the line
4705   is presumed to be in use, and Kermit should not use it.  If no such file is
4706   found, Kermit attempts to create one so that other programs will not use the
4707   same line at the same time.  Because the lockfile and/or the directory it's
4708   in might lack write permission for the person running Kermit, Kermit could
4709   find itself running setuid to uucp or other user that does have the
4710   necessary permissions.  At startup, Kermit has changed its effective uid to
4711   the user's real uid, and so ttlock() must switch back to the original
4712   effective uid in order to create the lockfile, and then back again to the
4713   real uid to prevent unauthorized access to other directories or files owned
4714   by the user the program is setuid to.
4715
4716   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
4717   based on suggestions from Warren Tucker.  Call with pointer to name of
4718   tty device.  Returns:
4719
4720    0 on success
4721   -1 on failure
4722
4723   Note: Once privileges are turned on using priv_on(), it is essential that
4724   they are turned off again before this function returns.
4725 */
4726 #ifdef SVR4                             /* Lockfile uses device numbers. */
4727 /*
4728   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
4729   it is the behavior of the "reference version" of SVR4, i.e. the Intel
4730   port from UNIX Systems Laboratories, then called Univel UnixWare,
4731   then called Novell UnixWare, then called SCO Unixware, then called Caldera
4732   Open UNIX...  It also makes much more sense than device-name-based lockfiles
4733   since there can be multiple names for the same device, symlinks, etc.
4734 */
4735 #ifndef NOLFDEVNO
4736 #ifndef LFDEVNO                         /* Define this for SVR4 */
4737 #ifndef AIXRS                           /* But not for RS/6000 AIX 3.2, etc. */
4738 #ifndef BSD44                           /* If anybody else needs it... */
4739 #ifndef __386BSD__
4740 #ifndef __FreeBSD__
4741 #ifndef HPUX10
4742 #ifndef IRIX51                          /* SGI IRIX 5.1 or later */
4743 #ifndef CK_SCOV5                        /* SCO Open Server 5.0 */
4744 #define LFDEVNO
4745 #endif /* CK_SCOV5 */
4746 #endif /* IRIX51 */
4747 #endif /* HPUX10 */
4748 #endif /* __FreeBSD__ */
4749 #endif /* __386BSD__ */
4750 #endif /* BSD44 */
4751 #endif /* AIXRS */
4752 #endif /* LFDEVNO */                    /* ... define it here or on CC */
4753 #endif /* NOLFDEVNO */
4754 #endif /* SVR4 */                       /* command line. */
4755
4756 #ifdef COHERENT
4757 #define LFDEVNO
4758 #endif /* COHERENT */
4759
4760 /*
4761   For platforms where the lockfile name is made from device/major/minor
4762   device number, as in SVR4.  Which, if we must have lockfiles at all, is
4763   by far the best format, since it eliminates all the confusion that stems
4764   from multiple names (or drivers) for the same port, not to mention
4765   symlinks.  It might even be a good idea to start using this form even
4766   on platforms where it's not supported, alongside the normal forms for those
4767   platforms, in order to get people used to it...
4768 */
4769 #ifdef LFDEVNO
4770 #ifndef major                           /* If we didn't find it */
4771 #ifdef SVR4                             /* then for Sys V R4 */
4772 #include <sys/mkdev.h>                  /* look here */
4773 #else                                   /* or for SunOS versions */
4774 #ifdef SUNOS4                           /* ... */
4775 #include <sys/sysmacros.h>              /* look here */
4776 #else                                   /* Otherwise take a chance: */
4777 #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
4778 #define minor(dev) ( (int) ( (dev) & 0xff))
4779 #endif /* SUNOS4 */
4780 #endif /* SVR4 */
4781 #endif /* major */
4782 #endif /* LFDEVNO */
4783
4784 /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
4785
4786 #ifdef LOCKF
4787 #ifndef F_TLOCK
4788 #undef LOCKF
4789 #ifndef NOLOCKF
4790 #define NOLOCKF
4791 #endif /* NOLOCKF */
4792 #endif /* F_TLOCK */
4793 #endif /* LOCKF */
4794
4795 #ifdef LOCKF
4796 #ifndef F_ULOCK
4797 #undef LOCKF
4798 #ifndef NOLOCKF
4799 #define NOLOCKF
4800 #endif /* NOLOCKF */
4801 #endif /* F_ULOCK */
4802 #endif /* LOCKF */
4803
4804 static char linkto[DEVNAMLEN+1];
4805 static char * linkdev = NULL;
4806
4807 #ifndef NOUUCP
4808 #ifdef USETTYLOCK
4809 #ifdef LOCK_DIR
4810 char * uucplockdir = LOCK_DIR;
4811 #else
4812 char * uucplockdir = "";
4813 #endif /* LOCK_DIR */
4814 #else
4815 #ifdef LOCK_DIR
4816 char * uucplockdir = LOCK_DIR;
4817 #else
4818 char * uucplockdir = "";
4819 #endif /* LOCK_DIR */
4820 #endif /* USETTYLOCK */
4821 #else
4822 char * uucplockdir = "";
4823 #endif /* NOUUCP */
4824
4825 #ifdef QNX                              /* Only for QNX4 */
4826 int                                     /* Visible to outside world */
4827 qnxopencount() {                        /* Get QNX device open count */
4828     struct _dev_info_entry info;
4829     int x;
4830
4831     x = -1;                             /* Unknown */
4832     if (ttyfd > -1) {
4833         if (!dev_info(ttyfd, &info)) {
4834             debug(F101,"ttlock QNX open_count","",info.open_count);
4835             x = info.open_count;
4836         }
4837     }
4838     return(x);
4839 }
4840 #endif /* QNX */
4841
4842 char *
4843 ttglckdir() {                           /* Get Lockfile directory name */
4844 #ifdef __OpenBSD__
4845     return("/var/spool/lock");
4846 #else /* __OpenBSD__ */
4847 #ifdef __FreeBSD__
4848     return("/var/spool/lock");
4849 #else  /* __FreeBSD__ */
4850 #ifdef LOCK_DIR
4851     char * s = LOCK_DIR;
4852 #endif /* LOCK_DIR */
4853 #ifdef NOUUCP
4854     return("");
4855 #else  /* NOUUCP */
4856 #ifdef LOCK_DIR
4857     return(s);
4858 #else  /* LOCK_DIR */
4859     return("");
4860 #endif /* LOCK_DIR */
4861 #endif /* NOUUCP */
4862 #endif /* __FreeBSD__ */
4863 #endif /* __OpenBSD__ */
4864 }
4865
4866 static int
4867 ttlock(ttdev) char *ttdev; {
4868
4869     int x, n;
4870     int islink = 0;
4871
4872 #ifdef NOUUCP
4873     debug(F100,"ttlock NOUUCP","",0);
4874     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
4875     haslock = 1;
4876     return(0);
4877 #else /* !NOUUCP */
4878
4879 #ifdef USETTYLOCK
4880     haslock = 0;                        /* Not locked yet. */
4881     *flfnam = '\0';                     /* Lockfile name is empty. */
4882     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
4883       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
4884     else
4885       ckstrncpy(lockname,ttdev,DEVNAMLEN);
4886 /*
4887   This might be overkill, but it's not clear from the man pages whether
4888   ttylock() can be called without calling ttylocked() first, since the doc
4889   says that ttylocked() removes any stale lockfiles, but it does not say this
4890   about ttylock().  Also the docs don't say what ttylocked() returns in the
4891   case when it finds and removes a stale lockfile.  So one or both calls to
4892   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
4893   assuming that we have to do all the same ID swapping, etc, with these
4894   routines as we do without them.  Thus the priv_on/off() sandwich.
4895 */
4896 #ifdef USE_UU_LOCK
4897     priv_on();                          /* Turn on privs */
4898     x = uu_lock(lockname);              /* Try to set the lock */
4899     priv_off();                         /* Turn privs off */
4900     debug(F111,"ttlock uu_lock",lockname,x);
4901     switch (x) {
4902       case UU_LOCK_INUSE:
4903         return(-2);
4904       case UU_LOCK_OK:
4905 #ifdef BSD44
4906         ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
4907 #endif /* BSD44 */
4908         haslock = 1;
4909         return(0);
4910       default:
4911         return(-1);
4912     }
4913 #else  /* USE_UU_LOCK */
4914     priv_on();                          /* Turn on privs */
4915     if (ttylocked(lockname)) {          /* This should remove any stale lock */
4916         if (ttylocked(lockname)) {      /* so check again. */
4917             priv_off();
4918             return(-5);                 /* Still locked, fail. */
4919         }
4920     }
4921     x = ttylock(lockname);              /* Lock it. */
4922     priv_off();                         /* Turn off privs */
4923
4924     debug(F111,"ttlock lockname",lockname,x);
4925     if (x > -1) {
4926         /*
4927           We don't really know the name of the lockfile, but
4928           this is what the man page says it is.  In USETTYLOCK
4929           builds, it is used only for display by SHOW COMM.
4930         */
4931         ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
4932         haslock = 1;
4933     }
4934     return(x);
4935 #endif /* USE_UU_LOCK */
4936 #else  /* Systems that don't have ttylock()... */
4937
4938 #ifndef HPUX
4939
4940     int lockfd;                         /* File descriptor for lock file. */
4941     PID_T pid;                          /* Process id of this process. */
4942     int tries;                          /* How many times we've tried... */
4943     struct stat devbuf;                 /* For device numbers (SVR4). */
4944
4945 #ifdef PIDSTRING
4946     char pid_str[32];                   /* My pid in string format. */
4947 #endif /* PIDSTRING */
4948
4949     char *device, *devname;
4950
4951 #define LFNAML 256                      /* Max length for lock file name. */
4952     char lockfil[LFNAML];               /* Lock file name */
4953 #ifdef RTAIX
4954     char lklockf[LFNAML];               /* Name for link to lock file  */
4955 #endif /* RTAIX */
4956 #ifdef CKSYMLINK
4957     char symlock[LFNAML];               /* Name for symlink lockfile name */
4958 #endif /* CKSYMLINK */
4959     char tmpnam[LFNAML+30];             /* Temporary lockfile name. */
4960     char *lockdir = LOCK_DIR;           /* Defined near top of this file, */
4961                                         /* or on cc command line. */
4962     haslock = 0;                        /* Not locked yet. */
4963     *flfnam = '\0';                     /* Lockfile name is empty. */
4964     lock2[0] = '\0';                    /* Clear secondary lockfile name. */
4965     pid = getpid();                     /* Get id of this process. */
4966
4967 /*  Construct name of lockfile and temporary file */
4968
4969 /*  device  = name of tty device without the path, e.g. "ttyh8" */
4970 /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
4971
4972     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
4973
4974     if (stat(ttdev,&devbuf) < 0)
4975       return(-1);
4976
4977 #ifdef CKSYMLINK
4978     islink = 1;                         /* Assume it's a symlink */
4979     linkto[0] = '\0';                   /* But we don't know to what */
4980 #ifdef COMMENT
4981 /*
4982   This is undependable.  If it worked it would save the readlink call if
4983   we knew the device name was not a link.
4984 */
4985 #ifdef S_ISLNK
4986     islink = S_ISLNK(devbuf.st_mode);
4987     debug(F101,"ttlock stat S_ISLNK","",islink);
4988 #endif /* S_ISLNK */
4989 #endif /* COMMENT */
4990     if (islink) {
4991         n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
4992         debug(F111,"ttlock readlink",ttdev,n);
4993         if (n > -1)                     /* It is */
4994           linkto[n] = '\0';
4995         else                            /* It's not */
4996           islink = 0;
4997         debug(F111,"ttlock link",linkto,islink);
4998     }
4999     if (islink) {
5000         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5001         debug(F110,"ttlock linkdev",linkdev,0);
5002     }
5003 #endif /* CKSYMLINK */
5004
5005 /*
5006   On SCO platforms, if we don't have a symlink, then let's pretend the
5007   name given for the device is a symlink, because later we will change
5008   the name if it contains any uppercase characters.
5009 */
5010 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5011     if (!islink) {
5012         islink = 1;
5013         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5014         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5015         debug(F110,"ttlock linkdev",linkdev,0);
5016     }
5017 #else
5018 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5019     if (!islink) {
5020         islink = 1;
5021         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5022         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5023         debug(F110,"ttlock linkdev",linkdev,0);
5024     }
5025 #endif /* M_XENIX */
5026 #endif /* CK_SCOV5 */
5027
5028 #ifdef ISIII                            /* Interactive System III, PC/IX */
5029     ckstrncpy(lockfil, device, DEVNAMLEN);
5030 #else  /* not ISIII */
5031 #ifdef LFDEVNO                          /* Lockfilename has device numbers. */
5032 #ifdef COHERENT
5033     sprintf(lockfil,"LCK..%d.%d",       /* SAFE */
5034             major(devbuf.st_rdev),         /* major device number */
5035             0x1f & minor(devbuf.st_rdev)); /* minor device number */
5036 #else
5037     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
5038     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
5039     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
5040             major(devbuf.st_dev),       /* device */
5041             major(devbuf.st_rdev),      /* major device number */
5042             minor(devbuf.st_rdev));     /* minor device number */
5043 #endif /* COHERENT */
5044 #else  /* Not LFDEVNO */
5045 #ifdef PTX                              /* Dynix PTX */
5046     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
5047         if ((int)strlen(device) + 8 < LFNAML)
5048           sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
5049         else
5050           ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5051     } else
5052 #endif /* PTX */
5053       if ((int)strlen(device) + 5 < LFNAML)
5054         sprintf(lockfil,"LCK..%s", device);
5055       else
5056         ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5057 #ifdef RTAIX
5058     ckstrncpy(lklockf,device,DEVNAMLEN);
5059 #endif /* RTAIX */
5060 #ifdef CKSYMLINK
5061     symlock[0] = '\0';
5062     if (islink)
5063       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
5064 #endif /* CKSYMLINK */
5065 #endif /* LFDEVNO */
5066 #endif /* ISIII */
5067
5068 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5069     {
5070         /* Lowercase the entire filename. */
5071         /* SCO says we must do this in V5.0 and later. */
5072         /* BUT... watch out for devices -- like Digiboard Portserver */
5073         /* That can have hundreds of ports... */
5074         char *p = (char *)(lockfil + 5);
5075         while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
5076     }
5077 #ifdef CKSYMLINK
5078     if (islink) {                       /* If no change */
5079         if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
5080             islink = 0;
5081             symlock[0] = '\0';
5082         }
5083     }
5084 #endif /* CKSYMLINK */
5085 #else
5086 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5087     {
5088         int x; char c;
5089         x = (int)strlen(lockfil) - 1;   /* Get last letter of device name. */
5090         if (x > 0) {                    /* If it's uppercase, lower it. */
5091             c = lockfil[x];
5092             if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
5093         }
5094     }
5095 #ifdef CKSYMLINK
5096     if (islink) {
5097         if (!strcmp(lockfil,symlock)) { /* No change */
5098             islink = 0;                 /* so no second lockfile */
5099             symlock[0] = '\0';
5100         }
5101     }
5102 #endif /* CKSYMLINK */
5103 #endif /* M_XENIX */
5104 #endif /* CK_SCOV5 */
5105
5106 /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
5107 /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
5108
5109     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
5110
5111 #ifdef RTAIX
5112     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
5113 #endif /* RTAIX */
5114
5115 #ifndef LFDEVNO
5116 #ifdef CKSYMLINK
5117     /* If it's a link then also make a lockfile for the real name */
5118     debug(F111,"ttlock link symlock",symlock,islink);
5119     if (islink && symlock[0]) {
5120         /* But only if the lockfile names would be different. */
5121         /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
5122         ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
5123         debug(F110,"ttlock lock2",lock2,0);
5124         if (!strcmp(lock2,flfnam)) {    /* Are lockfile names the same? */
5125             debug(F100,"ttlock lock2 cleared","",0);
5126             lock2[0] = '\0';            /* Clear secondary lockfile name. */
5127         }
5128     }
5129 #endif /* CKSYMLINK */
5130 #endif /* LFDEVNO */
5131
5132     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
5133     debug(F110,"ttlock flfnam",flfnam,0);
5134     debug(F110,"ttlock tmpnam",tmpnam,0);
5135
5136     priv_on();                          /* Turn on privileges if possible. */
5137     lockfd = creat(tmpnam, 0444);       /* Try to create temp lock file. */
5138     if (lockfd < 0) {                   /* Create failed. */
5139         debug(F111,"ttlock creat failed",tmpnam,errno);
5140         if (errno == ENOENT) {
5141             perror(lockdir);
5142             printf("UUCP not installed or Kermit misconfigured\n");
5143         } else {
5144             if (!quiet)
5145               perror(lockdir);
5146             unlink(tmpnam);             /* Get rid of the temporary file. */
5147         }
5148         priv_off();                     /* Turn off privileges!!! */
5149         return(-1);                     /* Return failure code. */
5150     }
5151 /* Now write the pid into the temp lockfile in the appropriate format */
5152
5153 #ifdef PIDSTRING                        /* For Honey DanBer UUCP, */
5154     sprintf(                            /* write PID as decimal string */
5155             pid_str,
5156 #ifdef LINUXFSSTND                      /* The "Linux File System Standard" */
5157 #ifdef FSSTND10                         /* Version 1.0 calls for */
5158             "%010d\n",                  /* leading zeros */
5159 #else                                   /* while version 1.2 calls for */
5160             "%10d\n",                   /* leading spaces */
5161 #endif /* FSSTND10 */
5162 #else
5163 #ifdef COHERENT
5164             "%d\n",                     /* with leading nothing */
5165 #else
5166             "%10d\n",                   /* with leading blanks */
5167 #endif /* COHERENT */
5168 #endif /* LINUXFSSTND */
5169             (int) pid
5170             );                          /* safe */
5171     write(lockfd, pid_str, 11);
5172     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
5173
5174 #else /* Not PIDSTRING, use integer PID */
5175
5176     write(lockfd, (char *)&pid, sizeof(pid) );
5177     debug(F101,"ttlock pid","",(int) pid);
5178
5179 #endif /* PIDSTRING */
5180
5181 /* Now try to rename the temp file to the real lock file name. */
5182 /* This will fail if a lock file of that name already exists.  */
5183
5184     close(lockfd);                      /* Close the temp lockfile. */
5185     chmod(tmpnam,0444);                 /* Permission for a valid lock. */
5186     tries = 0;
5187     while (!haslock && tries++ < 2) {
5188         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5189         if (haslock) {                        /* If we got the lockfile */
5190 #ifdef RTAIX
5191             link(flfnam,lkflfn);
5192 #endif /* RTAIX */
5193 #ifdef CKSYMLINK
5194 #ifndef LFDEVNO
5195             if (islink && lock2[0])
5196               link(flfnam,lock2);
5197 #endif /* LFDEVNO */
5198 #endif /* CKSYMLINK */
5199
5200 #ifdef COMMENT
5201 /* Can't do this any more because device is not open yet so no ttyfd. */
5202 #ifdef LOCKF
5203 /*
5204   Advisory file locking works on SVR4, so we use it.  In fact, it is
5205   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
5206   seem to prevent multiple users accessing the same device by different names.
5207 */
5208             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
5209                 debug(F111, "ttlock lockf returns errno", "", errno);
5210                 if ((++tries >= 3) || (errno != EAGAIN)) {
5211                     x = unlink(flfnam); /* remove the lockfile */
5212 #ifdef RTAIX
5213                     unlink(lkflfn);     /* And any links to it... */
5214 #endif /* RTAIX */
5215 #ifdef CKSYMLINK
5216 #ifndef LFDEVNO
5217                     if (islink && lock2[0])
5218                       unlink(lock2);    /* ditto... */
5219 #endif /* LFDEVNO */
5220 #endif /* CKSYMLINK */
5221                     debug(F111,"ttlock unlink",flfnam,x);
5222                     haslock = 0;
5223                     break;
5224                 }
5225                 sleep(2);
5226             }
5227             if (haslock)                /* If we got an advisory lock */
5228 #endif /* LOCKF */
5229 #endif /* COMMENT */
5230               break;                    /* We're done. */
5231
5232         } else {                        /* We didn't create a new lockfile. */
5233             priv_off();
5234             if (ttchkpid(flfnam)) {     /* Check existing lockfile */
5235                 priv_on();              /* cause ttchkpid turns priv_off... */
5236                 unlink(tmpnam);         /* Delete the tempfile */
5237                 debug(F100,"ttlock found tty locked","",0);
5238                 priv_off();             /* Turn off privs */
5239                 return(-2);             /* Code for device is in use. */
5240             }
5241             priv_on();
5242         }
5243     }
5244     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5245     priv_off();                         /* Turn off privs */
5246     return(haslock ? 0 : -1);           /* Return link's return code. */
5247
5248 #else /* HPUX */
5249
5250 /*
5251   HP-UX gets its own copy of this routine, modeled after the observed behavior
5252   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
5253   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
5254   designator which is a string of digits, possibly containing an imbedded
5255   letter "p".  Examples (for base name "tty"):
5256
5257      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
5258
5259   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
5260   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
5261   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
5262   However, we make and enforce no such distinctions; either notation is
5263   accepted on any model or HP-UX version as a valid unit designator.
5264
5265   If a valid unit is specified (as opposed to a designer name or symlink), we
5266   check for all aliases of the given unit according to the devprefix[] array.
5267   If no lockfiles are found for the given unit, we can have the device; we
5268   create a lockfile LCK..name in the lockfile directory appropriate for the
5269   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
5270   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
5271   created with the "ttyd" prefix.  This is exactly what cu does.
5272
5273   If the "set line" device does not have a valid unit designator, then it is
5274   used literally and no synomyms are searched for and only one lockfile is
5275   created.
5276
5277   -fdc, March 1998.
5278 */
5279 #define LFNAML 80                       /* Max length for lock file name. */
5280
5281     int lockfd;                         /* File descriptor for lock file. */
5282     PID_T pid;                          /* Process ID of this process. */
5283     int fpid;                           /* pid found in existing lockfile. */
5284     int tries;                          /* How many times we've tried... */
5285     int i, k;                           /* Workers */
5286
5287     char *device, *devname;             /* "/dev/xxx", "xxx" */
5288     char *unit, *p;                     /* <instance>p<port> part of xxx */
5289
5290     char lockfil[LFNAML];               /* Lockfile name (no path) */
5291     char tmpnam[LFNAML];                /* Temporary lockfile name. */
5292
5293 #ifdef HPUX10                           /* Lockfile directory */
5294     char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
5295 #else  /* HP-UX 9.xx and below */
5296 #ifdef LOCK_DIR
5297     char *lockdir = LOCK_DIR;           /* Defined near top of this file */
5298 #else
5299     char *lockdir = "/usr/spool/uucp";  /* or not... */
5300 #endif /* LOCK_DIR */
5301 #endif /* HPUX10 */
5302
5303     haslock = 0;                        /* Not locked yet. */
5304     *flfnam = '\0';                     /* Lockfile name is empty. */
5305     lock2[0] = '\0';                    /* Second one too. */
5306     pid = getpid();                     /* Get my process ID */
5307 /*
5308   Construct name of lockfile and temporary file...
5309   device  = name of tty device without the path, e.g. "tty0p0"
5310   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
5311 */
5312     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5313     debug(F110,"TTLOCK device",device,0);
5314     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
5315
5316     k = 0;                              /* Assume device is not locked */
5317     n = 0;                              /* Digit counter */
5318     unit = device;                      /* Unit = <instance>p<port> */
5319     while (*unit && !isdigit(*unit))    /* Search for digit... */
5320       unit++;
5321     p = unit;                           /* Verify <num>p<num> format... */
5322     debug(F110,"TTLOCK unit 1",unit,0);
5323 /*
5324   The unit number is recognized as:
5325   (a) any sequence of digits that runs to the end of the string.
5326   (b) any (a) that includes one and only one letter "p", with at least
5327       one digit before and after it.
5328 */
5329     while (isdigit(*p)) p++, n++;       /* Get a run of digits */
5330     if (*p && n > 0) {                  /* Have a "p"? */
5331         if (*p == 'p' && isdigit(*(p+1))) {
5332             p++;
5333             n = 0;
5334             while (isdigit(*p)) p++, n++;
5335         }
5336     }
5337     if (n == 0 || *p) unit = "";
5338     debug(F110,"TTLOCK unit 2",unit,0);
5339
5340     if (*unit) {                        /* Device name has unit number. */
5341         /* The following loop not only searches for the various lockfile    */
5342         /* synonyms, but also removes all -- not just one -- stale lockfile */
5343         /* for the device, should there be more than one.  See ttchkpid().  */
5344         ttydexists = 0;
5345         for (i = 0; *devprefix[i]; i++) { /* For each driver... */
5346             /* Make device name */
5347             ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
5348             priv_on();                  /* Privs on */
5349             k = zchki(lock2) != -1;     /* See if device exists */
5350             priv_off();                 /* Privs off */
5351             debug(F111,"TTLOCK exist",lock2,k);
5352             if (k) {
5353                 if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
5354                   ttydexists = 1;
5355                 /* Make lockfile name */
5356                 ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
5357                 debug(F110,"TTLOCK checking",lock2,0);
5358                 priv_on();              /* Privs on */
5359                 k = zchki(lock2) != -1; /* See if lockfile exists */
5360                 priv_off();             /* Privs off */
5361                 debug(F111,"TTLOCK check for lock A",lock2,k);
5362                 if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
5363                     ckstrncpy(flfnam,lock2,FLFNAML);
5364                     return(-2);
5365                 }
5366             }
5367         }
5368     } else {                            /* Some other device-name format */
5369         /* This takes care of symbolic links, etc... */
5370         /* But does not chase them down! */
5371         ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
5372         priv_on();
5373         k = zchki(lock2) != -1;         /* Check for existing lockfile */
5374         priv_off();
5375         debug(F111,"TTLOCK check for lock B",lock2,k);
5376         if (k) if (ttchkpid(lock2)) {   /* Check pid from lockfile */
5377             ckstrncpy(flfnam,lock2,FLFNAML);
5378             debug(F110,"TTLOCK in use",device,0);
5379             debug(F101,"TTLOCK returns","",-2);
5380             return(-2);
5381         }
5382     }
5383 /*
5384   Get here only if there is no (more) lockfile, so now we make one (or two)...
5385   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
5386   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
5387 */
5388     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
5389
5390     /* If dialout device, also make one for corresponding dialin device */
5391     lock2[0] = '\0';
5392     if (!strncmp(device,"cu",2) && *unit && ttydexists)
5393       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
5394
5395     if ((int)strlen(lockdir)+12 < LFNAML)
5396       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
5397 #ifdef DEBUG
5398     if (deblog) {
5399         debug(F110,"TTLOCK flfnam",flfnam,0);
5400         debug(F110,"TTLOCK lock2",lock2,0);
5401         debug(F110,"TTLOCK tmpnam",tmpnam,0);
5402     }
5403 #endif /* DEBUG */
5404 /*
5405    Lockfile permissions...
5406    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
5407    Kermit uses 444; the difference lets us tell whether Kermit created
5408    the lock file.
5409 */
5410     priv_on();                          /* Turn on privileges. */
5411     lockfd = creat(tmpnam, 0444);       /* Try to create temporary file. */
5412     if (lockfd < 0) {                   /* Create failed. */
5413         debug(F111,"TTLOCK creat failed",tmpnam,errno);
5414         if (errno == ENOENT) {
5415             perror(lockdir);
5416             printf("UUCP not installed or Kermit misconfigured\n");
5417         } else {
5418             if (!quiet)
5419               perror(lockdir);
5420             unlink(tmpnam);             /* Get rid of the temporary file. */
5421         }
5422         priv_off();                     /* Turn off privileges!!! */
5423         debug(F101,"TTLOCK returns","",-1);
5424         return(-1);                     /* Return failure code. */
5425     }
5426     debug(F110,"TTLOCK temp ok",tmpnam,0);
5427
5428 /* Now write our pid into the temp lockfile in integer format. */
5429
5430     i = write(lockfd, (char *)&pid, sizeof(pid));
5431
5432 #ifdef DEBUG
5433     if (deblog) {
5434         debug(F101,"TTLOCK pid","",pid);
5435         debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
5436         debug(F101,"TTLOCK write pid returns","",i);
5437     }
5438 #endif /* DEBUG */
5439
5440 /*
5441   Now try to rename the temporary file to the real lockfile name.
5442   This will fail if a lock file of that name already exists, which
5443   will catch race conditions with other users.
5444 */
5445     close(lockfd);                      /* Close the temp lockfile. */
5446     chmod(tmpnam,0444);
5447
5448     tries = 0;
5449     while (!haslock && tries++ < 2) {
5450         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5451         debug(F101,"TTLOCK link","",haslock);
5452         if (haslock) {                  /* If we made the lockfile... */
5453
5454 #ifdef COMMENT
5455 /* We can't do this any more because we don't have a file descriptor yet. */
5456 #ifdef LOCKF                            /* Can be canceled with -DNOLOCKF */
5457 /*
5458   Create an advisory lock on the device through its file descriptor.
5459   This code actually seems to work.  If it is executed, and then another
5460   process tries to open the same device under a different name to circumvent
5461   the lockfile, they get a "device busy" error.
5462 */
5463             debug(F100,"TTLOCK LOCKF code...","",0);
5464             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
5465                 debug(F111, "TTLOCK lockf error", "", errno);
5466                 if ((++tries >= 3) || (errno != EAGAIN)) {
5467                     x = unlink(flfnam); /* Remove the lockfile */
5468                     if (errno == EACCES && !quiet)
5469                       printf("Device already locked by another process\n");
5470                     haslock = 0;
5471                     break;
5472                 }
5473                 sleep(2);
5474             }
5475 #endif /* LOCKF */
5476 #endif /* COMMENT */
5477
5478             if (haslock) {              /* If we made the lockfile ... */
5479                 if (lock2[0]) {         /* if there is to be a 2nd lockfile */
5480                     lockfd = creat(lock2, 0444); /* Create it */
5481                     debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
5482                     if (lockfd > -1) {  /* Created OK, write pid. */
5483                         write(lockfd, (char *)&pid, sizeof(pid) );
5484                         close(lockfd);  /* Close and */
5485                         chmod(lock2, 0444); /* set permissions. */
5486                     } else {             /* Not OK, but don't fail. */
5487                         lock2[0] = '\0'; /* Just remember it's not there. */
5488                     }
5489                 }
5490                 break;                  /* and we're done. */
5491             }
5492         }
5493     }
5494     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5495     priv_off();                         /* Turn off privs */
5496     i = haslock ? 0 : -1;               /* Our return value */
5497     debug(F101,"TTLOCK returns","",i);
5498     return(i);
5499 #endif /* HPUX */
5500 #endif /* USETTYLOCK */
5501 #endif /* !NOUUCP */
5502 }
5503
5504 /*  T T U N L O C K  */
5505
5506 static int
5507 ttunlck() {                             /* Remove UUCP lockfile(s). */
5508 #ifndef NOUUCP
5509     int x;
5510
5511     debug(F111,"ttunlck",flfnam,haslock);
5512
5513 #ifdef USETTYLOCK
5514
5515     if (haslock && *flfnam) {
5516         int x;
5517         priv_on();                      /* Turn on privs */
5518 #ifdef USE_UU_LOCK
5519         x = uu_unlock(lockname);
5520 #else  /* USE_UU_LOCK */
5521         x = ttyunlock(lockname);        /* Try to unlock */
5522 #endif /* USE_UU_LOCK */
5523         priv_off();                     /* Turn off privs */
5524         if (x < 0 && !quiet)
5525           printf("Warning - Can't remove lockfile: %s\n", flfnam);
5526
5527         *flfnam = '\0';                 /* Erase the name. */
5528         haslock = 0;
5529         return(0);
5530     }
5531
5532 #else  /* No ttylock()... */
5533
5534     if (haslock && *flfnam) {
5535         /* Don't remove lockfile if we didn't make it ourselves */
5536         if ((x = ttrpid(flfnam)) != (int)getpid()) {
5537             debug(F111,"ttunlck lockfile seized",flfnam,x);
5538             printf("Warning - Lockfile %s seized by pid %d\n",
5539                    flfnam,
5540                    x
5541                    );
5542             return(0);
5543         }
5544         priv_on();                      /* Turn privileges on.  */
5545         errno = 0;
5546         x = unlink(flfnam);             /* Remove the lockfile. */
5547         debug(F111,"ttunlck unlink",flfnam,x);
5548         if (x < 0) {
5549             if (errno && !quiet)
5550               perror(ttnmsv);
5551             printf("Warning - Can't remove lockfile: %s\n", flfnam);
5552         }
5553         haslock = 0;
5554         *flfnam = '\0';                 /* Erase the name. */
5555
5556 #ifdef RTAIX
5557         errno = 0;
5558         x = unlink(lkflfn);             /* Remove link to lockfile */
5559         debug(F111,"ttunlck AIX link unlink",lkflfn,x);
5560         if (x < 0) {
5561             if (errno && !quiet)
5562               perror(ttnmsv);
5563             printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
5564         }
5565         *lkflfn = '\0';
5566 #else
5567         if (lock2[0]) {                 /* If there is a second lockfile, */
5568             errno = 0;
5569             x = unlink(lock2);          /*  remove it too. */
5570             debug(F111,"ttunlck lock2 unlink",lock2,x);
5571             if (x < 0) {
5572                 if (errno && !quiet)
5573                   perror(ttnmsv);
5574                 printf("Warning - Can't remove secondary lockfile: %s\n",
5575                        lock2
5576                        );
5577             }
5578             lock2[0] = '\0';            /* Forget its name. */
5579         }
5580 #endif /* RTAIX */
5581
5582 #ifdef COMMENT
5583 #ifdef LOCKF
5584         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
5585 #endif /* LOCKF */
5586 #endif /* COMMENT */
5587
5588         priv_off();                     /* Turn privileges off. */
5589     }
5590 #endif /* USETTYLOCK */
5591 #endif /* !NOUUCP */
5592     return(0);
5593 }
5594
5595 /*
5596   4.3BSD-style UUCP line direction control.
5597   (Stan Barber, Rice U, 1980-something...)
5598 */
5599 #ifndef NOUUCP
5600 #ifdef ACUCNTRL
5601 VOID
5602 acucntrl(flag,ttname) char *flag, *ttname; {
5603     char x[DEVNAMLEN+32], *device, *devname;
5604
5605     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
5606       return;                           /* just return. */
5607     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
5608     if (strncmp(device,"LCK..",4) == 0) device += 5;
5609     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
5610     debug(F110,"called ",x,0);
5611     zsyscmd(x);
5612 }
5613 #endif /* ACUCNTRL */
5614 #endif /* NOUUCP */
5615
5616 /*
5617   T T H F L O W  --  Set or Reset hardware flow control.
5618
5619   This is an attempt to collect all hardware-flow-control related code
5620   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
5621   help here.  Overview:
5622
5623   Hardware flow control is not supported in many UNIX implementions.  Even
5624   when it is supported, there is no (ha ha) "standard" for the programming
5625   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
5626   SunOS, AIX, etc, have totally different methods.  (And, not strictly
5627   relevant here, the programming interface often brings one only to a no-op
5628   in the device driver!)
5629
5630   Among all these, we have two major types of APIs: those in which hardware
5631   flow control is determined by bits in the same termio/termios/sgtty mode
5632   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
5633   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
5634   for changing terminal modes.  And those that use entirely different
5635   mechanisms.
5636
5637   In the first category, it is important that any change in the mode bits be
5638   reflected in the relevant termio(s)/sgtty structure, so that subsequent
5639   changes to that structure do not wipe out the effects of this routine.  That
5640   is why a pointer, attrs, to the appropriate structure is passed as a
5641   parameter to this routine.
5642
5643   The second category should give us no worries, since any changes to hardware
5644   flow control accomplished by this routine should not affect the termio(s)/
5645   sgtty structures, and therefore will not be undone by later changes to them.
5646
5647   The second argument, status, means to turn on hardware flow control if
5648   nonzero, and to turn it off if zero.
5649
5650   Returns: 0 on apparent success, -1 on probable failure.
5651 */
5652
5653 /*
5654   The following business is for BSDI, where it was discovered that two
5655   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
5656   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
5657   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
5658   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
5659   define CRTSCTS correctly.
5660 */
5661 #ifdef FIXCRTSCTS
5662 #ifdef CRTSCTS
5663 #ifdef CCTS_OFLOW
5664 #ifdef CRTS_IFLOW
5665 #undef CRTSCTS
5666 #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
5667 #endif /* CRTS_IFLOW */
5668 #endif /* CCTS_OFLOW */
5669 #endif /* CRTSCTS */
5670 #endif /* FIXCRTSCTS */
5671
5672 static int
5673 tthflow(flow, status, attrs)
5674     int flow,                           /* Type of flow control (ckcdeb.h) */
5675     status;                             /* Nonzero = turn it on */
5676                                         /* Zero = turn it off */
5677 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
5678     struct termios *attrs;
5679 #else                                   /* System V */
5680 #ifdef ATTSV
5681 #ifdef ATT7300
5682 #ifdef UNIX351M
5683 /* AT&T UNIX 3.51m can set but not test for hardware flow control */
5684 #define RTSFLOW CTSCD
5685 #define CTSFLOW CTSCD
5686 #endif /* ATT7300 */
5687 #endif /* UNIX351M */
5688     struct termio *attrs;
5689 #else                                   /* BSD, V7, etc */
5690     struct sgttyb *attrs;               /* sgtty info... */
5691 #endif /* ATTSV */
5692 #endif /* BSD44ORPOSIX */
5693 /* tthflow */ {
5694
5695     int x = 0;                          /* tthflow() return code */
5696
5697 #ifdef Plan9
5698     return p9tthflow(flow, status);
5699 #else
5700
5701 #ifndef OXOS                            /* NOT Olivetti X/OS... */
5702 /*
5703   For SunOS 4.0 and later in the BSD environment ...
5704
5705   The declarations are copied and interpreted from the System V header files,
5706   so we don't actually have to pull in all the System V junk when building
5707   C-Kermit for SunOS in the BSD environment, which would be dangerous because
5708   having those symbols defined would cause us to take the wrong paths through
5709   the code.  The code in this section is used in both the BSD and Sys V SunOS
5710   versions.
5711 */
5712 #ifdef SUNOS41
5713 /*
5714   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
5715   because GNU CC uses different formats for the _IOxxx macros than regular CC;
5716   the POSIX forms work for both.  But the POSIX calls are not available in
5717   SunOS 4.0.
5718 */
5719 #define CRTSCTS 0x80000000              /* RTS/CTS flow control */
5720 #define TCSANOW 0                       /* Do it now */
5721
5722     struct termios {
5723         unsigned long c_iflag;          /* Input modes */
5724         unsigned long c_oflag;          /* Output modes */
5725         unsigned long c_cflag;          /* Control modes */
5726         unsigned long c_lflag;          /* Line discipline modes */
5727         char c_line;
5728         CHAR c_cc[17];
5729     };
5730     struct termios temp;
5731
5732 _PROTOTYP( int tcgetattr, (int, struct termios *) );
5733 _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
5734 /*
5735   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
5736   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
5737   since we don't need RTS/CTS during dialing, and after dialing is complete,
5738   we should have CD.  If not, we still communicate, but without RTS/CTS.
5739 */
5740     int mflags;                         /* Modem signal flags */
5741
5742 #ifdef NETCMD
5743     if (ttpipe) return(0);
5744 #endif /* NETCMD */
5745 #ifdef NETPTY
5746     if (ttpty) return(0);
5747 #endif /* NETPTY */
5748
5749     debug(F101,"tthflow SUNOS41 entry status","",status);
5750     if (!status) {                      /* Turn hard flow off */
5751         if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5752             (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5753             temp.c_cflag &= ~CRTSCTS;   /* It's there, remove it */
5754             x = tcsetattr(ttyfd,TCSANOW,&temp);
5755         }
5756     } else {                            /* Turn hard flow on */
5757         if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
5758             (mflags & TIOCM_CAR)) {             /* Check for CD */
5759             debug(F100,"tthflow SunOS has CD","",0);
5760             if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5761                 !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5762                 temp.c_cflag |= CRTSCTS;        /* Not there, add it */
5763                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5764             }
5765         } else {
5766             x = -1;
5767             debug(F100,"tthflow SunOS no CD","",0);
5768         }
5769     }
5770 #else
5771 #ifdef QNX
5772     struct termios temp;
5773 #ifdef NETCMD
5774     if (ttpipe) return(0);
5775 #endif /* NETCMD */
5776 #ifdef NETPTY
5777     if (ttpty) return(0);
5778 #endif /* NETPTY */
5779     debug(F101,"tthflow QNX entry status","",status);
5780     if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
5781         if (!status) {                  /* Turn hard flow off */
5782             if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
5783                 temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
5784                 attrs->c_cflag &= ~(IHFLOW|OHFLOW);
5785                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5786             }
5787         } else {                        /* Turn hard flow on */
5788             if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
5789                 temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
5790                 temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
5791                 ttraw.c_lflag |= IEXTEN;         /* Must be on */
5792                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5793                 attrs->c_cflag |= (IHFLOW|OHFLOW);
5794                 attrs->c_iflag &= ~(IXON|IXOFF);
5795             }
5796         }
5797     } else {
5798         x = -1;
5799         debug(F100, "tthflow QNX getattr fails", "", 0);
5800     }
5801 #else
5802 #ifdef POSIX_CRTSCTS
5803 /*
5804   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
5805   Note: Do not assume CRTSCTS is a one-bit field!
5806 */
5807     struct termios temp;
5808 #ifdef NETCMD
5809     if (ttpipe) return(0);
5810 #endif /* NETCMD */
5811 #ifdef NETPTY
5812     if (ttpty) return(0);
5813 #endif /* NETPTY */
5814     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
5815     errno = 0;
5816     x = tcgetattr(ttyfd, &temp);
5817     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
5818     errno = 0;
5819     if (x < 0) {
5820         x = -1;
5821     } else {
5822         if (!status) {                  /* Turn hard flow off */
5823             if (
5824 #ifdef COMMENT
5825                 /* This can fail because of sign extension */
5826                 /* e.g. in Linux where it's Bit 31 */
5827                 (temp.c_cflag & CRTSCTS) == CRTSCTS
5828 #else
5829                 (temp.c_cflag & CRTSCTS) != 0
5830 #endif /* COMMENT */
5831                 ) {
5832                 temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
5833                 attrs->c_cflag &= ~CRTSCTS;
5834                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5835                 debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
5836                       ckitoa(x),errno);
5837             }
5838         } else {                        /* Turn hard flow on */
5839             if (
5840 #ifdef COMMENT
5841                 /* This can fail because of sign extension */
5842                 (temp.c_cflag & CRTSCTS) != CRTSCTS
5843 #else
5844                 (temp.c_cflag & CRTSCTS) == 0
5845 #endif /* COMMENT */
5846                 ) {
5847                 temp.c_cflag |= CRTSCTS; /* Not there, add it */
5848                 temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
5849                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5850                 debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
5851                       ckitoa(x),errno);
5852                 attrs->c_cflag |= CRTSCTS;
5853                 attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5854             }
5855         }
5856     }
5857 #else
5858 #ifdef SUNOS4
5859 /*
5860   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
5861   prevents compilation with GNU gcc, which uses different formats for the
5862   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
5863   routines above, which work for both cc and gcc.
5864 */
5865 #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
5866 #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
5867 #define CRTSCTS 0x80000000                /* RTS/CTS flow control */
5868
5869     struct termios {
5870         unsigned long c_iflag;          /* Input modes */
5871         unsigned long c_oflag;          /* Output modes */
5872         unsigned long c_cflag;          /* Control modes */
5873         unsigned long c_lflag;          /* Line discipline modes */
5874         char c_line;
5875         CHAR c_cc[17];
5876     };
5877     struct termios temp;
5878 #ifdef NETCMD
5879     if (ttpipe) return(0);
5880 #endif /* NETCMD */
5881 #ifdef NETPTY
5882     if (ttpty) return(0);
5883 #endif /* NETPTY */
5884     debug(F101,"tthflow entry status","",status);
5885     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
5886         if (status) {                   /* Turn hard flow on */
5887             temp.c_cflag |= CRTSCTS;    /* Add RTS/CTS to them. */
5888             x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
5889             attrs->c_cflag |= CRTSCTS;  /* Add to global info. */
5890         } else {                        /* Turn hard flow off */
5891             temp.c_cflag &= ~CRTSCTS;
5892             x = ioctl(ttyfd,TCSETS,&temp);
5893             attrs->c_cflag &= ~CRTSCTS;
5894         }
5895     }
5896 #else                                   /* Not SunOS 4.0 or later */
5897 #ifdef AIXRS                            /* IBM AIX RS/6000 */
5898 #ifndef AIX41                           /* But only pre-4.x == SVR4 */
5899 #ifdef NETCMD
5900     if (ttpipe) return(0);
5901 #endif /* NETCMD */
5902 #ifdef NETPTY
5903     if (ttpty) return(0);
5904 #endif /* NETPTY */
5905     if (status) {
5906         if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
5907           debug(F100,"hardflow TXADDCD (rts) error", "", 0);
5908     } else {
5909         if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
5910           debug(F100,"hardflow TXDELCD (rts) error", "", 0);
5911     }
5912 #endif /* AIX41 */
5913 #else                                   /* Not AIX RS/6000 */
5914
5915 #ifdef ATTSV                            /* System V... */
5916
5917 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5918 #define CK_SCOUNIX
5919 #else
5920 #ifdef M_UNIX                           /* SCO UNIX 3.2v4.x or earlier */
5921 #define CK_SCOUNIX
5922 #endif /* M_UNIX */
5923 #endif /* CK_SCOV5 */
5924
5925 #ifdef SCO_FORCE_RTSXOFF
5926 #ifdef CK_SCOUNIX                       /* But not SCO OpenServer 5.0.4 */
5927 #ifdef SCO_OSR504                       /* or later... */
5928 #undef CK_SCOUNIX
5929 #endif /* SCO_OSR504 */
5930 #endif /* CK_SCOUNIX */
5931 #endif /* SCO_FORCE_RTSXOFF */
5932
5933 #ifdef CK_SCOUNIX
5934 #ifdef POSIX
5935     struct termios temp;
5936 #ifdef NETCMD
5937     if (ttpipe) return(0);
5938 #endif /* NETCMD */
5939 #ifdef NETPTY
5940     if (ttpty) return(0);
5941 #endif /* NETPTY */
5942     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
5943     errno = 0;
5944     x = tcgetattr(ttyfd, &temp);
5945     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
5946 #else /* POSIX */
5947     struct termio temp;
5948 #ifdef NETCMD
5949     if (ttpipe) return(0);
5950 #endif /* NETCMD */
5951 #ifdef NETPTY
5952     if (ttpty) return(0);
5953 #endif /* NETPTY */
5954     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
5955     x = ioctl(ttyfd, TCGETA, &temp);
5956     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
5957 #endif /* POSIX */
5958 /*
5959   This is not really POSIX, since POSIX does not deal with hardware flow
5960   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
5961   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
5962   let's try forcing their definitions here.
5963 */
5964 #ifndef CTSFLOW
5965 #define CTSFLOW 0020000
5966     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
5967 #else
5968     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
5969 #endif /* CTSFLOW */
5970 #ifndef RTSFLOW
5971 #define RTSFLOW 0040000
5972     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
5973 #else
5974     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
5975 #endif /* RTSFLOW */
5976 #ifndef ORTSFL
5977 #define ORTSFL 0100000
5978     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
5979 #else
5980     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
5981 #endif /* ORTSFL */
5982
5983     if (x != -1) {
5984         if (status) {                   /* Turn it ON */
5985             temp.c_cflag |= RTSFLOW|CTSFLOW;
5986             attrs->c_cflag |= RTSFLOW|CTSFLOW;
5987 #ifdef ORTSFL
5988             temp.c_cflag &= ~ORTSFL;
5989             attrs->c_cflag &= ~ORTSFL;
5990 #endif /* ORTSFL */
5991             temp.c_iflag &= ~(IXON|IXOFF|IXANY);
5992             attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5993         } else {                        /* Turn it OFF */
5994 #ifdef ORTSFL
5995             temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
5996             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
5997 #else  /* ORTSFL */
5998             temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
5999             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
6000 #endif /* ORTSFL */
6001         }
6002 #ifdef POSIX
6003         x = tcsetattr(ttyfd, TCSADRAIN, &temp);
6004 #else
6005         x = ioctl(ttyfd, TCSETA, &temp);
6006 #endif /* POSIX */
6007         debug(F101,"tthflow SCO set modes","",x);
6008     }
6009 #else /* Not SCO UNIX */
6010 #ifdef NETCMD
6011     if (ttpipe) return(0);
6012 #endif /* NETCMD */
6013 #ifdef NETPTY
6014     if (ttpty) return(0);
6015 #endif /* NETPTY */
6016     if (!status) {                      /* Turn it OFF */
6017 #ifdef RTSXOFF
6018         debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
6019         rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
6020 #ifdef TCSETX
6021         x = ioctl(ttyfd,TCSETX,&rctsx);
6022         debug(F101,"tthflow ATTSV TCSETX OFF","",x);
6023 #else
6024         x = -1
6025         debug(F100,"tthflow TCSETX not defined","",0);
6026 #endif /* TCSETX */
6027 #else
6028         debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
6029 #endif /* RTSXOFF */
6030 #ifdef DTRXOFF
6031         debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
6032         rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6033         x = ioctl(ttyfd,TCSETX,&rctsx);
6034         debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
6035 #else
6036         debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6037 #endif /* DTRXOFF */
6038     } else {                            /* Turn it ON. */
6039         if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
6040             debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
6041 #ifdef RTSXOFF
6042             /* This is the preferred way, according to SVID3 */
6043 #ifdef TCGETX
6044             x = ioctl(ttyfd,TCGETX,&rctsx);
6045             debug(F101,"tthflow TCGETX","",x);
6046             if (x > -1) {
6047                 rctsx.x_hflag |= RTSXOFF | CTSXON;
6048                 x = ioctl(ttyfd,TCSETX,&rctsx);
6049                 debug(F100,"tthflow ATTSV ioctl","",x);
6050             }
6051 #else
6052             debug(F100,"tthflow TCGETX not defined","",0);
6053             x = -1
6054 #endif /* TCGETX */
6055 #else
6056             debug(F100,"tthflow RTSXOFF not defined","",0);
6057             x = -1;
6058 #endif /* RTSXOFF */
6059         } else if (flow == FLO_DTRC) {  /* DTR/CD Flow control... */
6060             debug(F100,"tthflow ATTSV DTR/CD ON","",0);
6061 #ifdef DTRXOFF
6062             /* This is straight out of SVID R4 */
6063             if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
6064                 rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6065                 x = ioctl(ttyfd,TCSETX,&rctsx);
6066             }
6067 #else
6068             debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6069             x = -1;
6070 #endif /* DTRXOFF */
6071         }
6072     }
6073 #endif /* CK_SCOUNIX */
6074
6075 #else /* not System V... */
6076
6077 #ifdef CK_DTRCTS
6078 #ifdef LDODTR
6079 #ifdef LDOCTS
6080 #ifdef NETCMD
6081     if (ttpipe) return(0);
6082 #endif /* NETCMD */
6083 #ifdef NETPTY
6084     if (ttpty) return(0);
6085 #endif /* NETPTY */
6086     x = LDODTR | LDOCTS;                /* Found only on UTEK? */
6087     if (flow == FLO_DTRT && status) {   /* Use hardware flow control */
6088         if (lmodef) {
6089             x = ioctl(ttyfd,TIOCLBIS,&x);
6090             if (x < 0) {
6091                 debug(F100,"hardflow TIOCLBIS error","",0);
6092             } else {
6093                 lmodef++;
6094                 debug(F100,"hardflow TIOCLBIS ok","",0);
6095             }
6096         }
6097     } else {
6098         if (lmodef) {
6099             x = ioctl(ttyfd,TIOCLBIC,&x);
6100             if (x < 0) {
6101                 debug(F100,"hardflow TIOCLBIC error","",0);
6102             } else {
6103                 lmodef++;
6104                 debug(F100,"hardflow TIOCLBIC ok","",0);
6105             }
6106         }
6107     }
6108 #endif /* LDODTR */
6109 #endif /* LDOCTS */
6110 #endif /* CK_DTRCTS */
6111 #endif /* ATTSV */
6112 #endif /* AIXRS */
6113 #endif /* SUNOS4 */
6114 #endif /* QNX */
6115 #endif /* POSIX_CRTSCTS */
6116 #endif /* SUNOS41 */
6117
6118 #else /* OXOS */
6119
6120     struct termios temp;                /* Olivetti X/OS ... */
6121
6122 #ifdef NETCMD
6123     if (ttpipe) return(0);
6124 #endif /* NETCMD */
6125 #ifdef NETPTY
6126     if (ttpty) return(0);
6127 #endif /* NETPTY */
6128     x = ioctl(ttyfd,TCGETS,&temp);
6129     if (x == 0) {
6130         temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
6131         if (status) {
6132             switch (flow) {
6133               case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
6134                 break;
6135               case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
6136                 break;
6137             }
6138         }
6139         x = ioctl(ttyfd,TCSETS,&temp);
6140     }
6141 #endif /* OXOS */
6142     return(x);
6143
6144 #endif /* Plan9 */
6145 }
6146
6147 /*  T T P K T  --  Condition the communication line for packets */
6148 /*                 or for modem dialing */
6149
6150 /*
6151   If called with speed > -1, also set the speed.
6152   Returns 0 on success, -1 on failure.
6153
6154   NOTE: the "xflow" parameter is supposed to be the currently selected
6155   type of flow control, but for historical reasons, this parameter is also
6156   used to indicate that we are dialing.  Therefore, when the true flow
6157   control setting is needed, we access the external variable "flow", rather
6158   than trusting our "xflow" argument.
6159 */
6160 int
6161 #ifdef CK_ANSIC
6162 ttpkt(long speed, int xflow, int parity)
6163 #else
6164 ttpkt(speed,xflow,parity) long speed; int xflow, parity;
6165 #endif /* CK_ANSIC */
6166 /* ttpkt */ {
6167 #ifndef NOLOCAL
6168     int s2;
6169     int s = -1;
6170 #endif /* NOLOCAL */
6171     int x;
6172     extern int flow;                    /* REAL flow-control setting */
6173
6174     if (ttyfd < 0) return(-1);          /* Not open. */
6175
6176     debug(F101,"ttpkt parity","",parity);
6177     debug(F101,"ttpkt xflow","",xflow);
6178     debug(F101,"ttpkt speed","",(int) speed);
6179
6180     ttprty = parity;                    /* Let other tt functions see these. */
6181     ttspeed = speed;                    /* Make global copy for this module */
6182     ttpmsk = ttprty ? 0177 : 0377;      /* Parity stripping mask */
6183 #ifdef PARSENSE
6184     needpchk = ttprty ? 0 : 1;          /* Parity check needed? */
6185 #else
6186     needpchk = 0;
6187 #endif /* PARSENSE */
6188
6189     debug(F101,"ttpkt ttpmsk","",ttpmsk);
6190     debug(F101,"ttpkt netconn","",netconn);
6191
6192 #ifdef NETCONN                          /* No mode-changing for telnet */
6193     if (netconn) {
6194 #ifdef TCPSOCKET
6195 #ifdef TCP_NODELAY
6196         if (ttnet == NET_TCPB) {        /* But turn off Nagle */
6197             extern int tcp_nodelay;
6198             nodelay_sav = tcp_nodelay;
6199             no_delay(ttyfd,1);
6200         }
6201 #endif /* TCP_NODELAY */
6202 #ifdef TN_COMPORT
6203         if (istncomport()) {
6204             int rc = -1;
6205             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
6206                  /* && ttcarr == curcarr */ ) {
6207                 debug(F100,"ttpkt modes already set, skipping...","",0);
6208                 return(0);              /* Already been called. */
6209             }
6210             if (flow != ttflow) {
6211                 if ((rc = tnsetflow(flow)) < 0)
6212                   return(rc);
6213                 ttflow = flow;
6214             }
6215             if (speed != ttspeed) {
6216                 if (speed <= 0) 
6217                   speed = tnc_get_baud();
6218                 else if ((rc = tnc_set_baud(speed)) < 0)
6219                   return(rc);
6220                 ttspeed = speed;
6221             }
6222             tnc_set_datasize(8);
6223             tnc_set_stopsize(stopbits);
6224
6225 #ifdef HWPARITY
6226             if (hwparity) {
6227                 switch (hwparity) {
6228                   case 'e':                     /* Even */
6229                     debug(F100,"ttres 8 bits + even parity","",0);
6230                     tnc_set_parity(3);
6231                     break;
6232                   case 'o':                     /* Odd */
6233                     debug(F100,"ttres 8 bits + odd parity","",0);
6234                     tnc_set_parity(2);
6235                     break;
6236                   case 'm':                     /* Mark */
6237                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6238                     tnc_set_parity(4);
6239                     break;
6240                   case 's':                     /* Space */
6241                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6242                     tnc_set_parity(5);
6243                     break;
6244                 }
6245             } else 
6246 #endif /* HWPARITY */
6247             {
6248                 tnc_set_parity(1);              /* None */
6249             }
6250             tvtflg = 0;
6251             return(0);
6252         }
6253 #endif /* TN_COMPORT */
6254 #endif /* TCPSOCKET */
6255         tvtflg = 0;
6256         return(0);
6257     }
6258 #endif /* NETCONN */
6259 #ifdef NETCMD
6260     if (ttpipe) return(0);
6261 #endif /* NETCMD */
6262 #ifdef NETPTY
6263     if (ttpty) return(0);
6264 #endif /* NETPTY */
6265
6266 #ifndef Plan9
6267     if (ttfdflg && !isatty(ttyfd)) return(0);
6268 #endif /* Plan9 */
6269
6270 #ifdef COHERENT
6271 #define SVORPOSIX
6272 #endif /* COHERENT */
6273
6274 #ifndef SVORPOSIX                       /* Berkeley, V7, etc. */
6275 #ifdef LPASS8
6276 /*
6277  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
6278  after having previously set it to NONE without closing and reopening the
6279  device.  Unless there's something I overlooked below...
6280 */
6281     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
6282         debug(F101,"ttpkt executing horrible flow kludge","",0);
6283         ttclos(0);                      /* Close it */
6284         x = 0;
6285         ttopen(ttnmsv,&x,ttmdm,0);      /* Open it again */
6286     }
6287 #endif /* LPASS8 */
6288 #endif /* SVORPOSIX */
6289
6290 #ifdef COHERENT                         /* This must be vestigial since we */
6291 #undef SVORPOSIX                        /* reverse it a few lines below... */
6292 #endif /* COHERENT */
6293
6294     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
6295       ttflow = xflow;                   /* Now make this available too. */
6296
6297 #ifndef NOLOCAL
6298     if (xlocal) {
6299         s2 = (int) (speed / 10L);       /* Convert bps to cps */
6300         debug(F101,"ttpkt calling ttsspd","",s2);
6301         s = ttsspd(s2);                 /* Check and set the speed */
6302         debug(F101,"ttpkt ttsspd result","",s);
6303         carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
6304                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6305         tvtflg = 0;                     /* So ttvt() will work next time */
6306     }
6307 #endif /* NOLOCAL */
6308
6309 #ifdef COHERENT
6310 #define SVORPOSIX
6311 #endif /* COHERENT */
6312
6313 #ifndef SVORPOSIX                       /* BSD section */
6314     if (flow == FLO_RTSC ||             /* Hardware flow control */
6315         flow == FLO_DTRC ||
6316         flow == FLO_DTRT) {
6317         tthflow(flow, 1, &ttraw);
6318         debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
6319         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6320         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6321     } else if (flow == FLO_NONE) {      /* No flow control */
6322         debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
6323         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6324         tthflow(flow, 0, &ttraw);       /* Turn off any hardware f/c too */
6325         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6326     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
6327         debug(F100,"ttpkt keeping original TANDEM","",0);
6328         ttraw.sg_flags &= ~TANDEM;
6329         ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
6330         /* NOTE: We should also handle hardware flow control here! */
6331     }
6332
6333 /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
6334
6335     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
6336         debug(F100,"ttpkt turning on TANDEM","",0);
6337         ttraw.sg_flags |= TANDEM;       /* So ask for it. */
6338
6339 #ifdef LPASS8                           /* Can pass 8-bit data through? */
6340 /* If the LPASS8 local mode is available, then flow control can always  */
6341 /* be used, even if parity is none and we are transferring 8-bit data.  */
6342 /* But we only need to do all this if Xon/Xoff is requested. */
6343 /* BUT... this tends not to work through IP or LAT connections, terminal */
6344 /* servers, telnet, rlogin, etc, so it is currently disabled. */
6345         x = LPASS8;                     /* If LPASS8 defined, then */
6346         debug(F100,"ttpkt executing LPASS8 code","",0);
6347         if (lmodef) {                   /* TIOCLBIS must be too. */
6348             x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
6349             if (x < 0) {
6350                 debug(F100,"ttpkt TIOCLBIS error","",0);
6351             } else {
6352                 lmodef++;
6353                 debug(F100,"ttpkt TIOCLBIS ok","",0);
6354             }
6355         }
6356 /*
6357  But if we use LPASS8 mode, we must explicitly turn off
6358  terminal interrupts of all kinds.
6359 */
6360 #ifdef TIOCGETC                         /* Not rawmode, */
6361         if (tcharf && (xlocal == 0)) {  /* must turn off */
6362             tchnoi.t_intrc = -1;        /* interrupt character */
6363             tchnoi.t_quitc = -1;        /* and quit character. */
6364             tchnoi.t_startc = 17;       /* Make sure xon */
6365             tchnoi.t_stopc = 19;        /* and xoff not ignored. */
6366 #ifndef NOBRKC
6367             tchnoi.t_eofc = -1;         /* eof character. */
6368             tchnoi.t_brkc = -1;         /* brk character. */
6369 #endif /* NOBRKC */
6370             if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6371                 debug(F100,"ttpkt TIOCSETC failed","",0);
6372             } else {
6373                 tcharf = 1;
6374                 debug(F100,"ttpkt TIOCSETC ok","",0);
6375             }
6376 #ifdef COMMENT
6377 /* only for paranoid debugging */
6378             if (tcharf) {
6379                 struct tchars foo;
6380                 char tchbuf[100];
6381                 ioctl(0,TIOCGETC,&foo);
6382                 sprintf(tchbuf,
6383                     "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
6384                     foo.t_intrc, foo.t_quitc, foo.t_startc,
6385                     foo.t_stopc, foo.t_eofc,  foo.t_brkc);
6386                 debug(F110,"ttpkt chars",tchbuf,0);
6387             }
6388 #endif /* COMMENT */
6389         }
6390         ttraw.sg_flags |= CBREAK;       /* Needed for unknown reason */
6391 #endif /* TIOCGETC */
6392
6393 /* Prevent suspend during packet mode */
6394 #ifdef TIOCGLTC                         /* Not rawmode, */
6395         if (ltcharf && (xlocal == 0)) { /* must turn off */
6396             ltchnoi.t_suspc = -1;       /* suspend character */
6397             ltchnoi.t_dsuspc = -1;      /* and delayed suspend character */
6398             if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6399                 debug(F100,"ttpkt TIOCSLTC failed","",0);
6400             } else {
6401                 ltcharf = 1;
6402                 debug(F100,"ttpkt TIOCSLTC ok","",0);
6403             }
6404         }
6405 #endif /* TIOCGLTC */
6406
6407 #else /* LPASS8 not defined */
6408
6409 /* Previously, BSD-based implementations always */
6410 /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
6411 /* This allows the flow control requested above to actually work, but only */
6412 /* if the user asks for parity (which also means they get 8th-bit quoting). */
6413
6414         if (parity) {                   /* If parity, */
6415             ttraw.sg_flags &= ~RAW;     /* use cooked mode */
6416 #ifdef COMMENT
6417 /* WHY??? */
6418             if (xlocal)
6419 #endif /* COMMENT */
6420               ttraw.sg_flags |= CBREAK;
6421             debug(F101,"ttpkt cooked, cbreak, parity","",parity);
6422 #ifdef TIOCGETC                         /* Not rawmode, */
6423             if (tcharf && (xlocal == 0)) { /* must turn off */
6424                 tchnoi.t_intrc = -1;    /* interrupt character */
6425                 tchnoi.t_quitc = -1;    /* and quit character. */
6426                 tchnoi.t_startc = 17;   /* Make sure xon */
6427                 tchnoi.t_stopc = 19;    /* and xoff not ignored. */
6428 #ifndef NOBRKC
6429                 tchnoi.t_eofc = -1;     /* eof character. */
6430                 tchnoi.t_brkc = -1;     /* brk character. */
6431 #endif /* NOBRKC */
6432                 if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6433                     debug(F100,"ttpkt TIOCSETC failed","",0);
6434                 } else {
6435                     tcharf = 1;
6436                     debug(F100,"ttpkt TIOCSETC ok","",0);
6437                 }
6438             }
6439 #endif /* TIOCGETC */
6440 #ifdef TIOCGLTC                         /* Not rawmode, */
6441 /* Prevent suspend during packet mode */
6442             if (ltcharf && (xlocal == 0)) { /* must turn off */
6443                 ltchnoi.t_suspc = -1;   /* suspend character */
6444                 ltchnoi.t_dsuspc = -1;  /* and delayed suspend character */
6445                 if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6446                     debug(F100,"ttpkt TIOCSLTC failed","",0);
6447                 } else {
6448                     ltcharf = 1;
6449                     debug(F100,"ttpkt TIOCSLTC ok","",0);
6450                 }
6451             }
6452 #endif /* TIOCGLTC */
6453         } else {                        /* If no parity, */
6454             ttraw.sg_flags |= RAW;      /* must use 8-bit raw mode. */
6455             debug(F101,"ttpkt setting rawmode, parity","",parity);
6456         }
6457 #endif /* LPASS8 */
6458     } /* End of Xon/Xoff section */
6459
6460     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
6461 #ifdef LCASE
6462     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
6463 #else
6464     ttraw.sg_flags &= ~(ECHO|CRMOD);
6465 #endif /* LCASE */
6466
6467 #ifdef TOWER1
6468     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
6469 #endif /* TOWER1 */
6470
6471 #ifdef BELLV10
6472     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
6473       return(-1);
6474 #else
6475     errno = 0;
6476     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
6477         debug(F101,"ttpkt stty failed","",errno);
6478         return(-1);
6479     }
6480 #endif /* BELLV10 */
6481     debug(F100,"ttpkt stty ok","",0);
6482
6483 #ifdef sony_news
6484     x = xlocal ? km_ext : km_con;       /* Put line in ASCII mode. */
6485     if (x != -1) {                      /* Make sure we know original modes. */
6486         x &= ~KM_TTYPE;
6487         x |= KM_ASCII;
6488         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
6489             perror("ttpkt can't set ASCII mode");
6490             debug(F101,"ttpkt error setting ASCII mode","",x);
6491             return(-1);
6492         }
6493     }
6494     debug(F100,"ttpkt set ASCII mode ok","",0);
6495 #endif /* sony_news */
6496
6497     if (xlocal == 0) {                  /* Turn this off so we can read */
6498         signal(SIGINT,SIG_IGN);         /* Ctrl-C chars typed at console */
6499         sigint_ign = 1;
6500     }
6501     tvtflg = 0;                         /* So ttvt() will work next time */
6502     debug(F100,"ttpkt success","",0);
6503     return(0);
6504
6505 #endif /* Not ATTSV or POSIX */
6506
6507 /* AT&T UNIX and POSIX */
6508
6509 #ifdef COHERENT
6510 #define SVORPOSIX
6511 #endif /* COHERENT */
6512
6513 #ifdef SVORPOSIX
6514     if (flow == FLO_XONX) {             /* Xon/Xoff */
6515         ttraw.c_iflag |= (IXON|IXOFF);
6516         tthflow(flow, 0, &ttraw);
6517     } else if (flow == FLO_NONE) {      /* None */
6518         /* NOTE: We should also turn off hardware flow control here! */
6519         ttraw.c_iflag &= ~(IXON|IXOFF);
6520         tthflow(flow, 0, &ttraw);
6521     } else if (flow == FLO_KEEP) {      /* Keep */
6522         ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
6523         ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6524         /* NOTE: We should also handle hardware flow control here! */
6525 #ifdef POSIX_CRTSCTS
6526 /* In Linux case, we do this, which is unlikely to be portable */
6527         ttraw.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
6528         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6529 #endif /* POSIX_CRTSCTS */
6530     } else if (flow == FLO_RTSC ||      /* Hardware */
6531                flow == FLO_DTRC ||
6532                flow == FLO_DTRT) {
6533         ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
6534         tthflow(flow, 1, &ttraw);
6535     }
6536     ttraw.c_lflag &= ~(ICANON|ECHO);
6537     ttraw.c_lflag &= ~ISIG;             /* Do NOT check for interrupt chars */
6538
6539 #ifndef OXOS
6540 #ifdef QNX
6541     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
6542 #endif /* QNX */
6543 #ifndef COHERENT
6544       ttraw.c_lflag &= ~IEXTEN;         /* Turn off ^O/^V processing */
6545 #endif /* COHERENT */
6546 #else /* OXOS */
6547     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
6548 #endif /* OXOS */
6549     ttraw.c_lflag |= NOFLSH;            /* Don't flush */
6550     ttraw.c_iflag |= IGNPAR;            /* Ignore parity errors */
6551 #ifdef ATTSV
6552 #ifdef BSD44
6553     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
6554 #else
6555     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
6556 #endif /* BSD44 */
6557 #else /* POSIX */
6558     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
6559 #endif /* ATTSV */
6560     ttraw.c_oflag &= ~OPOST;
6561     ttraw.c_cflag &= ~(CSIZE);
6562     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
6563
6564 #ifdef CSTOPB
6565     if (xlocal) {
6566         if (stopbits == 2) {
6567             ttraw.c_cflag |= CSTOPB;    /* 2 stop bits */
6568             debug(F100,"ttpkt 2 stopbits","",0);
6569         } else if (stopbits == 1) {
6570             ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
6571             debug(F100,"ttpkt 1 stopbit","",0);
6572         }
6573     }
6574 #endif /* CSTOPB */
6575
6576 #ifdef HWPARITY
6577     if (hwparity && xlocal) {           /* Hardware parity */
6578         ttraw.c_cflag |= PARENB;        /* Enable parity */
6579 #ifdef COMMENT
6580 /* Uncomment this only if needed -- I don't think it is */
6581         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
6582         ttraw.c_cflag |= CS8;           /* And set it to 8 */
6583 #endif /* COMMENT */
6584 #ifdef IGNPAR
6585         ttraw.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
6586         debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
6587 #endif /* IGNPAR */
6588         switch (hwparity) {
6589           case 'e':                     /* Even */
6590             ttraw.c_cflag &= ~(PARODD);
6591             debug(F100,"ttpkt 8 bits + even parity","",0);
6592             break;
6593           case 'o':                     /* Odd */
6594             ttraw.c_cflag |= PARODD;
6595             debug(F100,"ttpkt 8 bits + odd parity","",0);
6596             break;
6597           case 'm':                     /* Mark */
6598           case 's':                     /* Space */
6599             /* PAREXT is mentioned in SVID but the details are not given. */
6600             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
6601             debug(F100,"ttpkt 8 bits + invalid parity","",0);
6602             break;
6603         }
6604     } else {                            /* We handle parity ourselves */
6605 #endif /* HWPARITY */
6606         ttraw.c_cflag &= ~(PARENB);     /* Don't enable parity */
6607 #ifdef HWPARITY
6608     }
6609 #endif /* HWPARITY */
6610
6611 #ifdef IX370
6612     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
6613     ttraw.c_cc[5] = 1;
6614 #else
6615 #ifndef VEOF                            /* for DGUX this is VEOF, not VMIN */
6616     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
6617 #else
6618 #ifndef OXOS
6619 #ifdef VMIN
6620     ttraw.c_cc[VMIN] = 1;
6621 #endif /* VMIN */
6622 #else /* OXOS */
6623     ttraw.c_min = 1;
6624 #endif /* OXOS */
6625 #endif /* VEOF */
6626 #ifndef VEOL                            /* for DGUX this is VEOL, not VTIME */
6627     ttraw.c_cc[5] = 0;   /* [VTIME] when this many secs/10 expire w/no input */
6628 #else
6629 #ifndef OXOS
6630 #ifdef VTIME
6631     ttraw.c_cc[VTIME] = 0;
6632 #endif /* VTIME */
6633 #else /* OXOS */
6634     ttraw.c_time = 0;
6635 #endif /* OXOS */
6636 #endif /* VEOL */
6637 #endif /* IX370 */
6638
6639 #ifdef VINTR                            /* Turn off interrupt character */
6640     if (xlocal == 0)                    /* so ^C^C can break us out of */
6641       ttraw.c_cc[VINTR] = 0;            /* packet mode. */
6642 #endif /* VINTR */
6643
6644 #ifdef Plan9
6645     if (p9ttyparity('n') < 0)
6646         return -1;
6647 #else
6648 #ifdef BSD44ORPOSIX
6649     errno = 0;
6650 #ifdef BEOSORBEBOX
6651     ttraw.c_cc[VMIN] = 0;               /* DR7 can only poll. */
6652 #endif /* BEOSORBEBOX */
6653     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
6654     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
6655     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
6656     if (x < 0) {
6657         debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
6658         return(-1);
6659     }
6660 #else /* BSD44ORPOSIX */
6661     x = ioctl(ttyfd,TCSETAW,&ttraw);
6662     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
6663     if (x < 0) {  /* set new modes . */
6664         debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
6665         return(-1);
6666     }
6667 #endif /* BSD44ORPOSIX */
6668 #endif /* Plan9 */
6669     tvtflg = 0;
6670     debug(F100,"ttpkt ok","",0);
6671     return(0);
6672 #endif /* ATTSV */
6673
6674 #ifdef COHERENT
6675 #undef SVORPOSIX
6676 #endif /* COHERENT */
6677
6678 }
6679
6680 /*  T T S E T F L O W  --  Set flow control immediately.  */
6681
6682 #ifdef COHERENT
6683 #define SVORPOSIX
6684 #endif /* COHERENT */
6685
6686 int
6687 ttsetflow(flow) int flow; {
6688     if (ttyfd < 0)                      /* A channel must be open */
6689       return(-1);
6690
6691     debug(F101,"ttsetflow flow","",flow);
6692
6693 #ifdef TN_COMPORT
6694     if (netconn && istncomport()) {
6695         debug(F101,"ttsetflow net modem","",ttmdm);
6696         return(tnsetflow(flow));
6697     }
6698 #endif /* TN_COMPORT */
6699 #ifdef NETCMD
6700     if (ttpipe) return(0);
6701 #endif /* NETCMD */
6702 #ifdef NETPTY
6703     if (ttpty) return(0);
6704 #endif /* NETPTY */
6705
6706 #ifdef COMMENT
6707     /* This seems to hurt... */
6708     if (flow == FLO_KEEP)
6709       return(0);
6710 #endif /* COMMENT */
6711
6712     if (flow == FLO_RTSC ||             /* Hardware flow control... */
6713         flow == FLO_DTRC ||
6714         flow == FLO_DTRT) {
6715         tthflow(flow, 1, &ttraw);
6716 #ifndef SVORPOSIX
6717         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6718 #else
6719         ttraw.c_iflag &= ~(IXON|IXOFF);
6720 #endif /* SVORPOSIX */
6721
6722     } else if (flow == FLO_XONX) {      /* Xon/Xoff... */
6723
6724 #ifndef SVORPOSIX
6725         ttraw.sg_flags |= TANDEM;
6726 #else
6727         ttraw.c_iflag |= (IXON|IXOFF);
6728 #endif /* SVORPOSIX */
6729         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off hardware flow control */
6730
6731     } else if (flow == FLO_NONE) {      /* No flow control */
6732
6733 #ifndef SVORPOSIX
6734         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6735 #else
6736         ttraw.c_iflag &= ~(IXON|IXOFF);
6737 #endif /* SVORPOSIX */
6738         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off any hardware f/c too */
6739     }
6740
6741 /* Set the new modes... */
6742
6743 #ifndef SVORPOSIX                       /* BSD and friends */
6744 #ifdef BELLV10
6745     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
6746       return(-1);
6747 #else
6748 #ifndef MINIX2
6749     if (stty(ttyfd,&ttraw) < 0)
6750       return(-1);
6751 #endif /* MINIX2 */
6752 #endif /* BELLV10 */
6753 #else
6754 #ifdef BSD44ORPOSIX                     /* POSIX */
6755     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
6756       return(-1);
6757 #else                                   /* System V */
6758     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
6759       return(-1);
6760 #endif /* BSD44ORPOSIX */
6761 #endif /* SVORPOSIX */
6762     return(0);
6763 }
6764 #ifdef COHERENT
6765 #undef SVORPOSIX
6766 #endif /* COHERENT */
6767
6768 /*  T T V T -- Condition communication device for use as virtual terminal. */
6769
6770 int
6771 #ifdef CK_ANSIC
6772 ttvt(long speed, int flow)
6773 #else
6774 ttvt(speed,flow) long speed; int flow;
6775 #endif /* CK_ANSIC */
6776 /* ttvt */ {
6777     int s, s2, x;
6778
6779     debug(F101,"ttvt ttyfd","",ttyfd);
6780     debug(F101,"ttvt tvtflg","",tvtflg);
6781     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
6782     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
6783     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
6784
6785 /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
6786 /* Maybe it would be simpler to use it... */
6787
6788     ttpmsk = 0xff;
6789 #ifdef NOLOCAL
6790     return(conbin((char)escchr));
6791 #else
6792     if (ttyfd < 0) {                    /* Not open. */
6793         if (ttchk() < 0)
6794           return(-1);
6795         else                            /* But maybe something buffered. */
6796           return(0);
6797     }
6798 #ifdef NETCMD
6799     if (ttpipe) return(0);
6800 #endif /* NETCMD */
6801 #ifdef NETPTY
6802     if (ttpty) return(0);
6803 #endif /* NETPTY */
6804 #ifdef NETCONN
6805     if (netconn) {
6806 #ifdef TCPSOCKET
6807 #ifdef TCP_NODELAY
6808         {
6809             extern int tcp_nodelay;
6810             if (ttnet == NET_TCPB) {
6811                 if (nodelay_sav > -1) {
6812                     no_delay(ttyfd,nodelay_sav);
6813                     nodelay_sav = -1;
6814                 }
6815             }
6816         }
6817 #endif /* TCP_NODELAY */
6818 #ifdef TN_COMPORT
6819         if (istncomport()) {
6820             int rc = -1;
6821             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
6822                  /* && ttcarr == curcarr */ ) {
6823                 debug(F100,"ttvt modes already set, skipping...","",0);
6824                 return(0);                      /* Already been called. */
6825             }
6826             if (flow != ttflow) {
6827                 if ((rc = tnsetflow(flow)) < 0)
6828                   return(rc);
6829                 ttflow = flow;
6830             }
6831             if (speed != ttspeed) {
6832                 if (speed <= 0) 
6833                   speed = tnc_get_baud();
6834                 else if ((rc = tnc_set_baud(speed)) < 0)
6835                   return(rc);
6836                 ttspeed = speed;
6837             }
6838             tnc_set_datasize(8);
6839             tnc_set_stopsize(stopbits);
6840
6841 #ifdef HWPARITY
6842             if (hwparity) {
6843                 switch (hwparity) {
6844                   case 'e':             /* Even */
6845                     debug(F100,"ttres 8 bits + even parity","",0);
6846                     tnc_set_parity(3);
6847                     break;
6848                   case 'o':             /* Odd */
6849                     debug(F100,"ttres 8 bits + odd parity","",0);
6850                     tnc_set_parity(2);
6851                     break;
6852                   case 'm':             /* Mark */
6853                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6854                     tnc_set_parity(4);
6855                     break;
6856                   case 's':             /* Space */
6857                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6858                     tnc_set_parity(5);
6859                     break;
6860                 }
6861             } else
6862 #endif /* HWPARITY */
6863             {
6864                 tnc_set_parity(1);      /* None */
6865             }
6866             tvtflg = 1;
6867             return(0);
6868         }
6869 #endif /* TN_COMPORT */
6870 #endif /* TCPSOCKET */
6871         tvtflg = 1;                     /* Network connections... */
6872         debug(F100,"ttvt network connection, skipping...","",0);
6873         return(0);                      /* ... require no special setup */
6874     }
6875 #endif /* NETCONN */
6876
6877     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
6878         /* && ttcarr == curcarr */ )
6879       {
6880           debug(F100,"ttvt modes already set, skipping...","",0);
6881           return(0);                    /* Already been called. */
6882       }
6883
6884     if (ttfdflg
6885 #ifndef Plan9
6886         && !isatty(ttyfd)
6887 #endif /* Plan9 */
6888         ) {
6889         debug(F100,"ttvt using external fd, skipping...","",0);
6890         return(0);
6891     }
6892
6893     debug(F100,"ttvt setting modes...","",0);
6894
6895     if (xlocal) {                       /* For external lines... */
6896         s2 = (int) (speed / 10L);
6897         s = ttsspd(s2);                 /* Check/set the speed */
6898         carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
6899                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6900     } else
6901       s = s2 = -1;
6902
6903 #ifdef COHERENT
6904 #define SVORPOSIX
6905 #endif /* COHERENT */
6906
6907 #ifndef SVORPOSIX
6908     /* Berkeley, V7, etc */
6909     if (flow == FLO_RTSC ||             /* Hardware flow control */
6910         flow == FLO_DTRC ||
6911         flow == FLO_DTRT) {
6912         tthflow(flow, 1, &tttvt);
6913         debug(F100,"ttvt hard flow, TANDEM off","",0);
6914         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6915     } else if (flow == FLO_XONX) {      /* Xon/Xoff flow control */
6916         debug(F100,"ttvt TANDEM on","",0);
6917         tttvt.sg_flags |= TANDEM;       /* Ask for it. */
6918         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
6919     } else if (flow == FLO_NONE) {
6920         debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
6921         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6922         tthflow(flow, 0, &tttvt);       /* Turn off any hardware f/c too */
6923         tttvt.sg_flags |= RAW;          /* Enter raw mode */
6924     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
6925         debug(F100,"ttvt keeping original TANDEM","",0);
6926         tttvt.sg_flags &= ~TANDEM;
6927         tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
6928         /* NOTE: We should also handle hardware flow control here! */
6929     }
6930     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
6931 #ifdef TOWER1
6932     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
6933 #else
6934     tttvt.sg_flags &= ~ECHO;            /* No echo */
6935 #endif /* TOWER1 */
6936
6937 #ifdef BELLV10
6938     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
6939       return(-1);
6940 #else
6941     if (stty(ttyfd,&tttvt) < 0)         /* Set the new modes */
6942       return(-1);
6943 #endif /* BELLV10 */
6944
6945 #else /* It is ATTSV or POSIX */
6946
6947     if (flow == FLO_XONX) {             /* Software flow control */
6948         tttvt.c_iflag |= (IXON|IXOFF);  /* On if requested. */
6949         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
6950         debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
6951     } else if (flow == FLO_NONE) {      /* NONE */
6952         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
6953         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
6954         debug(F100,"ttvt SVORPOSIX flow NONE","",0);
6955     } else if (flow == FLO_KEEP) {
6956         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
6957         tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6958 #ifdef POSIX_CRTSCTS
6959         tttvt.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
6960         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6961 #endif /* POSIX_CRTSCTS */
6962         debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
6963     } else if (flow == FLO_RTSC ||      /* Hardware flow control */
6964                flow == FLO_DTRC ||
6965                flow == FLO_DTRT) {
6966         tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
6967         tthflow(flow, 1, &tttvt);
6968         debug(F100,"ttvt SVORPOSIX flow HARD","",0);
6969     }
6970 #ifndef OXOS
6971 #ifdef COHERENT
6972     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
6973 #else
6974     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
6975 #endif /* COHERENT */
6976 #ifdef QNX
6977     /* Needed for hwfc */
6978     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
6979       tttvt.c_lflag |= IEXTEN;
6980 #endif /* QNX */
6981 #else /* OXOS */
6982     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
6983     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
6984 #endif /* OXOS */
6985
6986     tttvt.c_iflag |= (IGNBRK|IGNPAR);
6987
6988 /* Stop bits */
6989
6990 #ifdef CSTOPB
6991     if (xlocal) {
6992         if (stopbits == 2) {
6993             tttvt.c_cflag |= CSTOPB;    /* 2 stop bits */
6994             debug(F100,"ttvt 2 stopbits","",0);
6995         } else if (stopbits == 1) {
6996             tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
6997             debug(F100,"ttvt 1 stopbit","",0);
6998         }
6999     }
7000 #endif /* CSTOPB */
7001
7002 /* Parity */
7003
7004 #ifdef HWPARITY
7005     if (hwparity && xlocal) {           /* Hardware parity */
7006 #ifdef COMMENT
7007 /* Uncomment this only if needed -- I don't think it is */
7008         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
7009         ttraw.c_cflag |= CS8;           /* And set it to 8 */
7010 #endif /* COMMENT */
7011 #ifdef IGNPAR
7012         debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
7013         tttvt.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
7014 #endif /* IGNPAR */
7015         tttvt.c_cflag |= PARENB;        /* Enable parity */
7016
7017         switch (hwparity) {
7018           case 'e':                     /* Even */
7019             tttvt.c_cflag &= ~(PARODD);
7020             debug(F100,"ttvt 8 bits + even parity","",0);
7021             break;
7022           case 'o':                     /* Odd */
7023             tttvt.c_cflag |= PARODD;
7024             debug(F100,"ttvt 8 bits + odd parity","",0);
7025             break;
7026           case 'm':                     /* Mark */
7027           case 's':                     /* Space */
7028             /* PAREXT is mentioned in SVID but the details are not given. */
7029             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
7030             debug(F100,"ttvt 8 bits + invalid parity","",0);
7031             break;
7032         }
7033     } else {                            /* We handle parity ourselves */
7034 #endif /* HWPARITY */
7035         tttvt.c_cflag &= ~(PARENB);     /* Don't enable parity */
7036 #ifdef HWPARITY
7037     }
7038 #endif /* HWPARITY */
7039
7040 #ifdef ATTSV
7041 #ifdef BSD44
7042     /* Things not to do... */
7043     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
7044 #else
7045     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
7046 #endif /* BSD44 */
7047 #else /* POSIX */
7048     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
7049 #endif /* ATTSV */
7050     tttvt.c_cflag &= ~(CSIZE);          /* Zero out the char size field */
7051     tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
7052     tttvt.c_oflag &= ~OPOST;            /* Don't postprocess output */
7053 #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
7054     tttvt.c_cc[4] = 1;
7055 #else
7056 #ifndef OXOS
7057 #ifdef VMIN
7058     tttvt.c_cc[VMIN] = 1;
7059 #endif /* VMIN */
7060 #else /* OXOS */
7061     tttvt.c_min = 1;
7062 #endif /* OXOS */
7063 #endif /* VEOF */
7064 #ifndef VEOL    /* DGUX termio has VEOL at entry 5, see comment above */
7065     tttvt.c_cc[5] = 0;
7066 #else
7067 #ifndef OXOS
7068 #ifdef VTIME
7069     tttvt.c_cc[VTIME] = 0;
7070 #endif /* VTIME */
7071 #else /* OXOS */
7072     tttvt.c_time = 0;
7073 #endif /* OXOS */
7074 #endif /* VEOL */
7075
7076 #ifdef Plan9
7077     if (p9ttyparity('n') < 0)
7078       return -1;
7079 #else
7080 #ifdef BSD44ORPOSIX
7081     errno = 0;
7082 #ifdef BEOSORBEBOX
7083     tttvt.c_cc[VMIN] = 0;               /* DR7 can only poll. */
7084 #endif /* BEOSORBEBOX */
7085
7086     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
7087     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
7088     if (x < 0) {
7089         debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
7090         return(-1);
7091     }
7092 #else /* ATTSV */
7093     x = ioctl(ttyfd,TCSETAW,&tttvt);
7094     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
7095     if (x < 0) {                        /* set new modes . */
7096         debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
7097         return(-1);     
7098     }
7099 #endif /* BSD44ORPOSIX */
7100 #endif /* Plan9 */
7101 #endif /* ATTSV */
7102
7103     ttspeed = speed;                    /* Done, remember how we were */
7104     ttflow = flow;                      /* called, so we can decide how to */
7105     tvtflg = 1;                         /* respond next time. */
7106     debug(F100,"ttvt ok","",0);
7107     return(0);
7108
7109 #ifdef COHERENT
7110 #undef SVORPOSIX
7111 #endif /* COHERENT */
7112
7113 #endif /* NOLOCAL */
7114 }
7115
7116 #ifndef NOLOCAL
7117
7118 /* Serial speed department . . . */
7119
7120 /*
7121   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
7122   defined in the header files but they are supported (e.g. when building with
7123   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
7124   was the first release that came with high serial speeds standard, releases
7125   back to 5.0.0 could use them if certain patches (or "supplements") were
7126   applied to the SIO driver.  Plus a lot of SCO installations run third-party
7127   drivers.
7128 */
7129 #ifdef CK_SCOV5
7130 #ifndef B38400
7131 #define B38400  0000017
7132 #endif /* B38400 */
7133 #ifndef B57600
7134 #define B57600  0000021
7135 #endif /* B57600 */
7136 #ifndef B76800
7137 #define B76800  0000022
7138 #endif /* B76800 */
7139 #ifndef B115200
7140 #define B115200 0000023
7141 #endif /* B115200 */
7142 #ifndef B230400
7143 #define B230400 0000024
7144 #endif /* B230400 */
7145 #ifndef B460800
7146 #define B460800 0000025
7147 #endif /* B460800 */
7148 #ifndef B921600
7149 #define B921600 0000026
7150 #endif /* B921600 */
7151 #endif /* CK_SCOV5 */
7152 /*
7153   Plan 9's native speed setting interface lets you set anything you like,
7154   but will fail if the hardware doesn't like it, so we allow all the common
7155   speeds.
7156 */
7157 #ifdef Plan9
7158 #ifndef B50
7159 #define B50 50
7160 #endif /* B50 */
7161 #ifndef B75
7162 #define B75 75
7163 #endif /* B75 */
7164 #ifndef B110
7165 #define B110 110
7166 #endif /* B110 */
7167 #ifndef B134
7168 #define B134 134
7169 #endif /* B134 */
7170 #ifndef B200
7171 #define B200 200
7172 #endif /* B200 */
7173 #ifndef B300
7174 #define B300 300
7175 #endif /* B300 */
7176 #ifndef B1200
7177 #define B1200 1200
7178 #endif /* B1200 */
7179 #ifndef B1800
7180 #define B1800 1800
7181 #endif /* B1800 */
7182 #ifndef B2400
7183 #define B2400 2400
7184 #endif /* B2400 */
7185 #ifndef B4800
7186 #define B4800 4800
7187 #endif /* B4800 */
7188 #ifndef B9600
7189 #define B9600 9600
7190 #endif /* B9600 */
7191 #ifndef B14400
7192 #define B14400 14400
7193 #endif /* B14400 */
7194 #ifndef B19200
7195 #define B19200 19200
7196 #endif /* B19200 */
7197 #ifndef B28800
7198 #define B28800 28800
7199 #endif /* B28800 */
7200 #ifndef B38400
7201 #define B38400 38400
7202 #endif /* B38400 */
7203 #ifndef B57600
7204 #define B57600 57600
7205 #endif /* B57600 */
7206 #ifndef B76800
7207 #define B76800 76800
7208 #endif /* B76800 */
7209 #ifndef B115200
7210 #define B115200 115200
7211 #endif /* B115200 */
7212 #ifndef B230400
7213 #define B230400 230400
7214 #endif /* B230400 */
7215 #ifndef B460800
7216 #define B460800 460800
7217 #endif /* B460800 */
7218 #ifndef B921600
7219 #define B921600 921600
7220 #endif /* B921600 */
7221 #endif /* Plan9 */
7222
7223 /*  T T S S P D  --  Checks and sets transmission rate.  */
7224
7225 /*  Call with speed in characters (not bits!) per second. */
7226 /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
7227
7228 #ifdef USETCSETSPEED
7229 /*
7230   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
7231   to be used as a speed to be set, rather than forcing a choice from a
7232   predefined list.  It seems to be peculiar to UnixWare 7.
7233
7234   These are the function codes to be passed to tc[gs]etspeed(),
7235   but for some reason they don't seem to be picked up from termios.h.
7236 */
7237 #ifndef TCS_ALL
7238 #define TCS_ALL 0
7239 #endif /* TCS_ALL */
7240 #ifndef TCS_IN
7241 #define TCS_IN 1
7242 #endif /* TCS_IN */
7243 #ifndef TCS_OUT
7244 #define TCS_OUT 2
7245 #endif /* TCS_OUT */
7246 #endif /* USETCSETSPEED */
7247
7248 int
7249 ttsspd(cps) int cps; {
7250     int x;
7251 #ifdef POSIX
7252 /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
7253     speed_t
7254 #else
7255     int
7256 #endif /* POSIX */
7257       s, s2;
7258     int ok = 1;                         /* Speed check result, assume ok */
7259
7260 #ifdef OLINUXHISPEED
7261     unsigned int spd_flags = 0;
7262     struct serial_struct serinfo;
7263 #endif /* OLINUXHISPEED */
7264
7265     debug(F101,"ttsspd cps","",cps);
7266     debug(F101,"ttsspd ttyfd","",ttyfd);
7267     debug(F101,"ttsspd xlocal","",xlocal);
7268
7269     if (ttyfd < 0 || xlocal == 0)       /* Don't set speed on console */
7270       return(0);
7271
7272 #ifdef  NETCONN
7273     if (netconn) {
7274 #ifdef TN_COMPORT
7275         if (istncomport())
7276           return(tnc_set_baud(cps * 10));
7277         else
7278 #endif /* TN_COMPORT */
7279         return(0);
7280   }
7281 #endif  /* NETCONN */
7282 #ifdef NETCMD
7283     if (ttpipe) return(0);
7284 #endif /* NETCMD */
7285 #ifdef NETPTY
7286     if (ttpty) return(0);
7287 #endif /* NETPTY */
7288
7289     if (cps < 0) return(-1);
7290     s = s2 = 0;                         /* NB: s and s2 might be unsigned */
7291
7292 #ifdef USETCSETSPEED
7293
7294     s = cps * 10L;
7295
7296     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7297     debug(F101,"ttsspd tcgetattr","",x);
7298     if (x < 0)
7299       return(-1);
7300     debug(F101,"ttsspd TCSETSPEED speed","",s);
7301
7302     errno = 0;
7303     if (s == 8880L) {                   /* 75/1200 split speed requested */
7304         tcsetspeed(TCS_IN, &ttcur, 1200L);
7305         tcsetspeed(TCS_OUT, &ttcur, 75L);
7306     } else
7307       tcsetspeed(TCS_ALL, &ttcur, s);   /* Put new speed in structs */
7308 #ifdef DEBUG
7309     if (errno & deblog) {
7310         debug(F101,"ttsspd TCSETSPEED errno","",errno);
7311     }
7312 #endif /* DEBUG */
7313
7314 #ifdef COMMENT
7315     tcsetspeed(TCS_ALL, &ttraw, s);
7316     tcsetspeed(TCS_ALL, &tttvt, s);
7317     tcsetspeed(TCS_ALL, &ttold, s);
7318 #else
7319     if (s == 8880L) {                   /* 75/1200 split speed requested */
7320         tcsetspeed(TCS_IN, &ttraw, 1200L);
7321         tcsetspeed(TCS_OUT, &ttraw, 75L);
7322         tcsetspeed(TCS_IN, &tttvt, 1200L);
7323         tcsetspeed(TCS_OUT, &tttvt, 75L);
7324         tcsetspeed(TCS_IN, &ttold, 1200L);
7325         tcsetspeed(TCS_OUT, &ttold, 75L);
7326     } else {
7327         tcsetspeed(TCS_ALL, &ttraw, s);
7328         tcsetspeed(TCS_ALL, &tttvt, s);
7329         tcsetspeed(TCS_ALL, &ttold, s);
7330     }
7331 #endif /* COMMENT */
7332
7333     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
7334     debug(F101,"ttsspd tcsetattr","",x);
7335     if (x < 0)
7336       return(-1);
7337
7338 #else  /* Not USETCSETSPEED */
7339
7340 #ifdef MINIX2        /* Hack alert */
7341 #define MINIX        /* Use pre-2.0 speed selection for Minix 2.0 as well */
7342 #endif /* MINIX2 */
7343
7344     /* First check that the given speed is valid. */
7345
7346     switch (cps) {
7347 #ifndef MINIX
7348       case 0:   s = B0;    break;
7349       case 5:   s = B50;   break;
7350       case 7:   s = B75;   break;
7351 #endif /* MINIX */
7352       case 11:  s = B110;  break;
7353 #ifndef MINIX
7354       case 13:  s = B134;  break;
7355       case 15:  s = B150;  break;
7356       case 20:  s = B200;  break;
7357 #endif /* MINIX */
7358       case 30:  s = B300;  break;
7359 #ifndef MINIX
7360       case 60:  s = B600;  break;
7361 #endif /* MINIX */
7362       case 120: s = B1200; break;
7363 #ifndef MINIX
7364       case 180: s = B1800; break;
7365 #endif /* MINIX */
7366       case 240: s = B2400; break;
7367       case 480: s = B4800; break;
7368 #ifndef MINIX
7369       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
7370 #endif /* MINIX */
7371 #ifdef B7200
7372       case 720: s = B7200; break;
7373 #endif /* B7200 */
7374       case 960: s = B9600; break;
7375 #ifdef B14400
7376       case 1440: s = B14400; break;
7377 #endif /* B14400 */
7378 #ifdef B19200
7379       case 1920: s = B19200; break;
7380 #else
7381 #ifdef EXTA
7382       case 1920: s = EXTA; break;
7383 #endif /* EXTA */
7384 #endif /* B19200 */
7385 #ifdef B28800
7386       case 2880: s = B28800; break;
7387 #endif /* B28800 */
7388 #ifdef B38400
7389       case 3840: s = B38400;
7390 #ifdef OLINUXHISPEED
7391         spd_flags = ~ASYNC_SPD_MASK;    /* Nonzero, but zero flags */
7392 #endif /* OLINUXHISPEED */
7393         break;
7394 #else /* B38400 not defined... */
7395 #ifdef EXTB
7396       case 3840: s = EXTB; break;
7397 #endif /* EXTB */
7398 #endif /* B38400 */
7399
7400 #ifdef HPUX
7401 #ifdef _B57600
7402       case 5760: s = _B57600; break;
7403 #endif /* _B57600 */
7404 #ifdef _B115200
7405       case 11520: s = _B115200; break;
7406 #endif /* _B115200 */
7407 #else
7408 #ifdef OLINUXHISPEED
7409 /*
7410   This bit from <carlo@sg.tn.tudelft.nl>:
7411   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
7412   setting the speed to 38400 will set the custom speed (and ttgspd returns
7413   38400), but speeds 57600 and 115200 won't work any more because I didn't
7414   want to mess up the speed flags when someone is doing sophisticated stuff
7415   like custom speeds..."
7416 */
7417       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
7418       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
7419 #else
7420 #ifdef B57600
7421       case 5760: s = B57600; break;
7422 #endif /* B57600 */
7423 #ifdef B76800
7424       case 7680: s = B76800; break;
7425 #endif /* B76800 */
7426 #ifdef B115200
7427       case 11520: s = B115200; break;
7428 #endif /* B115200 */
7429 #endif /* OLINUXHISPEED */
7430 #ifdef B153600
7431       case 15360: s = B153600; break;
7432 #endif /* B153600 */
7433 #ifdef B230400
7434       case 23040: s = B230400; break;
7435 #endif /* B230400 */
7436 #ifdef B307200
7437       case 30720: s = B307200; break;
7438 #endif /* B307200 */
7439 #ifdef B460800
7440       case 46080: s = B460800; break;
7441 #endif /* 460800 */
7442 #ifdef B921600
7443       case 92160: s = B921600; break;
7444 #endif /* B921600 */
7445 #endif /* HPUX */
7446       default:
7447         ok = 0;                         /* Good speed not found, so not ok */
7448         break;
7449     }
7450     debug(F101,"ttsspd ok","",ok);
7451     debug(F101,"ttsspd s","",s);
7452
7453     if (!ok) {
7454         debug(F100,"ttsspd fails","",0);
7455         return(-1);
7456     } else {
7457         if (!s2) s2 = s;                /* Set input speed */
7458 #ifdef Plan9
7459         if (p9ttsspd(cps) < 0)
7460           return(-1);
7461 #else
7462 #ifdef BSD44ORPOSIX
7463         x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
7464         debug(F101,"ttsspd tcgetattr","",x);
7465         if (x < 0)
7466           return(-1);
7467 #ifdef OLINUXHISPEED
7468         debug(F101,"ttsspd spd_flags","",spd_flags);
7469         if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
7470             if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
7471                 debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
7472                 return(-1);
7473             } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
7474             serinfo.flags &= ~ASYNC_SPD_MASK;
7475             serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
7476             if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
7477               return(-1);
7478         }
7479 #endif /* OLINUXHISPEED */
7480         cfsetospeed(&ttcur,s);
7481         cfsetispeed(&ttcur,s2);
7482         cfsetospeed(&ttraw,s);
7483         cfsetispeed(&ttraw,s2);
7484         cfsetospeed(&tttvt,s);
7485         cfsetispeed(&tttvt,s2);
7486         cfsetospeed(&ttold,s);
7487         cfsetispeed(&ttold,s2);
7488         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
7489         debug(F101,"ttsspd tcsetattr","",x);
7490         if (x < 0) return(-1);
7491 #else
7492 #ifdef ATTSV
7493         if (cps == 888) return(-1);     /* No split speeds, sorry. */
7494         x = ioctl(ttyfd,TCGETA,&ttcur);
7495         debug(F101,"ttsspd TCGETA ioctl","",x);
7496         if (x < 0) return(-1);
7497         ttcur.c_cflag &= ~CBAUD;
7498         ttcur.c_cflag |= s;
7499         tttvt.c_cflag &= ~CBAUD;
7500         tttvt.c_cflag |= s;
7501         ttraw.c_cflag &= ~CBAUD;
7502         ttraw.c_cflag |= s;
7503         ttold.c_cflag &= ~CBAUD;
7504         ttold.c_cflag |= s;
7505         x = ioctl(ttyfd,TCSETAW,&ttcur);
7506         debug(F101,"ttsspd TCSETAW ioctl","",x);
7507         if (x < 0) return(-1);
7508 #else
7509 #ifdef BELLV10
7510         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7511         debug(F101,"ttsspd TIOCGDEV ioctl","",x);
7512         if (x < 0) return(-1);
7513         tdcur.ispeed = s2;
7514         tdcur.ospeed = s;
7515         errno = 0;
7516         ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
7517         debug(F101,"ttsspd BELLV10 ioctl","",ok);
7518         if (ok < 0) {
7519             perror(ttnmsv);
7520             debug(F101,"ttsspd BELLV10 errno","",ok);
7521             return(-1);
7522         }
7523 #else
7524         x = gtty(ttyfd,&ttcur);
7525         debug(F101,"ttsspd gtty","",x);
7526         if (x < 0) return(-1);
7527         ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
7528         tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
7529         ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
7530         ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
7531         x = stty(ttyfd,&ttcur);
7532         debug(F101,"ttsspd stty","",x);
7533         if (x < 0) return(-1);
7534 #endif /* BELLV10 */
7535 #endif /* ATTSV */
7536 #endif /* BSD44ORPOSIX */
7537 #endif /* Plan9 */
7538     }
7539     return(1);                          /* Return 1 = success. */
7540 #endif /* USETCSETSPEED */
7541 }
7542
7543 #endif /* NOLOCAL */
7544
7545 /* C O N G S P D  -  Get speed of console terminal  */
7546
7547 long
7548 congspd() {
7549 /*
7550   This is a disgusting hack.  The right way to do this would be to pass an
7551   argument to ttgspd(), but then we'd need to change the Kermit API and
7552   all of the ck?tio.c modules.  (Currently used only for rlogin.)
7553 */
7554     int t1;
7555     long spd;
7556 #ifdef NETCONN
7557     int t2 = netconn;
7558     netconn = 0;
7559 #endif /* NETCONN */
7560     t1 = ttyfd;
7561     ttyfd = -1;
7562     spd = ttgspd();
7563     debug(F101,"congspd","",spd);
7564 #ifdef NETCONN
7565     netconn = t2;
7566 #endif /* NETCONN */
7567     ttyfd = t1;
7568     return(spd);
7569 }
7570
7571 /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
7572
7573 #define NSPDLIST 64
7574 static long spdlist[NSPDLIST];
7575 /*
7576   As written, this picks up the speeds known at compile time, and thus
7577   apply to the system where C-Kermit was built, rather than to the one where
7578   it is running.  Suggestions for improvement are always welcome.
7579 */
7580 long *
7581 ttspdlist() {
7582     int i;
7583     for (i = 0; i < NSPDLIST; i++)      /* Initialize the list */
7584       spdlist[i] = -1L;
7585     i = 1;
7586
7587 #ifdef USETCSETSPEED                    /* No way to find out what's legal */
7588     debug(F100,"ttspdlist USETCSETSPEED","",0);
7589     spdlist[i++] = 50L;
7590 #ifndef UW7
7591     spdlist[i++] = 75L;
7592 #endif /* UW7 */
7593     spdlist[i++] = 110L;
7594 #ifndef UW7
7595     spdlist[i++] = 134L;
7596 #endif /* UW7 */
7597     spdlist[i++] = 150L;
7598     spdlist[i++] = 200L;
7599     spdlist[i++] = 300L;
7600     spdlist[i++] = 600L;
7601     spdlist[i++] = 1200L;
7602     spdlist[i++] = 1800L;
7603     spdlist[i++] = 2400L;
7604     spdlist[i++] = 4800L;
7605     spdlist[i++] = 8880L;
7606     spdlist[i++] = 9600L;
7607     spdlist[i++] = 14400L;
7608     spdlist[i++] = 19200L;
7609     spdlist[i++] = 28800L;
7610 #ifndef UW7
7611     spdlist[i++] = 33600L;
7612 #endif /* UW7 */
7613     spdlist[i++] = 38400L;
7614     spdlist[i++] = 57600L;
7615     spdlist[i++] = 76800L;
7616     spdlist[i++] = 115200L;
7617 #ifndef UW7
7618     spdlist[i++] = 153600L;
7619     spdlist[i++] = 230400L;
7620     spdlist[i++] = 307200L;
7621     spdlist[i++] = 460800L;
7622     spdlist[i++] = 921600L;
7623 #endif /* UW7 */
7624
7625 #else  /* USETCSETSPEED */
7626
7627     debug(F100,"ttspdlist no USETCSETSPEED","",0);
7628
7629 #ifdef B50
7630     debug(F101,"ttspdlist B50","",B50);
7631     spdlist[i++] = 50L;
7632 #endif /* B50 */
7633 #ifdef B75
7634     debug(F101,"ttspdlist B75","",B75);
7635     spdlist[i++] = 75L;
7636 #endif /* B75 */
7637 #ifdef B110
7638     debug(F101,"ttspdlist B110","",B110);
7639     spdlist[i++] = 110L;
7640 #endif /* B110 */
7641 #ifdef B134
7642     debug(F101,"ttspdlist B134","",B134);
7643     spdlist[i++] = 134L;
7644 #endif /* B134 */
7645 #ifdef B150
7646     debug(F101,"ttspdlist B150","",B150);
7647     spdlist[i++] = 150L;
7648 #endif /* B150 */
7649 #ifdef B200
7650     debug(F101,"ttspdlist B200","",B200);
7651     spdlist[i++] = 200L;
7652 #endif /* B200 */
7653 #ifdef B300
7654     debug(F101,"ttspdlist B300","",B300);
7655     spdlist[i++] = 300L;
7656 #endif /* B300 */
7657 #ifdef B600
7658     debug(F101,"ttspdlist B600","",B600);
7659     spdlist[i++] = 600L;
7660 #endif /* B600 */
7661 #ifdef B1200
7662     debug(F101,"ttspdlist B1200","",B1200);
7663     spdlist[i++] = 1200L;
7664 #endif /* B1200 */
7665 #ifdef B1800
7666     debug(F101,"ttspdlist B1800","",B1800);
7667     spdlist[i++] = 1800L;
7668 #endif /* B1800 */
7669 #ifdef B2400
7670     debug(F101,"ttspdlist B2400","",B2400);
7671     spdlist[i++] = 2400L;
7672 #endif /* B2400 */
7673 #ifdef B4800
7674     debug(F101,"ttspdlist B4800","",B4800);
7675     spdlist[i++] = 4800L;
7676 #endif /* B4800 */
7677 #ifdef B9600
7678     debug(F101,"ttspdlist B9600","",B9600);
7679     spdlist[i++] = 9600L;
7680 #endif /* B9600 */
7681 #ifdef B14400
7682     debug(F101,"ttspdlist B14400","",B14400);
7683     spdlist[i++] = 14400L;
7684 #endif /* B14400 */
7685 #ifdef B19200
7686     debug(F101,"ttspdlist B19200","",B19200);
7687     spdlist[i++] = 19200L;
7688 #else
7689 #ifdef EXTA
7690     debug(F101,"ttspdlist EXTA","",EXTA);
7691     spdlist[i++] = 19200L;
7692 #endif /* EXTA */
7693 #endif /* B19200 */
7694 #ifdef B28800
7695     debug(F101,"ttspdlist B28800","",B28800);
7696     spdlist[i++] = 28800L;
7697 #endif /* B28800 */
7698 #ifdef B33600
7699     debug(F101,"ttspdlist B33600","",B33600);
7700     spdlist[i++] = 33600L;
7701 #endif /* B33600 */
7702 #ifdef B38400
7703     debug(F101,"ttspdlist B38400","",B38400);
7704     spdlist[i++] = 38400L;
7705 #else
7706 #ifdef EXTB
7707     debug(F101,"ttspdlist EXTB","",EXTB);
7708     spdlist[i++] = 38400L;
7709 #endif /* EXTB */
7710 #endif /* B38400 */
7711 #ifdef _B57600
7712     debug(F101,"ttspdlist _B57600","",_B57600);
7713     spdlist[i++] = 57600L;
7714 #else
7715 #ifdef B57600
7716     debug(F101,"ttspdlist B57600","",B57600);
7717     spdlist[i++] = 57600L;
7718 #endif /* B57600 */
7719 #endif /* _B57600 */
7720 #ifdef B76800
7721     debug(F101,"ttspdlist B76800","",B76800);
7722     spdlist[i++] = 76800L;
7723 #endif /* B76800 */
7724 #ifdef _B115200
7725     debug(F101,"ttspdlist _B115200","",_B115200);
7726     spdlist[i++] = 115200L;
7727 #else
7728 #ifdef B115200
7729     debug(F101,"ttspdlist B115200","",B115200);
7730     spdlist[i++] = 115200L;
7731 #endif /* B115200 */
7732 #endif /* _B115200 */
7733 #ifdef B153600
7734     debug(F101,"ttspdlist B153600","",B153600);
7735     spdlist[i++] = 153600L;
7736 #endif /* B153600 */
7737 #ifdef B230400
7738     debug(F101,"ttspdlist B230400","",B230400);
7739     spdlist[i++] = 230400L;
7740 #endif /* B230400 */
7741 #ifdef B307200
7742     debug(F101,"ttspdlist B307200","",B307200);
7743     spdlist[i++] = 307200L;
7744 #endif /* B307200 */
7745 #ifdef B460800
7746     debug(F101,"ttspdlist B460800","",B460800);
7747     spdlist[i++] = 460800L;
7748 #endif /* B460800 */
7749 #ifdef B921600
7750     debug(F101,"ttspdlist B921600","",B921600);
7751     spdlist[i++] = 921600L;
7752 #endif /* B921600 */
7753 #endif /* USETCSETSPEED */
7754     spdlist[0] = i - 1;                 /* Return count in 0th element */
7755     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
7756     return((long *)spdlist);
7757 }
7758
7759 /* T T G S P D  -  Get speed of currently selected tty line  */
7760
7761 /*
7762   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
7763   the real speed.  On some systems, it returns the line's nominal speed, from
7764   /etc/ttytab.  Even if you SET SPEED to something else, this function might
7765   not notice.
7766 */
7767 long
7768 ttgspd() {                              /* Get current serial device speed */
7769 #ifdef NOLOCAL
7770     return(-1L);
7771 #else
7772 #ifdef POSIX
7773     speed_t                             /* Should be unsigned */
7774 #else
7775     int                                 /* Isn't unsigned */
7776 #endif /* POSIX */
7777       s;
7778     int x;
7779     long ss;
7780 #ifdef OLINUXHISPEED
7781     unsigned int spd_flags = 0;
7782     struct serial_struct serinfo;
7783 #endif /* OLINUXHISPEED */
7784
7785 #ifdef NETCONN
7786     if (netconn) {
7787 #ifdef TN_COMPORT
7788         if (istncomport())
7789           return(tnc_get_baud());
7790         else
7791 #endif /* TN_COMPORT */
7792           return(-1);                   /* -1 if network connection */
7793     }
7794 #endif /* NETCONN */
7795 #ifdef NETCMD
7796     if (ttpipe) return(-1);
7797 #endif /* NETCMD */
7798 #ifdef NETPTY
7799     if (ttpty) return(-1);
7800 #endif /* NETPTY */
7801
7802     debug(F101,"ttgspd ttyfd","",ttyfd);
7803
7804 #ifdef USETCSETSPEED
7805
7806     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7807     debug(F101,"ttgspd tcgetattr","",x);
7808     if (x < 0)
7809       return(-1);
7810     errno = 0;
7811     s = tcgetspeed(TCS_ALL, &ttcur);
7812     debug(F101,"ttsspd TCGETSPEED speed","",s);
7813     if (s == 0) {
7814         long s1, s2;
7815         s1 = tcgetspeed(TCS_IN, &ttcur);
7816         s2 = tcgetspeed(TCS_OUT, &ttcur);
7817         if (s1 == 1200L && s2 == 75L)
7818           return(8880L);
7819     }
7820 #ifdef DEBUG
7821     if (errno & deblog) {
7822         debug(F101,"ttsspd TCGETSPEED errno","",errno);
7823     }
7824 #endif /* DEBUG */
7825     return(s);
7826
7827 #else  /* Not USETCSETSPEED */
7828
7829 #ifdef Plan9
7830     if (ttyfd < 0)
7831       ss = -1;
7832     else
7833       ss = ttylastspeed;
7834 #else
7835 #ifdef OLINUXHISPEED
7836     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
7837 #endif /* OLINUXHISPEED */
7838
7839     if (ttyfd < 0) {
7840 #ifdef BSD44ORPOSIX
7841         s = cfgetospeed(&ccold);
7842         debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
7843 #else
7844 #ifdef ATTSV
7845         s = ccold.c_cflag & CBAUD;
7846         debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
7847 #else
7848         s = ccold.sg_ospeed;            /* (obtained by congm()) */
7849         debug(F101,"ttgspd sg_ospeed 1","",s);
7850 #endif /* ATTSV */
7851 #endif /* BSD44POSIX */
7852
7853     } else {
7854 #ifdef BSD44ORPOSIX
7855         if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
7856         s = cfgetospeed(&ttcur);
7857         debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
7858 #ifdef OLINUXHISPEED
7859         if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
7860           spd_flags = serinfo.flags & ASYNC_SPD_MASK;
7861         debug(F101,"ttgspd spd_flags","",spd_flags);
7862 #endif /* OLINUXHISPEED */
7863 #else
7864 #ifdef ATTSV
7865         x = ioctl(ttyfd,TCGETA,&ttcur);
7866         debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
7867         debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
7868         if (x < 0) return(-1);
7869         s = ttcur.c_cflag & CBAUD;
7870         debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
7871 #else
7872 #ifdef BELLV10
7873         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7874         debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
7875         if (x < 0) return(-1);
7876         s = tdcur.ospeed;
7877         debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
7878 #else
7879         x = gtty(ttyfd,&ttcur);
7880         debug(F101,"ttgspd gtty 2 x","",x);
7881         debug(F101,"ttgspd gtty 2 errno","",errno);
7882         if (x < 0) return(-1);
7883         s = ttcur.sg_ospeed;
7884         debug(F101,"ttgspd gtty 2 speed","",s);
7885 #endif /* BELLV10 */
7886 #endif /* ATTSV */
7887 #endif /* BSD44ORPOSIX */
7888     }
7889     debug(F101,"ttgspd code","",s);
7890 #ifdef OLINUXHISPEED
7891     debug(F101,"ttgspd spd_flags","",spd_flags);
7892 #endif /* OLINUXHISPEED */
7893     switch (s) {
7894 #ifdef B0
7895       case B0:    ss = 0L; break;
7896 #endif /* B0 */
7897
7898 #ifndef MINIX
7899 /*
7900  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
7901  etc, making for many "duplicate case in switch" errors, which are fatal.
7902 */
7903 #ifdef B50
7904       case B50:   ss = 50L; break;
7905 #endif /* B50 */
7906 #ifdef B75
7907       case B75:   ss = 75L; break;
7908 #endif /* B75 */
7909 #endif /* MINIX */
7910
7911 #ifdef B110
7912       case B110:  ss = 110L; break;
7913 #endif /* B110 */
7914
7915 #ifndef MINIX
7916 #ifdef B134
7917       case B134:  ss = 134L; break;
7918 #endif /* B134 */
7919 #ifdef B150
7920       case B150:  ss = 150L; break;
7921 #endif /* B150 */
7922 #endif /* MINIX */
7923
7924 #ifdef B200
7925       case B200:  ss = 200L; break;
7926 #endif /* B200 */
7927
7928 #ifdef B300
7929       case B300:  ss = 300L; break;
7930 #endif /* B300 */
7931
7932 #ifdef B600
7933       case B600:  ss = 600L; break;
7934 #endif /* B600 */
7935
7936 #ifdef B1200
7937       case B1200: ss = 1200L; break;
7938 #endif /* B1200 */
7939
7940 #ifdef B1800
7941       case B1800: ss = 1800L; break;
7942 #endif /* B1800 */
7943
7944 #ifdef B2400
7945       case B2400: ss = 2400L; break;
7946 #endif /* B2400 */
7947
7948 #ifdef B4800
7949       case B4800: ss = 4800L; break;
7950 #endif /* B4800 */
7951
7952 #ifdef B7200
7953       case B7200: ss = 7200L; break;
7954 #endif /* B7200 */
7955
7956 #ifdef B9600
7957       case B9600: ss = 9600L; break;
7958 #endif /* B9600 */
7959
7960 #ifdef B19200
7961       case B19200: ss = 19200L; break;
7962 #else
7963 #ifdef EXTA
7964       case EXTA: ss = 19200L; break;
7965 #endif /* EXTA */
7966 #endif /* B19200 */
7967
7968 #ifdef MINIX2
7969 /* End of hack to make MINIX2 use MINIX1 speed setting */
7970 #undef MINIX
7971 #endif /* MINIX2 */
7972
7973 #ifndef MINIX
7974 #ifdef B38400
7975       case B38400:
7976         ss = 38400L;
7977 #ifdef OLINUXHISPEED
7978         switch(spd_flags) {
7979           case ASYNC_SPD_HI:  ss =  57600L; break;
7980           case ASYNC_SPD_VHI: ss = 115200L; break;
7981         }
7982 #endif /* OLINUXHISPEED */
7983         break;
7984 #else
7985 #ifdef EXTB
7986       case EXTB: ss = 38400L; break;
7987 #endif /* EXTB */
7988 #endif /* B38400 */
7989 #endif /* MINIX */
7990
7991 #ifdef HPUX
7992 #ifdef _B57600
7993       case _B57600: ss = 57600L; break;
7994 #endif /* _B57600 */
7995 #ifdef _B115200
7996       case _B115200: ss = 115200L; break;
7997 #endif /* _B115200 */
7998 #else
7999 #ifdef B57600
8000       case B57600: ss = 57600L; break;
8001 #endif /* B57600 */
8002 #ifdef B76800
8003       case B76800: ss = 76800L; break;
8004 #endif /* B76800 */
8005 #ifdef B115200
8006       case B115200: ss = 115200L; break;
8007 #endif /* B115200 */
8008 #ifdef B153600
8009       case B153600: ss = 153600L; break;
8010 #endif /* B153600 */
8011 #ifdef B230400
8012       case B230400: ss = 230400L; break;
8013 #endif /* B230400 */
8014 #ifdef B307200
8015       case B307200: ss = 307200L; break;
8016 #endif /* B307200 */
8017 #ifdef B460800
8018       case B460800: ss = 460800L; break;
8019 #endif /* B460800 */
8020 #endif /* HPUX */
8021 #ifdef B921600
8022       case 92160: ss = 921600L; break;
8023 #endif /* B921600 */
8024       default:
8025         ss = -1; break;
8026     }
8027 #endif /* Plan9 */
8028     debug(F101,"ttgspd speed","",ss);
8029     return(ss);
8030
8031 #endif /* USETCSETSPEED */
8032 #endif /* NOLOCAL */
8033 }
8034 #ifdef MINIX2                           /* Another hack alert */
8035 #define MINIX
8036 #endif /* MINIX2 */
8037
8038 /*
8039   FIONREAD data type...  This has been defined as "long" for many, many
8040   years, and it worked OK until 64-bit platforms appeared.  Thus we use
8041   int for 64-bit platforms, but keep long for the others.  If we changed
8042   the default PEEKTYPE to int, this would probably break 16-bit builds
8043   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
8044   of which we have no way of testing any more.  Therefore, do not change
8045   the default definition of PEEKTYPE -- only add exceptions to it as needed.
8046 */
8047 #ifdef COHERENT
8048 #ifdef FIONREAD
8049 #undef FIONREAD
8050 #endif /* FIONREAD */
8051 /* #define FIONREAD TIOCQUERY */
8052 /* #define PEEKTYPE int */
8053 #else  /* Not COHERENT... */
8054
8055 #ifdef OSF32                            /* Digital UNIX 3.2 or higher */
8056 #define PEEKTYPE int
8057 #else
8058 #define PEEKTYPE long                   /* Elsewhere (see notes above) */
8059 #endif /* OSF32 */
8060 #endif /* COHERENT */
8061
8062 /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
8063
8064 #ifdef MYREAD
8065
8066 /* Private buffer for myread() and its companions.  Not for use by anything
8067  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
8068  * allowed to read my_count.
8069  *
8070  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
8071  *
8072  * A global parity mask variable could be useful too.  We could use it to
8073  * let myread() strip the parity on its own, instead of stripping sign
8074  * bits as it does now.
8075  */
8076 #ifdef BIGBUFOK
8077 #define MYBUFLEN 32768
8078 #else
8079 #ifdef pdp11
8080 #define MYBUFLEN 256
8081 #else
8082 #define MYBUFLEN 1024
8083 #endif /* pdp11 */
8084 #endif /* BIGBUFOK */
8085
8086 #ifdef ANYX25
8087 #undef MYBUFLEN
8088 #define MYBUFLEN 256
8089 /*
8090   On X.25 connections, there is an extra control byte at the beginning.
8091 */
8092 static CHAR x25buf[MYBUFLEN+1];         /* Communication device input buffer */
8093 static CHAR  *mybuf = x25buf+1;
8094 #else
8095 static CHAR mybuf[MYBUFLEN];
8096 #endif /* ANYX25 */
8097
8098 static int my_count = 0;                /* Number of chars still in mybuf */
8099 static int my_item = -1;                /* Last index read from mybuf[]   */
8100
8101 /*  T T P E E K  --  Peek into our internal communications input buffers. */
8102
8103 /*
8104   NOTE: This routine is peculiar to UNIX, and is used only by the
8105   select()-based CONNECT module, ckucns.c.  It need not be replicated in
8106   the ck?tio.c of other platforms.
8107 */
8108 int
8109 ttpeek() {
8110 #ifdef TTLEBUF
8111     int rc = 0;
8112     if (ttpush >= 0)
8113       rc++;
8114     rc += le_inbuf();
8115     if (rc > 0)
8116       return(rc);
8117     else
8118 #endif /* TTLEBUF */
8119
8120 #ifdef MYREAD
8121     return(my_count);
8122 #else
8123     return(0);
8124 #endif /* MYREAD */
8125 }
8126
8127 /* myread() -- Efficient read of one character from communications line.
8128  *
8129  * Uses a private buffer to minimize the number of expensive read() system
8130  * calls.  Essentially performs the equivalent of read() of 1 character, which
8131  * is then returned.  By reading all available input from the system buffers
8132  * to the private buffer in one chunk, and then working from this buffer, the
8133  * number of system calls is reduced in any case where more than one character
8134  * arrives during the processing of the previous chunk, for instance high
8135  * baud rates or network type connections where input arrives in packets.
8136  * If the time needed for a read() system call approaches the time for more
8137  * than one character to arrive, then this mechanism automatically compensates
8138  * for that by performing bigger read()s less frequently.  If the system load
8139  * is high, the same mechanism compensates for that too.
8140  *
8141  * myread() is a macro that returns the next character from the buffer.  If the
8142  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
8143  * returns.
8144  *
8145  * This should be efficient enough for any one-character-at-a-time loops.
8146  * For even better efficiency you might use memcpy()/bcopy() or such between
8147  * buffers (since they are often better optimized for copying), but it may not
8148  * be worth it if you have to take an extra pass over the buffer to strip
8149  * parity and check for CTRL-C anyway.
8150  *
8151  * Note that if you have been using myread() from another program module, you
8152  * may have some trouble accessing this macro version and the private variables
8153  * it uses.  In that case, just add a function in this module, that invokes the
8154  * macro.
8155  */
8156 #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
8157
8158 /* Specification: Push back up to one character onto myread()'s queue.
8159  *
8160  * This implementation: Push back characters into mybuf. At least one character
8161  * must have been read through myread() before myunrd() may be used.  After
8162  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
8163  * one character can be pushed back, but only one character is guaranteed.
8164  * Since a previous myread() must have read its character out of mybuf[],
8165  * that guarantees that there is space for at least one character.  If push
8166  * back was really needed after EOF, a small addition could provide that.
8167  *
8168  * myunrd() is currently not called from anywhere inside kermit...
8169  */
8170 #ifdef COMMENT /* not used */
8171 myunrd(ch) CHAR ch; {
8172     if (my_item >= 0) {
8173         mybuf[my_item--] = ch;
8174         ++my_count;
8175     }
8176 }
8177 #endif /* COMMENT */
8178
8179 /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
8180
8181 static CHAR * pushbuf = NULL;
8182 /* static int pushed = 0; */
8183
8184 int
8185 ttpushback(s,n) CHAR * s; int n; {
8186     debug(F101,"ttpushback n","",n);
8187     if (pushbuf || n > MYBUFLEN || n < 1)
8188       return(-1);
8189     debug(F101,"ttpushback my_count","",my_count);
8190     if (my_count > 0) {
8191         if (!(pushbuf = (CHAR *)malloc(n+1)))
8192           return(-1);
8193         memcpy(pushbuf,mybuf,my_count);
8194         /* pushed = my_count; */ /* (set but never used) */
8195     }
8196     memcpy(mybuf,s,n);
8197     my_count = n;
8198     my_item = -1;
8199     return(0);
8200 }
8201
8202 /* mygetbuf() -- Fill buffer for myread() and return first character.
8203  *
8204  * This function is what myread() uses when it can't get the next character
8205  * directly from its buffer.  First, it calls a system dependent myfillbuf()
8206  * to read at least one new character into the buffer, and then it returns
8207  * the first character just as myread() would have done.  This function also
8208  * is responsible for all error conditions that myread() can indicate.
8209  *
8210  * Returns: When OK     => a positive character, 0 or greater.
8211  *          When EOF    => -2.
8212  *          When error  => -3, error code in errno.
8213  *
8214  * Older myread()s additionally returned -1 to indicate that there was nothing
8215  * to read, upon which the caller would call myread() again until it got
8216  * something.  The new myread()/mygetbuf() always gets something.  If it
8217  * doesn't, then make it do so!  Any program that actually depends on the old
8218  * behaviour will break.
8219  *
8220  * The older version also used to return -2 both for EOF and other errors,
8221  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
8222  * other errors now return different results, although Kermit currently never
8223  * checks to see which it was.  It just disconnects in both cases.
8224  *
8225  * Kermit lets the user use the quit key to perform some special commands
8226  * during file transfer.  This causes read(), and thus also mygetbuf(), to
8227  * finish without reading anything and return the EINTR error.  This should
8228  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
8229  * but if there is nothing to read, this could delay Kermit's reaction to
8230  * the command, and make Kermit appear unresponsive.
8231  *
8232  * The debug() call should be removed for optimum performance.
8233  */
8234 int
8235 mygetbuf() {
8236     int x;
8237     errno = 0;
8238 #ifdef DEBUG
8239     if (deblog && my_count > 0)
8240       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
8241 #endif /* DEBUG */
8242     if (my_count <= 0)
8243       my_count = myfillbuf();
8244
8245 #ifdef DEBUG
8246 #ifdef COMMENT
8247     if (deblog) debug(F101, "mygetbuf read", "", my_count);
8248 #else /* COMMENT */
8249     if (deblog) hexdump("mygetbuf read", mybuf, my_count);
8250 #endif /* COMMENT */
8251 #endif /* DEBUG */
8252     x = my_count;
8253     if (my_count <= 0) {
8254         my_count = 0;
8255         my_item = -1;
8256         debug(F101,"mygetbuf errno","",errno);
8257 #ifdef TCPSOCKET
8258         if (netconn && ttnet == NET_TCPB && errno != 0) {
8259             if (errno != EINTR) {
8260                 debug(F101,"mygetbuf TCP error","",errno);
8261                 ttclos(0);              /* Close the connection. */
8262             }
8263             return(-3);
8264         }
8265 #endif /* TCPSOCKET */
8266         if (!netconn && xlocal && errno) {
8267             if (errno != EINTR) {
8268                 debug(F101,"mygetbuf SERIAL error","",errno);
8269                 x = -3;
8270                 ttclos(0);              /* Close the connection. */
8271             }
8272         }
8273         return((x < 0) ? -3 : -2);
8274     }
8275     --my_count;
8276     return((unsigned)(0xff & mybuf[my_item = 0]));
8277 }
8278
8279 /* myfillbuf():
8280  * System-dependent read() into mybuf[], as many characters as possible.
8281  *
8282  * Returns: OK => number of characters read, always more than zero.
8283  *          EOF => 0
8284  *          Error => -1, error code in errno.
8285  *
8286  * If there is input available in the system's buffers, all of it should be
8287  * read into mybuf[] and the function return immediately.  If no input is
8288  * available, it should wait for a character to arrive, and return with that
8289  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
8290  * character, but be aware that any such delay lengthens the packet turnaround
8291  * time during kermit file transfers.  Should never return with zero characters
8292  * unless EOF or irrecoverable read error.
8293  *
8294  * Correct functioning depends on the correct tty parameters being used.
8295  * Better control of current parameters is required than may have been the
8296  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
8297  * no longer be sometimes off and sometimes on like it used to, unless a
8298  * special myfillbuf() is written to handle that.  Otherwise the ordinary
8299  * myfillbuf()s may think they have come to EOF.
8300  *
8301  * If your system has a facility to directly perform the functioning of
8302  * myfillbuf(), then use it.  If the system can tell you how many characters
8303  * are available in its buffers, then read that amount (but not less than 1).
8304  * If the system can return a special indication when you try to read without
8305  * anything to read, while allowing you to read all there is when there is
8306  * something, you may loop until there is something to read, but probably that
8307  * is not good for the system load.
8308  */
8309
8310 #ifdef SVORPOSIX
8311         /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
8312          * and CLOCAL set any way you like.  This way, read() will do exactly
8313          * what is required by myfillbuf(): If there is data in the buffers
8314          * of the O.S., all available data is read into mybuf, up to the size
8315          * of mybuf.  If there is none, the first character to arrive is
8316          * awaited and returned.
8317          */
8318 int
8319 myfillbuf() {
8320     int fd, n;
8321 #ifdef NETCMD
8322     if (ttpipe)
8323       fd = fdin;
8324     else
8325 #endif /* NETCMD */
8326       fd = ttyfd;
8327
8328 #ifdef sxaE50
8329     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
8330     /* necessary for the sxa E50, but it is. */
8331     return read(fd, mybuf, 255);
8332 #else
8333 #ifdef BEOSORBEBOX
8334     while (1) {
8335 #ifdef NETCONN
8336         if (netconn) {
8337             n = netxin(sizeof(mybuf), (char *)mybuf);
8338             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
8339         }
8340         else
8341 #endif /* NETCONN */
8342           n = read(fd, mybuf, sizeof(mybuf));
8343         debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
8344         if (n > 0)
8345           return(n);
8346         snooze(1000.0);
8347     }
8348 #else /* BEOSORBEBOX */
8349     errno = 0;
8350     debug(F100,"SVORPOSIX myfillbuf calling read()","",0);
8351 #ifdef IBMX25
8352     if (netconn && (nettype == NET_IX25)) {
8353         /* can't use sizeof because mybuf is a pointer, and not an array! */
8354         n = x25xin( MYBUFLEN, mybuf );
8355     } else
8356 #endif /* IBMX25 */
8357
8358 #ifdef CK_SSL
8359       if (ssl_active_flag || tls_active_flag) {
8360           int error, n = 0;
8361           while (n == 0) {
8362               if (ssl_active_flag)
8363                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8364               else if (tls_active_flag)
8365                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8366               else
8367                 break;
8368               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8369                 case SSL_ERROR_NONE:
8370                   if (n > 0)
8371                     return(n);
8372                   if (n < 0)
8373                     return(-2);
8374                   msleep(50);
8375                   break;
8376                 case SSL_ERROR_WANT_WRITE:
8377                 case SSL_ERROR_WANT_READ:
8378                   return(-1);
8379                 case SSL_ERROR_SYSCALL:
8380                   if (n != 0)
8381                     return(-1);
8382                 case SSL_ERROR_WANT_X509_LOOKUP:
8383                 case SSL_ERROR_SSL:
8384                 case SSL_ERROR_ZERO_RETURN:
8385                 default:
8386                   ttclos(0);
8387                   return(-3);
8388             }
8389         }
8390     }
8391 #endif /* CK_SSL */
8392 #ifdef CK_KERBEROS
8393 #ifdef KRB4
8394 #ifdef RLOGCODE
8395     if (ttnproto == NP_EK4LOGIN) {
8396         if ((n = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8397           return(-3);
8398         else
8399           return(n);
8400     }
8401 #endif /* RLOGCODE */
8402 #endif /* KRB4 */
8403 #ifdef KRB5
8404 #ifdef RLOGCODE
8405     if (ttnproto == NP_EK5LOGIN) {
8406         if ((n = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8407           return(-3);
8408         else
8409           return(n);
8410     }
8411 #endif /* RLOGCODE */
8412 #ifdef KRB5_U2U
8413     if (ttnproto == NP_K5U2U) {
8414         if ((n = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8415           return(-3);
8416         else
8417           return(n);
8418     }
8419 #endif /* KRB5_U2U */
8420 #endif /* KRB5 */
8421 #endif /* CK_KERBEROS */
8422
8423 #ifdef NETPTY
8424 #ifdef HAVE_PTYTRAP
8425     /* Special handling for HP-UX pty i/o */
8426   ptyread:
8427     if (ttpty && pty_trap_pending(ttyfd) > 0) {
8428         if (pty_trap_handler(ttyfd) > 0) {
8429             ttclos(0);
8430             return(-3);
8431         }
8432     }
8433 #endif /* HAVE_PTYTRAP */
8434 #endif /* NETPTY */
8435     n = read(fd, mybuf, sizeof(mybuf));
8436     debug(F101,"SVORPOSIX myfillbuf","",n);
8437     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
8438     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
8439     if (n < 1) {
8440 #ifdef NETPTY
8441 #ifdef HAVE_PTYTRAP
8442         /* When we have a PTY trap in place the connection cannot */
8443         /* be closed until the trap receives a close indication.  */
8444         if (n == 0 && ttpty)
8445             goto ptyread;
8446 #endif /* HAVE_PTYTRAP */
8447 #endif /* NETPTY */
8448         return(-3);
8449     }
8450     return(n);
8451 #endif /* BEOSORBEBOX */
8452 #endif /* sxaE50 */
8453 }
8454
8455 #else /* not AT&T or POSIX */
8456
8457 #ifdef aegis
8458         /* This is quoted from the old myread().  The semantics seem to be
8459          * alright, but maybe errno would not need to be set even when
8460          * there is no error?  I don't know aegis.
8461          */
8462 int
8463 myfillbuf() {
8464     int count;
8465 #ifdef NETCMD
8466     if (ttpipe)
8467       fd = fdin;
8468     else
8469 #endif /* NETCMD */
8470       fd = ttyfd;
8471
8472     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
8473     errno = EIO;
8474     if (st.all == ios_$get_conditional_failed) /* get at least one */
8475       count = ios_$get((short)fd, 0, mybuf, 1L, st);
8476     if (st.all == ios_$end_of_file)
8477       return(-3);
8478     else if (st.all != status_$ok) {
8479         errno = EIO;
8480         return(-1);
8481     }
8482     return(count > 0 ? count : -3);
8483 }
8484 #else /* !aegis */
8485
8486 #ifdef FIONREAD
8487         /* This is for systems with FIONREAD.  FIONREAD returns the number
8488          * of characters available for reading. If none are available, wait
8489          * until something arrives, otherwise return all there is.
8490          */
8491 int
8492 myfillbuf() {
8493     PEEKTYPE avail = 0;
8494     int x, fd;
8495 #ifdef NETCMD
8496     if (ttpipe)
8497       fd = fdin;
8498     else
8499 #endif /* NETCMD */
8500       fd = ttyfd;
8501
8502 #ifdef SUNX25
8503 /*
8504   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
8505   Depends on SunOS having FIONREAD, not because we use it, but just so this
8506   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
8507
8508   We call x25xin() instead of read() so that Q-Bit packets, which contain
8509   X.25 service-level information (e.g. PAD parameter changes), can be processed
8510   transparently to the upper-level code.  This is a blocking read, and so
8511   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
8512 */
8513     extern int nettype;
8514     if (netconn && nettype == NET_SX25) {
8515         while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
8516         return(x - 1);          /* "-1" compensates for extra status byte */
8517     }
8518 #endif /* SUNX25 */
8519
8520 #ifdef CK_SSL
8521     if (ssl_active_flag || tls_active_flag) {
8522         int error, n = 0;
8523         while (n == 0) {
8524             if (ssl_active_flag)
8525               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8526             else
8527               n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8528             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8529               case SSL_ERROR_NONE:
8530                 if (n > 0)
8531                   return(n);
8532                 if (n < 0)
8533                   return(-2);
8534                 msleep(50);
8535                 break;
8536               case SSL_ERROR_WANT_WRITE:
8537               case SSL_ERROR_WANT_READ:
8538                 return(-1);
8539               case SSL_ERROR_SYSCALL:
8540                 if (n != 0)
8541                   return(-1);
8542               case SSL_ERROR_WANT_X509_LOOKUP:
8543               case SSL_ERROR_SSL:
8544               case SSL_ERROR_ZERO_RETURN:
8545               default:
8546                 ttclos(0);
8547                 return(-2);
8548             }
8549         }
8550     }
8551 #endif /* CK_SSL */
8552 #ifdef CK_KERBEROS
8553 #ifdef KRB4
8554 #ifdef RLOGCODE
8555     if (ttnproto == NP_EK4LOGIN) {
8556         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8557           return(-1);
8558         else
8559           return(x);
8560     }
8561 #endif /* RLOGCODE */
8562 #endif /* KRB4 */
8563 #ifdef KRB5
8564 #ifdef RLOGCODE
8565     if (ttnproto == NP_EK5LOGIN) {
8566         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8567           return(-1);
8568         else
8569           return(x);
8570     }
8571 #endif /* RLOGCODE */
8572 #ifdef KRB5_U2U
8573     if (ttnproto == NP_K5U2U) {
8574         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8575           return(-1);
8576         else
8577           return(x);
8578     }
8579 #endif /* KRB5_U2U */
8580 #endif /* KRB5 */
8581 #endif /* CK_KERBEROS */
8582
8583     errno = 0;
8584     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
8585     x = ioctl(fd, FIONREAD, &avail);
8586 #ifdef DEBUG
8587     if (deblog) {
8588         debug(F101,"myfillbuf FIONREAD","",x);
8589         debug(F101,"myfillbuf FIONREAD avail","",avail);
8590         debug(F101,"myfillbuf FIONREAD errno","",errno);
8591     }
8592 #endif /* DEBUG */
8593     if (x < 0 || avail == 0)
8594       avail = 1;
8595
8596     if (avail > MYBUFLEN)
8597       avail = MYBUFLEN;
8598
8599     errno = 0;
8600
8601     x = read(fd, mybuf, (int) avail);
8602 #ifdef DEBUG
8603     if (deblog) {
8604         debug(F101,"myfillbuf avail","",avail);
8605         debug(F101,"myfillbuf read","",x);
8606         debug(F101,"myfillbuf read errno","",errno);
8607         if (x > 0)
8608           hexdump("myfillbuf mybuf",mybuf,x);
8609     }
8610 #endif /* DEBUG */
8611     if (x < 1) x = -3;                  /* read 0 == connection loss */
8612     return(x);
8613 }
8614
8615 #else /* !FIONREAD */
8616 /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
8617 /* When there is no other possibility, read 1 character at a time. */
8618 int
8619 myfillbuf() {
8620     int x;
8621
8622 #ifdef CK_SSL
8623     if (ssl_active_flag || tls_active_flag) {
8624         int error, n = 0;
8625         while (n == 0) {
8626             if (ssl_active_flag)
8627               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8628             else
8629               count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8630             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8631               case SSL_ERROR_NONE:
8632                 if (n > 0)
8633                   return(n);
8634                 if (n < 0)
8635                   return(-2);
8636                 msleep(50);
8637                 break;
8638               case SSL_ERROR_WANT_WRITE:
8639               case SSL_ERROR_WANT_READ:
8640                 return(-1);
8641               case SSL_ERROR_SYSCALL:
8642                 if (n != 0)
8643                   return(-1);
8644               case SSL_ERROR_WANT_X509_LOOKUP:
8645               case SSL_ERROR_SSL:
8646               case SSL_ERROR_ZERO_RETURN:
8647               default:
8648                 ttclos(0);
8649                 return(-2);
8650             }
8651         }
8652     }
8653 #endif /* CK_SSL */
8654 #ifdef CK_KERBEROS
8655 #ifdef KRB4
8656 #ifdef RLOGCODE
8657     if (ttnproto == NP_EK4LOGIN) {
8658         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8659           return(-1);
8660         else
8661           return(len);
8662     }
8663 #endif /* RLOGCODE */
8664 #endif /* KRB4 */
8665 #ifdef KRB5
8666 #ifdef RLOGCODE
8667     if (ttnproto == NP_EK5LOGIN) {
8668         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8669           return(-1);
8670         else
8671           return(len);
8672     }
8673 #endif /* RLOGCODE */
8674 #ifdef KRB5_U2U
8675     if (ttnproto == NP_K5U2U) {
8676         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8677           return(-1);
8678         else
8679           return(len);
8680     }
8681 #endif /* KRB5_U2U */
8682 #endif /* KRB5 */
8683 #endif /* CK_KERBEROS */
8684
8685 #ifdef NETCMD
8686     if (ttpipe)
8687       fd = fdin;
8688     else
8689 #endif /* NETCMD */
8690       fd = ttyfd;
8691     x = read(fd, mybuf, 1);
8692     return(x > 0 ? x : -3);
8693 }
8694
8695 #endif /* !FIONREAD */
8696 #endif /* !aegis */
8697 #endif /* !ATTSV */
8698
8699 #endif /* MYREAD */
8700
8701 #ifdef MINIX2
8702 #undef MINIX
8703 #endif /* MINIX2 */
8704
8705 /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
8706 /*
8707   Call with the IAC that was encountered.
8708   Returns:
8709    -3: If connection has dropped or gone bad.
8710    -2: On Telnet protocol error resulting in inconsistent states.
8711     0: If negotiation OK and caller has nothing to do.
8712     1: If packet start character has changed (new value is in global stchr).
8713   255: If there was a quoted IAC as data.
8714    or: Not at all if we got a legitimate Telnet Logout request.
8715 */
8716 #ifdef TCPSOCKET
8717 static int
8718 tt_tnopt(n) int n; {                    /* Handle Telnet options */
8719     /* In case caller did not already check these conditions...  */
8720     if (n == IAC &&
8721         ((xlocal && netconn && IS_TELNET()) ||
8722          (!xlocal && sstelnet))) {
8723         extern int duplex;
8724         extern int server;
8725         int tx = 0;
8726         debug(F100,"ttinl calling tn_doop()","",0);
8727         tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
8728         debug(F111,"ttinl tn_doop() returned","tx",tx);
8729         switch (tx) {
8730           case 0:
8731             return(0);
8732           case -1:                      /* I/O error */
8733             ttimoff();                  /* Turn off timer */
8734             return(-3);
8735           case -2:                      /* Connection failed. */
8736           case -3:
8737             ttimoff();                  /* Turn off timer */
8738             ttclos(0);
8739             return(-3);
8740           case 1:                       /* ECHO change */
8741             duplex = 1;
8742             return(0);
8743           case 2:                       /* ECHO change */
8744             duplex = 0;
8745             return(0);
8746           case 3:                       /* Quoted IAC */
8747             n = 255;
8748             return((unsigned)255);
8749 #ifdef IKS_OPTION
8750           case 4: {
8751               if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
8752 #ifdef IKSD
8753                   && !inserver
8754 #endif /* IKSD */
8755                   ) {                   /* Remote in Server mode */
8756                   ttimoff();            /* Turn off timer */
8757                   debug(F100,"u_start and !inserver","",0);
8758                   return(-2);           /* End server mode */
8759               } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
8760                          server
8761                          ) {            /* I'm no longer in Server Mode */
8762                   debug(F100,"me_start and server","",0);
8763                   ttimoff();
8764                   return(-2);
8765               }
8766               return(0);
8767           }
8768           case 5: {                     /* Start character change */
8769               /* extern CHAR stchr; */
8770               /* start = stchr; */
8771               return(1);
8772           }
8773 #endif /* IKS_OPTION */
8774           case 6:                       /* Remote Logout */
8775             ttimoff();
8776             ttclos(0);
8777 #ifdef IKSD
8778             if (inserver && !local)
8779               doexit(GOOD_EXIT,0);
8780             else
8781 #endif /* IKSD */
8782               return(-2);
8783           default:
8784             return(0);
8785         }
8786     } else
8787       return(0);
8788 }
8789 #endif /* TCPSOCKET */
8790
8791 /*  T T F L U I  --  Flush tty input buffer */
8792
8793 void
8794 ttflux() {                              /* But first... */
8795 #ifdef MYREAD
8796 /*
8797   Flush internal MYREAD buffer.
8798 */
8799 #ifdef TCPSOCKET
8800     int dotnopts, x;
8801     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
8802                  (!xlocal && sstelnet)));
8803 #endif /* TCPSOCKET */
8804     debug(F101,"ttflux my_count","",my_count);
8805 #ifdef TCPSOCKET
8806     if (dotnopts) {
8807         CHAR ch = '\0';
8808         while (my_count > 0) {
8809             ch = myread();
8810 #ifdef CK_ENCRYPTION
8811             if (TELOPT_U(TELOPT_ENCRYPTION))
8812               ck_tn_decrypt(&ch,1);
8813 #endif /* CK_ENCRYPTION */
8814             if (ch == IAC)
8815               x = tt_tnopt(ch);
8816         }
8817     } else
8818 #endif /* TCPSOCKET */
8819 #ifdef COMMENT
8820 #ifdef CK_ENCRYPTION
8821     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
8822       ck_tn_decrypt(&mybuf[my_item+1],my_count);
8823 #endif /* CK_ENCRYPTION */
8824 #endif /* COMMENT */
8825     my_count = 0;                       /* Reset count to zero */
8826     my_item = -1;                       /* And buffer index to -1 */
8827 #endif /* MYREAD */
8828 }
8829
8830 int
8831 ttflui() {
8832     int n, fd;
8833 #ifdef TCPSOCKET
8834     int dotnopts;
8835     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
8836                  (!xlocal && sstelnet)));
8837 #endif /* TCPSOCKET */
8838
8839 #ifdef NETCMD
8840     if (ttpipe)
8841       fd = fdin;
8842     else
8843 #endif /* NETCMD */
8844       fd = ttyfd;
8845
8846 #ifdef TTLEBUF
8847     ttpush = -1;                        /* Clear the peek-ahead char */
8848     while (le_data && (le_inbuf() > 0)) {
8849         CHAR ch = '\0';
8850         if (le_getchar(&ch) > 0) {      /* Clear any more... */
8851             debug(F101,"ttflui le_inbuf ch","",ch);
8852         }
8853     }
8854 #endif /* TTLEBUF */
8855     debug(F101,"ttflui ttpipe","",ttpipe);
8856
8857 #ifdef MYREAD
8858 /*
8859   Flush internal MYREAD buffer *NEXT*, in all cases.
8860 */
8861     ttflux();
8862 #endif /* MYREAD */
8863
8864 #ifdef NETCONN
8865 /* Network flush is done specially, in the network support module. */
8866     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
8867         debug(F100,"ttflui netflui","",0);
8868 #ifdef COMMENT
8869 #ifdef TN_COMPORT
8870         if (istncomport())
8871             tnc_send_purge_data(TNC_PURGE_RECEIVE);
8872 #endif /* TN_COMPORT */
8873 #endif /* COMMENT */
8874         return(netflui());
8875     }
8876 #endif /* NETCONN */
8877
8878     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
8879     if (ttyfd < 0)
8880       return(-1);
8881
8882 #ifdef aegis
8883     sio_$control((short)yfd, sio_$flush_in, true, st);
8884     if (st.all != status_$ok) {
8885         fprintf(stderr, "flush failed: "); error_$print(st);
8886     } else {      /* sometimes the flush doesn't work */
8887         for (;;) {
8888             char buf[256];
8889             /* eat all the characters that shouldn't be available */
8890             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
8891             if (st.all == ios_$get_conditional_failed) break;
8892             fprintf(stderr, "flush failed(2): "); error_$print(st);
8893         }
8894     }
8895 #else
8896 #ifdef BSD44                            /* 4.4 BSD */
8897     n = FREAD;                          /* Specify read queue */
8898     debug(F100,"ttflui BSD44","",0);
8899     ioctl(fd,TIOCFLUSH,&n);
8900 #else
8901 #ifdef Plan9
8902 #undef POSIX                            /* Uh oh... */
8903 #endif /* Plan9 */
8904 #ifdef POSIX                            /* POSIX */
8905     debug(F100,"ttflui POSIX","",0);
8906     tcflush(fd,TCIFLUSH);
8907 #else
8908 #ifdef ATTSV                            /* System V */
8909 #ifndef VXVE
8910     debug(F100,"ttflui ATTSV","",0);
8911     ioctl(fd,TCFLSH,0);
8912 #endif /* VXVE */
8913 #else                                   /* Not BSD44, POSIX, or Sys V */
8914 #ifdef TIOCFLUSH                        /* Those with TIOCFLUSH defined */
8915 #ifdef ANYBSD                           /* Berkeley */
8916     n = FREAD;                          /* Specify read queue */
8917     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
8918     ioctl(fd,TIOCFLUSH,&n);
8919 #else                                   /* Others (V7, etc) */
8920     debug(F100,"ttflui TIOCFLUSH","",0);
8921     ioctl(fd,TIOCFLUSH,0);
8922 #endif /* ANYBSD */
8923 #else                                   /* All others... */
8924 /*
8925   No system call (that we know about) for input buffer flushing.
8926   So see how many there are and read them in a loop, using ttinc().
8927   ttinc() is buffered, so we're not getting charged with a system call
8928   per character, just a function call.
8929 */
8930     if ((n = ttchk()) > 0) {
8931         debug(F101,"ttflui read loop","",n);
8932         while ((n--) && ttinc(0) > 0) ;
8933     }
8934 #endif /* TIOCFLUSH */
8935 #endif /* ATTSV */
8936 #endif /* POSIX */
8937 #ifdef Plan9
8938 #define POSIX
8939 #endif /* Plan9 */
8940 #endif /* BSD44 */
8941 #endif /* aegis */
8942     return(0);
8943 }
8944
8945 int
8946 ttfluo() {                              /* Flush output buffer */
8947     int fd;
8948 #ifdef NETCMD
8949     if (ttpipe)
8950       fd = fdout;
8951     else
8952 #endif /* NETCMD */
8953       fd = ttyfd;
8954
8955 #ifdef Plan9
8956     return 0;
8957 #else
8958 #ifdef POSIX
8959     return(tcflush(fd,TCOFLUSH));
8960 #else
8961 #ifdef OXOS
8962     return(ioctl(fd,TCFLSH,1));
8963 #else
8964     return(0);                          /* All others, nothing */
8965 #endif /* OXOS */
8966 #endif /* POSIX */
8967 #endif /* Plan9 */
8968 }
8969
8970 /* Interrupt Functions */
8971
8972 /* Set up terminal interrupts on console terminal */
8973
8974 #ifndef FIONREAD                        /* We don't need esctrp() */
8975 #ifndef SELECT                          /* if we have any of these... */
8976 #ifndef CK_POLL
8977 #ifndef RDCHK
8978
8979 #ifndef OXOS
8980 #ifdef SVORPOSIX
8981 SIGTYP
8982 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
8983     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
8984     conesc = 1;
8985     debug(F101,"esctrp caught SIGQUIT","",conesc);
8986 }
8987 #endif /* SVORPOSIX */
8988 #endif /* OXOS */
8989
8990 #ifdef V7
8991 #ifndef MINIX2
8992 SIGTYP
8993 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
8994     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
8995     conesc = 1;
8996     debug(F101,"esctrp caught SIGQUIT","",conesc);
8997 }
8998 #endif /* MINIX2 */
8999 #endif /* V7 */
9000
9001 #ifdef C70
9002 SIGTYP
9003 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9004     conesc = 1;
9005     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9006 }
9007 #endif /* C70 */
9008
9009 #endif /* RDCHK */
9010 #endif /* CK_POLL */
9011 #endif /* SELECT */
9012 #endif /* FIONREAD */
9013
9014 /*  C O N B G T  --  Background Test  */
9015
9016 static int jc = 0;                      /* 0 = no job control */
9017
9018 /*
9019   Call with flag == 1 to prevent signal test, which can not be expected
9020   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
9021
9022   Call with flag == 0 to use the signal test, but only if the process-group
9023   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
9024   requires an argument when the man page says it doesn't, or vice versa.
9025
9026   If flag == 0 and the process-group test fails, then we determine background
9027   status simply (but not necessarily reliably) from isatty().
9028
9029   conbgt() sets the global backgrd = 1 if we appear to be in the background,
9030   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
9031   misbehavior.
9032 */
9033 VOID
9034 conbgt(flag) int flag; {
9035     int x = -1,                         /* process group or SIGINT test */
9036         y = 0;                          /* isatty() test */
9037 /*
9038   Check for background operation, even if not running on real tty, so that
9039   background flag can be set correctly.  If background status is detected,
9040   then Kermit will not issue its interactive prompt or most messages.
9041   If your prompt goes away, you can blame (and fix?) this function.
9042 */
9043
9044 /* Use process-group test if possible. */
9045
9046 #ifdef POSIX                            /* We can do it in POSIX */
9047 #define PGROUP_T
9048 #else
9049 #ifdef BSD4                             /* and in BSD 4.x. */
9050 #define PGROUP_T
9051 #else
9052 #ifdef HPUXJOBCTL                       /* and in most HP-UX's */
9053 #define PGROUP_T
9054 #else
9055 #ifdef TIOCGPGRP                        /* and anyplace that has this ioctl. */
9056 #define PGROUP_T
9057 #endif /* TIOCGPGRP */
9058 #endif /* HPUXJOBCTL */
9059 #endif /* BSD4 */
9060 #endif /* POSIX */
9061
9062 #ifdef MIPS                             /* Except if it doesn't work... */
9063 #undef PGROUP_T
9064 #endif /* MIPS */
9065
9066 #ifdef PGROUP_T
9067 /*
9068   Semi-reliable process-group test.  Check whether this process's group is
9069   the same as the controlling terminal's process group.  This works if the
9070   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
9071 */
9072     PID_T mypgrp = (PID_T)0;            /* Kermit's process group */
9073     PID_T ctpgrp = (PID_T)0;            /* The terminal's process group */
9074 #ifndef _POSIX_SOURCE
9075 /*
9076   The getpgrp() prototype is obtained from system header files for POSIX
9077   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
9078   a duplicate declaration here, others don't, so it's safer to leave it in
9079   if we don't know for certain.
9080 */
9081 #ifndef SVR4
9082 #ifndef PS2AIX10
9083 #ifndef HPUX9
9084     extern PID_T getpgrp();
9085 #endif /* HPUX9 */
9086 #endif /* PS2AIX10 */
9087 #endif /* SVR4 */
9088 #endif /* _POSIX_SOURCE */
9089
9090 /* Get my process group. */
9091
9092 #ifdef SVR3 /* Maybe this should be ATTSV? */
9093 /* This function is not described in SVID R2 */
9094     mypgrp = getpgrp();
9095     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
9096 #else
9097 #ifdef POSIX
9098     mypgrp = getpgrp();
9099     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
9100 #else
9101 #ifdef OSFPC
9102     mypgrp = getpgrp();
9103     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
9104 #else
9105 #ifdef QNX
9106     mypgrp = getpgrp();
9107     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
9108 #else
9109 #ifdef OSF32                            /* (was OSF40) */
9110     mypgrp = getpgrp();
9111     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
9112 #else /* BSD, V7, etc */
9113 #ifdef MINIX2
9114     mypgrp = getpgrp();
9115 #else
9116     mypgrp = getpgrp(0);
9117 #endif /* MINIX2 */
9118     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
9119 #endif /* OSF32 */
9120 #endif /* QNX */
9121 #endif /* OSFPC */
9122 #endif /* POSIX */
9123 #endif /* SVR3 */
9124
9125 #ifdef MINIX2
9126 #undef BSD44ORPOSIX
9127 #endif /* MINIX2 */
9128
9129 /* Now get controlling tty's process group */
9130 #ifdef BSD44ORPOSIX
9131     ctpgrp = tcgetpgrp(1);              /* The POSIX way */
9132     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
9133 #else
9134     ioctl(1, TIOCGPGRP, &ctpgrp);       /* Or the BSD way */
9135    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
9136 #endif /* BSD44ORPOSIX */
9137
9138 #ifdef MINIX2
9139 #define BSD44ORPOSIX
9140 #endif /* MINIX2 */
9141
9142     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
9143       x = (mypgrp == ctpgrp) ? 0 : 1;   /* If they differ, then background. */
9144     else x = -1;                        /* If error, remember. */
9145     debug(F101,"conbgt process group test","",x);
9146 #endif /* PGROUP_T */
9147
9148 /* Try to see if job control is available */
9149
9150 #ifdef NOJC                             /* User override */
9151     jc = 0;                             /* No job control allowed */
9152     debug(F111,"NOJC","jc",jc);
9153 #else
9154 #ifdef BSD44
9155     jc = 1;
9156 #else
9157 #ifdef SVR4ORPOSIX                      /* POSIX actually tells us */
9158     debug(F100,"SVR4ORPOSIX jc test...","",0);
9159 #ifdef _SC_JOB_CONTROL
9160 #ifdef __bsdi__
9161     jc = 1;
9162 #else
9163 #ifdef __386BSD__
9164     jc = 1;
9165 #else
9166     jc = sysconf(_SC_JOB_CONTROL);      /* Whatever system says */
9167     if (jc < 0) {
9168         debug(F101,"sysconf fails, jcshell","",jcshell);
9169         jc = (jchdlr == SIG_DFL) ? 1 : 0;
9170     } else
9171       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
9172 #endif /* __386BSD__ */
9173 #endif /* __bsdi__ */
9174 #else
9175 #ifdef _POSIX_JOB_CONTROL
9176     jc = 1;                             /* By definition */
9177     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
9178 #else
9179     jc = 0;                             /* Assume job control not allowed */
9180     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
9181 #endif /* _POSIX_JOB_CONTROL */
9182 #endif /* _SC_JOB_CONTROL */
9183 #else
9184 #ifdef BSD4
9185     jc = 1;                             /* Job control allowed */
9186     debug(F111,"BSD job control","jc",jc);
9187 #else
9188 #ifdef SVR3JC
9189     jc = 1;                             /* JC allowed */
9190     debug(F111,"SVR3 job control","jc",jc);
9191 #else
9192 #ifdef OXOS
9193     jc = 1;                             /* JC allowed */
9194     debug(F111,"X/OS job control","jc",jc);
9195 #else
9196 #ifdef HPUX9
9197     jc = 1;                             /* JC allowed */
9198     debug(F111,"HP-UX 9.0 job control","jc",jc);
9199 #else
9200 #ifdef HPUX10
9201     jc = 1;                             /* JC allowed */
9202     debug(F111,"HP-UX 10.0 job control","jc",jc);
9203 #else
9204     jc = 0;                             /* JC not allowed */
9205     debug(F111,"job control catch-all","jc",jc);
9206 #endif /* HPUX10 */
9207 #endif /* HPUX9 */
9208 #endif /* OXOS */
9209 #endif /* SVR3JC */
9210 #endif /* BSD4 */
9211 #endif /* SVR4ORPOSIX */
9212 #endif /* BSD44 */
9213 #endif /* NOJC */
9214     debug(F101,"conbgt jc","",jc);
9215 #ifndef NOJC
9216     debug(F101,"conbgt jcshell","",jcshell);
9217 /*
9218   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
9219   job control, but the shell or other process we are running under does not
9220   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
9221   will come of it.  So...
9222 */
9223     if (jc < 0) jc = 0;
9224     if (jc > 0 && jcshell == 0) jc = 0;
9225 #endif /* NOJC */
9226
9227 /*
9228   Another background test.
9229   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
9230   which is done by the shell (sh) if the program is started with '&'.
9231   Unfortunately, this is NOT done by csh or ksh so watch out!
9232   Note, it's safe to set SIGINT to SIG_IGN here, because further down
9233   we always set it to something else.
9234   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
9235   SIG_IGN ourselves.
9236 */
9237     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
9238
9239         SIGTYP (*osigint)();
9240
9241         osigint = signal(SIGINT,SIG_IGN);       /* What is SIGINT set to? */
9242         sigint_ign = 1;
9243         x = (osigint == SIG_IGN) ? 1 : 0;       /* SIG_IGN? */
9244         debug(F101,"conbgt osigint","",osigint);
9245         debug(F101,"conbgt signal test","",x);
9246     }
9247
9248 /* Also check to see if we're running with redirected stdio. */
9249 /* This is not really background operation, but we want to act as though */
9250 /* it were. */
9251
9252 #ifdef IKSD
9253     if (inserver) {                     /* Internet Kermit Server */
9254         backgrd = 0;                    /* is not in the background */
9255         return;
9256     }
9257 #endif /* IKSD */
9258
9259     y = (isatty(0) && isatty(1)) ? 1 : 0;
9260     debug(F101,"conbgt isatty test","",y);
9261
9262 #ifdef BSD29
9263 /* The process group and/or signal test doesn't work under these... */
9264     backgrd = !y;
9265 #else
9266 #ifdef sxaE50
9267     backgrd = !y;
9268 #else
9269 #ifdef MINIX
9270     backgrd = !y;
9271 #else
9272 #ifdef MINIX2
9273     backgrd = !y;
9274 #else
9275     if (x > -1)
9276       backgrd = (x || !y) ? 1 : 0;
9277     else backgrd = !y;
9278 #endif /* BSD29 */
9279 #endif /* sxaE50 */
9280 #endif /* MINIX */
9281 #endif /* MINIX2 */
9282     debug(F101,"conbgt backgrd","",backgrd);
9283 }
9284
9285 /*  C O N I N T  --  Console Interrupt setter  */
9286
9287 /*
9288   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
9289   Second arg is pointer to function to handle SIGTSTP (suspend).
9290 */
9291
9292 VOID                                    /* Set terminal interrupt traps. */
9293 #ifdef CK_ANSIC
9294 #ifdef apollo
9295 conint(f,s) SIGTYP (*f)(), (*s)();
9296 #else
9297 conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
9298 #endif /* apollo */
9299 #else
9300 conint(f,s) SIGTYP (*f)(), (*s)();
9301 #endif /* CK_ANSIC */
9302 /* conint */ {
9303
9304     debug(F101,"conint conistate","",conistate);
9305
9306     conbgt(0);                          /* Do background test. */
9307
9308 /* Set the desired handlers for hangup and software termination. */
9309
9310 #ifdef SIGTERM
9311     signal(SIGTERM,f);                  /* Software termination */
9312 #endif /* SIGTERM */
9313
9314 /*
9315   Prior to July 1999 we used to call sighup() here but now it's called in
9316   sysinit() so SIGHUP can be caught during execution of the init file or
9317   a kerbang script.
9318 */
9319
9320 /* Now handle keyboard stop, quit, and interrupt signals. */
9321 /* Check if invoked in background -- if so signals set to be ignored. */
9322 /* However, if running under a job control shell, don't ignore them. */
9323 /* We won't be getting any, as we aren't in the terminal's process group. */
9324
9325     debug(F101,"conint backgrd","",backgrd);
9326     debug(F101,"conint jc","",jc);
9327
9328     if (backgrd && !jc) {               /* In background, ignore signals */
9329         debug(F101,"conint background ignoring signals, jc","",jc);
9330 #ifdef SIGTSTP
9331         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
9332 #endif /* SIGTSTP */
9333         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
9334         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
9335         sigint_ign = 1;
9336         conistate = CONI_NOI;
9337     } else {                            /* Else in foreground or suspended */
9338         debug(F101,"conint foreground catching signals, jc","",jc);
9339         signal(SIGINT,f);               /* Catch terminal interrupt */
9340         sigint_ign = (f == SIG_IGN) ? 1 : 0;
9341
9342 #ifdef SIGTSTP                          /* Keyboard stop (suspend) */
9343         /* debug(F101,"conint SIGSTSTP","",s); */
9344         if (s == NULL) s = SIG_DFL;
9345 #ifdef NOJC                             /* No job control allowed. */
9346         signal(SIGTSTP,SIG_IGN);
9347 #else                                   /* Job control allowed */
9348         if (jc)                         /* if available. */
9349           signal(SIGTSTP,s);
9350         else
9351           signal(SIGTSTP,SIG_IGN);
9352 #endif /* NOJC */
9353 #endif /* SIGTSTP */
9354
9355 #ifndef OXOS
9356 #ifdef SVORPOSIX
9357 #ifndef FIONREAD                        /* Watch out, we don't know this... */
9358 #ifndef SELECT
9359 #ifndef CK_POLL
9360 #ifndef RDCHK
9361         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
9362 #endif /* RDCHK */
9363 #endif /* CK_POLL */
9364 #endif /* SELECT */
9365 #endif /* FIONREAD */
9366         if (conesc) conesc = 0;         /* Clear out pending escapes */
9367 #else
9368 #ifdef V7
9369         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
9370         if (conesc) conesc = 0;
9371 #else
9372 #ifdef aegis
9373         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
9374 #else
9375         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
9376 #endif /* aegis */
9377 #endif /* V7 */
9378 #endif /* SVORPOSIX */
9379 #endif /* OXOS */
9380         conistate = CONI_INT;
9381     }
9382 }
9383
9384
9385 /*  C O N N O I  --  Reset console terminal interrupts */
9386
9387 VOID
9388 connoi() {                              /* Console-no-interrupts */
9389
9390     debug(F101,"connoi conistate","",conistate);
9391 #ifdef SIGTSTP
9392     signal(SIGTSTP,SIG_IGN);            /* Suspend */
9393 #endif /* SIGTSTP */
9394     conint(SIG_IGN,SIG_IGN);            /* Interrupt */
9395     sigint_ign = 1;                     /* Remember we did this ourselves */
9396 #ifdef SIGQUIT
9397     signal(SIGQUIT,SIG_IGN);            /* Quit */
9398 #endif /* SIGQUIT */
9399 #ifdef SIGTERM
9400     signal(SIGTERM,SIG_IGN);            /* Term */
9401 #endif /* SIGTERM */
9402     conistate = CONI_NOI;
9403 }
9404
9405 /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
9406
9407 #ifdef  V7
9408 /*
9409  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
9410  eliminates blocking on a read, because we can read /dev/kmem to get the
9411  number of characters available for raw input.  If your system can't
9412  or you won't let the world read /dev/kmem then you must figure out a
9413  different way to do the counting of characters available, or else replace
9414  this by a dummy function that always returns 0.
9415 */
9416 /*
9417  * Call this routine as: initrawq(tty)
9418  * where tty is the file descriptor of a terminal.  It will return
9419  * (as a char *) the kernel-mode memory address of the rawq character
9420  * count, which may then be read.  It has the side-effect of flushing
9421  * input on the terminal.
9422  */
9423 /*
9424  * John Mackin, Physiology Dept., University of Sydney (Australia)
9425  * ...!decvax!mulga!physiol.su.oz!john
9426  *
9427  * Permission is hereby granted to do anything with this code, as
9428  * long as this comment is retained unmodified and no commercial
9429  * advantage is gained.
9430  */
9431 #ifndef MINIX
9432 #ifndef MINIX2
9433 #ifndef COHERENT
9434 #include <a.out.h>
9435 #include <sys/proc.h>
9436 #endif /* COHERENT */
9437 #endif /* MINIX2 */
9438 #endif /* MINIX */
9439
9440 #ifdef COHERENT
9441 #include <l.out.h>
9442 #include <sys/proc.h>
9443 #endif /* COHERENT */
9444
9445 char *
9446 initrawq(tty) int tty; {
9447 #ifdef MINIX
9448     return(0);
9449 #else
9450 #ifdef MINIX2
9451     return(0);
9452 #else
9453 #ifdef UTS24
9454     return(0);
9455 #else
9456 #ifdef BSD29
9457     return(0);
9458 #else
9459     long lseek();
9460     static struct nlist nl[] = {
9461         {PROCNAME},
9462         {NPROCNAME},
9463         {""}
9464     };
9465     static struct proc *pp;
9466     char *qaddr, *p, c;
9467     int m;
9468     PID_T pid, me;
9469     NPTYPE xproc;                       /* Its type is defined in makefile. */
9470     int catch();
9471
9472     me = getpid();
9473     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
9474     nlist(BOOTNAME, nl);
9475     if (nl[0].n_type == 0) err("proc array");
9476
9477     if (nl[1].n_type == 0) err("nproc");
9478
9479     lseek(m, (long)(nl[1].n_value), 0);
9480     read (m, &xproc, sizeof(xproc));
9481     saval = signal(SIGALRM, catch);
9482     if ((pid = fork()) == 0) {
9483         while(1)
9484             read(tty, &c, 1);
9485     }
9486     alarm(2);
9487
9488     if(setjmp(jjbuf) == 0) {
9489         while(1)
9490           read(tty, &c, 1);
9491     }
9492     signal(SIGALRM, SIG_DFL);
9493
9494 #ifdef DIRECT
9495     pp = (struct proc *) nl[0].n_value;
9496 #else
9497     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
9498     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
9499 #endif
9500     lseek(m, (long)(nl[1].n_value), 0);
9501     read(m, &xproc, sizeof(xproc));
9502
9503     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
9504     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
9505     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
9506         err("read proc table");
9507     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
9508         if (pp -> p_pid == (short) pid) goto iout;
9509     }
9510     err("no such proc");
9511
9512 iout:
9513     close(m);
9514     qaddr = (char *)(pp -> p_wchan);
9515     free (p);
9516     kill(pid, SIGKILL);
9517     wait((WAIT_T *)0);
9518     return (qaddr);
9519 #endif
9520 #endif
9521 #endif
9522 #endif
9523 }
9524
9525 /*  More V7-support functions...  */
9526
9527 static VOID
9528 err(s) char *s; {
9529     char buf[200];
9530
9531     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
9532     perror(buf);
9533     doexit(1,-1);
9534 }
9535
9536 static VOID
9537 catch(foo) int foo; {
9538     longjmp(jjbuf, -1);
9539 }
9540
9541
9542 /*  G E N B R K  --  Simulate a modem break.  */
9543
9544 #ifdef MINIX
9545 #define BSPEED B110
9546 #else
9547 #ifdef MINIX2
9548 #define BSPEED B110
9549 #else
9550 #define BSPEED B150
9551 #endif /* MINIX2 */
9552 #endif /* MINIX */
9553
9554 #ifndef MINIX2
9555 VOID
9556 genbrk(fn,msec) int fn, msec; {
9557     struct sgttyb ttbuf;
9558     int ret, sospeed, x, y;
9559
9560     ret = ioctl(fn, TIOCGETP, &ttbuf);
9561     sospeed = ttbuf.sg_ospeed;
9562     ttbuf.sg_ospeed = BSPEED;
9563     ret = ioctl(fn, TIOCSETP, &ttbuf);
9564     y = (int)strlen(brnuls);
9565     x = ( BSPEED * 100 ) / msec;
9566     if (x > y) x = y;
9567     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9568     ttbuf.sg_ospeed = sospeed;
9569     ret = ioctl(fn, TIOCSETP, &ttbuf);
9570     ret = write(fn, "@", 1);
9571     return;
9572 }
9573 #endif /* MINIX2 */
9574
9575 #ifdef MINIX2
9576 int
9577 genbrk(fn,msec) int fn, msec; {
9578     struct termios ttbuf;
9579     int ret, x, y;
9580     speed_t sospeed;
9581
9582     ret = tcgetattr(fn, &ttbuf);
9583     sospeed = ttbuf.c_ospeed;
9584     ttbuf.c_ospeed = BSPEED;
9585     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
9586     y = (int)strlen(brnuls);
9587     x = ( BSPEED * 100 ) / msec;
9588     if (x > y) x = y;
9589     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9590     ttbuf.c_ospeed = sospeed;
9591     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
9592     ret = write(fn, "@", 1);
9593     return ret;
9594 }
9595 #endif /* MINIX2 */
9596 #endif /* V7 */
9597
9598 /*
9599   I N C H K  --  Check if chars waiting to be read on given file descriptor.
9600
9601   This routine is a merger of ttchk() and conchk().
9602   Call with:
9603     channel == 0 to check console.
9604     channel == 1 to check communications connection.
9605   and:
9606     fd = file descriptor.
9607   Returns:
9608    >= 0: number of characters waiting, 0 or greater,
9609      -1: on any kind of error,
9610      -2: if there is (definitely) no connection.
9611   Note: In UNIX we don't have to call nettchk() because a socket
9612   file descriptor works just like in serial i/o, ioctls and all.
9613   (But this will change if we add non-file-descriptor channels,
9614   such as IBM X.25 for AIX...)
9615 */
9616 static int
9617 in_chk(channel, fd) int channel, fd; {
9618     int x, n = 0;                       /* Workers, n = return value */
9619     extern int clsondisc;               /* Close on disconnect */
9620 /*
9621   The first section checks to make sure we have a connection,
9622   but only if we're in local mode.
9623 */
9624 #ifdef DEBUG
9625     if (deblog) {
9626         debug(F111,"in_chk entry",ckitoa(fd),channel);
9627         debug(F101,"in_chk ttyfd","",ttyfd);
9628         debug(F101,"in_chk ttpty","",ttpty);
9629     }
9630 #endif /* DEBUG */
9631 /*
9632   But don't say connection is gone if we have any buffered-stuff.
9633 */
9634 #ifdef TTLEBUF
9635     debug(F101,"in_chk ttpush","",ttpush);
9636     if (channel == 1) {
9637         if (ttpush >= 0)
9638           n++;
9639         n += le_inbuf();
9640         if (n > 0)
9641           return(n);
9642     }
9643 #endif /* TTLEBUF */
9644
9645 #ifdef NETPTY
9646 #ifdef HAVE_PTYTRAP
9647     /* Special handling for HP-UX pty i/o */
9648     if (ttpty && pty_trap_pending(ttyfd) > 0) {
9649         if (pty_trap_handler(ttyfd) > 0) {
9650             ttclos(0);
9651             return(-2);
9652         }
9653     }
9654 #endif /* HAVE_PTYTRAP */
9655 #endif /* NETPTY */
9656
9657     if (channel) {                      /* Checking communications channel */
9658         if (ttyfd < 0) {                /* No connection */
9659           return(-2);                   /* That's what this means */
9660         } else if (xlocal &&            /* In local mode */
9661                    (!netconn            /* Serial connection or */
9662 #ifdef TN_COMPORT
9663                     || istncomport()    /* Telnet Com Port */
9664 #endif /* TN_COMPORT */
9665                    ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
9666 #ifdef COMMENT
9667 #ifdef MYREAD
9668 /*
9669   Seems like this would be a good idea but it prevents C-Kermit from
9670   popping back to the prompt automatically when carrier drops.  However,
9671   commenting this out prevents us from seeing the NO CARRIER message.
9672   Needs more work...
9673 */
9674                    && my_count < 1      /* Nothing in our internal buffer */
9675 #endif /* MYREAD */
9676 #endif /* COMMENT */
9677                    ) {
9678             int x;
9679             x = ttgmdm();               /* So get modem signals */
9680             debug(F101,"in_chk close-on-disconnect","",clsondisc);
9681             if (x > -1) {               /* Check for carrier */
9682                 if (!(x & BM_DCD)) {    /* No carrier */
9683                     debug(F101,"in_chk carrier lost","",x);
9684                     if (clsondisc)      /* If "close-on-disconnect" */
9685                       ttclos(0);        /* close device & release lock. */
9686                     return(-2);         /* This means "disconnected" */
9687                 }
9688             /* In case I/O to device after CD dropped always fails */
9689             /* as in Debian Linux 2.1 and Unixware 2.1... */
9690             } else {
9691                 debug(F101,"in_chk ttgmdm I/O error","",errno);
9692                 debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
9693                 if (gotsigs) {          /* If we got signals before... */
9694                     if (errno == 5 || errno == 6) { /* I/O error etc */
9695                         if (clsondisc)  /* like when modem hangs up */
9696                           ttclos(0);
9697                         return(-2);
9698                     }
9699                 }
9700                 /* If we never got modem signals successfully on this */
9701                 /* connection before, we can't conclude that THIS failure */
9702                 /* means the connection was lost. */
9703                 return(0);
9704             }
9705         }
9706     }
9707
9708 /* We seem to have a connection so now see if any bytes are waiting on it */
9709
9710 #ifdef CK_SSL
9711     if (ssl_active_flag || tls_active_flag) {
9712         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
9713         debug(F101,"in_chk SSL_pending","",n);
9714         if (n < 0) {
9715             ttclos(0);
9716             return(-1);
9717         } else if (n > 0) {
9718             return(n);
9719         }
9720     }
9721 #endif /* CK_SSL */
9722 #ifdef RLOGCODE
9723 #ifdef CK_KERBEROS
9724     /* It is not safe to read any data when using encrypted Klogin */
9725     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
9726 #ifdef KRB4
9727         if (ttnproto == NP_EK4LOGIN) {
9728             n += krb4_des_avail(ttyfd);
9729             debug(F101,"in_chk krb4_des_avail","",n);
9730         }
9731 #endif /* KRB4 */
9732 #ifdef KRB5
9733         if (ttnproto == NP_EK5LOGIN) {
9734             n += krb5_des_avail(ttyfd);
9735             debug(F101,"in_chk krb5_des_avail","",n);
9736         }
9737 #ifdef KRB5_U2U
9738         if (ttnproto == NP_K5U2U) {
9739             n += krb5_u2u_avail(ttyfd);
9740             debug(F101,"in_chk krb5_des_avail","",n);
9741         }
9742 #endif /* KRB5_U2U */
9743 #endif /* KRB5 */
9744         if (n < 0)                      /* Is this right? */
9745           return(-1);
9746         else
9747           return(n);
9748     }
9749 #endif /* CK_KERBEROS */
9750 #endif /* RLOGCODE */
9751
9752     errno = 0;                          /* Reset this so we log good info */
9753 #ifdef FIONREAD
9754     x = ioctl(fd, FIONREAD, &n);        /* BSD and lots of others */
9755 #ifdef DEBUG                            /* (the more the better) */
9756     if (deblog) {
9757         debug(F101,"in_chk FIONREAD return code","",x);
9758         debug(F101,"in_chk FIONREAD count","",n);
9759         debug(F101,"in_chk FIONREAD errno","",errno);
9760     }
9761 #endif /* DEBUG */
9762 #else /* FIONREAD not defined */
9763 /*
9764   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
9765   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
9766   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
9767   that I looked at, but it is needed to prevent the call from blocking), and
9768   the msghdr struct differs from place to place, so we would need another
9769   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
9770   only other known method of asking the OS for the *number* of characters
9771   available for reading.
9772 */
9773 #ifdef V7                               /* UNIX V7: look in kernel memory */
9774 #ifdef MINIX
9775     n = 0;                              /* But not in MINIX */
9776 #else
9777 #ifdef MINIX2
9778     n = 0;
9779 #else
9780     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
9781     x = read(kmem[TTY], &n, sizeof(int));
9782     if (x != sizeof(int))
9783       n = 0;
9784 #endif /* MINIX2 */
9785 #endif /* MINIX */
9786 #else /* Not V7 */
9787 #ifdef PROVX1
9788     x = ioctl(fd, TIOCQCNT, &ttbuf);    /* DEC Pro/3xx Venix V.1 */
9789     n = ttbuf.sg_ispeed & 0377;         /* Circa 1984 */
9790     if (x < 0) n = 0;
9791 #else
9792 #ifdef MYREAD
9793 /*
9794   Here we skip all the undependable and expensive calls below if we
9795   already have something in our internal buffer.  This tends to work quite
9796   nicely, so the only really bad case remaining is the one in which neither
9797   FIONREAD or MYREAD are defined, which is increasingly rare these days.
9798 */
9799     if (channel != 0 && my_count > 0) {
9800         debug(F101,"in_chk buf my_count","",my_count);
9801         n = my_count;                   /* n was 0 before we got here */
9802         return(n);
9803     }
9804 #endif /* MYREAD */
9805 /*
9806   rdchk(), select(), and poll() tell us *if* data is available to be read, but
9807   not how much, so these should be used only as a final resort.  Especially
9808   since these calls tend to add a lot overhead.
9809 */
9810 #ifdef RDCHK                            /* This mostly SCO-specific */
9811     n = rdchk(fd);
9812     debug(F101,"in_chk rdchk","",n);
9813 #else /* No RDCHK */
9814 #ifdef SELECT
9815 #ifdef Plan9
9816     /* Only allows select on the console ... don't ask */
9817     if (channel == 0)
9818 #endif /* Plan9 */
9819       {
9820         fd_set rfds;                    /* Read file descriptors */
9821 #ifdef BELLV10
9822         FD_ZERO(rfds);                  /* Initialize them */
9823         FD_SET(fd,rfds);                /* We want to look at this fd */
9824 #else
9825         FD_ZERO(&rfds);                 /* Initialize them */
9826         FD_SET(fd,&rfds);               /* We want to look at this fd */
9827         tv.tv_sec = tv.tv_usec = 0L;    /* A 0-valued timeval structure */
9828 #endif /* BELLV10 */
9829 #ifdef Plan9
9830         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9831         debug(F101,"in_chk Plan 9 select","",n);
9832 #else
9833 #ifdef BELLV10
9834         n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
9835         debug(F101,"in_chk BELLV10 select","",n);
9836 #else
9837 #ifdef BSD44
9838         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9839         debug(F101,"in_chk BSD44 select","",n);
9840 #else
9841 #ifdef BSD43
9842         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9843         debug(F101,"in_chk BSD43 select","",n);
9844 #else
9845 #ifdef SOLARIS
9846         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9847         debug(F101,"in_chk SOLARIS select","",n);
9848 #else
9849 #ifdef QNX6
9850         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9851         debug(F101,"in_chk QNX6 select","",n);
9852 #else
9853 #ifdef QNX
9854         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9855         debug(F101,"in_chk QNX select","",n);
9856 #else
9857 #ifdef COHERENT
9858         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9859         debug(F101,"in_chk COHERENT select","",n);
9860 #else
9861 #ifdef SVR4
9862         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9863         debug(F101,"in_chk SVR4 select","",n);
9864 #else
9865 #ifdef __linux__
9866         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9867         debug(F101,"in_chk LINUX select","",n);
9868 #ifdef OSF
9869         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
9870         debug(F101,"in_chk OSF select","",n);
9871 #else
9872         n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
9873         debug(F101,"in_chk catchall select","",n);
9874 #endif /* OSF */
9875 #endif /* __linux__ */
9876 #endif /* SVR4 */
9877 #endif /* COHERENT */
9878 #endif /* QNX */
9879 #endif /* QNX6 */
9880 #endif /* SOLARIS */
9881 #endif /* BSD43 */
9882 #endif /* BSD44 */
9883 #endif /* BELLV10 */
9884 #endif /* Plan9 */
9885     }
9886 #else  /* Not SELECT */
9887 #ifdef CK_POLL
9888     {
9889       struct pollfd pfd;
9890
9891       pfd.fd = fd;
9892       pfd.events = POLLIN;
9893       pfd.revents = 0;
9894       n = poll(&pfd, 1, 0);
9895       debug(F101,"in_chk poll","",n);
9896       if ((n > 0) && (pfd.revents & POLLIN))
9897         n = 1;
9898     }
9899 #endif /* CK_POLL */
9900 #endif /* SELECT */
9901 #endif /* RDCHK */
9902 #endif /* PROVX1 */
9903 #endif /* V7 */
9904 #endif /* FIONREAD */
9905
9906 /* From here down, treat console and communication device differently... */
9907
9908     if (channel == 0) {                 /* Console */
9909
9910 #ifdef SVORPOSIX
9911 #ifndef FIONREAD
9912 #ifndef SELECT
9913 #ifndef CK_POLL
9914 #ifndef RDCHK
9915 /*
9916   This is the hideous hack used in System V and POSIX systems that don't
9917   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
9918   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
9919   only on the console.
9920 */
9921         if (conesc) {                   /* Escape character typed == SIGQUIT */
9922             debug(F100,"in_chk conesc","",conesc);
9923             conesc = 0;
9924             signal(SIGQUIT,esctrp);     /* Restore signal */
9925             n += 1;
9926         }
9927 #endif /* RDCHK */
9928 #endif /* CK_POLL */
9929 #endif /* SELECT */
9930 #endif /* FIONREAD */
9931 #endif /* SVORPOSIX */
9932
9933         return(n);                      /* Done with console */
9934     }
9935
9936     if (channel != 0) {                 /* Communications connection */
9937
9938 #ifdef MYREAD
9939 #ifndef FIONREAD
9940 /*
9941   select() or rdchk(), etc, has told us that something is waiting, but we
9942   don't know how much.  So we do a read to get it and then we know.  Note:
9943   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
9944   it should be safe in this case since the OS tells us at least one byte is
9945   waiting to be read, and MYREAD reads return as much as is there without
9946   waiting for any more.  Controlled tests on Solaris and Unixware (with
9947   FIONREAD deliberately undefined) show this to be true.
9948 */
9949         debug(F101,"in_chk read my_count","",my_count);
9950         debug(F101,"in_chk read n","",n);
9951         if (n > 0 && my_count == 0) {
9952             /* This also catches disconnects etc */
9953             /* Do what mygetbuf does except don't grab a character */
9954             my_count = myfillbuf();
9955             my_item = -1;               /* ^^^ */
9956             debug(F101,"in_chk myfillbuf my_count","",my_count);
9957             if (my_count < 0)
9958               return(-1);
9959             else
9960               n = 0;                    /* NB: n is replaced by my_count */
9961         }
9962 #endif /* FIONREAD */
9963 /*
9964   Here we add whatever we think is unread to what is still in our
9965   our internal buffer.  Thus the importance of setting n to 0 just above.
9966 */
9967         debug(F101,"in_chk my_count","",my_count);
9968         debug(F101,"in_chk n","",n);
9969         if (my_count > 0)
9970           n += my_count;
9971 #endif /* MYREAD */
9972     }
9973     debug(F101,"in_chk result","",n);
9974
9975     /* Errors here don't prove the connection has dropped so just say 0 */
9976
9977     return(n < 0 ? 0 : n);
9978 }
9979
9980
9981 /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
9982
9983 int
9984 ttchk() {
9985     int fd;
9986 #ifdef NETCMD
9987     if (ttpipe)
9988       fd = fdin;
9989     else
9990 #endif /* NETCMD */
9991       fd = ttyfd;
9992     return(in_chk(1,fd));
9993 }
9994
9995 /*  T T X I N  --  Get n characters from tty input buffer  */
9996
9997 /*  Returns number of characters actually gotten, or -1 on failure  */
9998
9999 /*  Intended for use only when it is known that n characters are actually */
10000 /*  Available in the input buffer.  */
10001
10002 int
10003 ttxin(n,buf) int n; CHAR *buf; {
10004     register int x = 0, c = -2;
10005 #ifdef TTLEBUF
10006     register int i = 0;
10007 #endif /* TTLEBUF */
10008     int fd;
10009
10010     if (n < 1)                          /* Nothing to do */
10011       return(0);
10012
10013 #ifdef TTLEBUF
10014     if (ttpush >= 0) {
10015         buf[0] = ttpush;                /* Put pushed char in buffer*/
10016         ttpush = -1;                    /* Clear the push buffer */
10017         if (ttchk() > 0)
10018           return(ttxin(n-1, &buf[1]) + 1);
10019         else
10020           return(1);
10021     }
10022     if (le_data) {
10023         while (le_inbuf() > 0) {
10024             if (le_getchar(&buf[i])) {
10025                 i++;
10026                 n--;
10027             }
10028         }
10029         if (ttchk() > 0)
10030           return(ttxin(n,&buf[i])+i);
10031         else
10032           return(i);
10033     }
10034 #endif /* TTLEBUF */
10035
10036 #ifdef NETCMD
10037     if (ttpipe)
10038       fd = fdin;
10039     else
10040 #endif /* NETCMD */
10041       fd = ttyfd;
10042
10043 #ifdef SUNX25
10044     if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
10045       return(x25xin(n,buf));
10046 #endif /* SUNX25 */
10047
10048 #ifdef IBMX25
10049     /* riehm: possibly not needed. Test worked with normal reads and writes */
10050     if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
10051         x = x25xin(n,buf);
10052         if (x > 0) buf[x] = '\0';
10053         return(x);
10054     }
10055 #endif /* IBMX25 */
10056
10057 #ifdef MYREAD
10058     debug(F101,"ttxin MYREAD","",n);
10059     while (x < n) {
10060         c = myread();
10061         if (c < 0) {
10062             debug(F101,"ttxin myread returns","",c);
10063             if (c == -3) x = -1;
10064             break;
10065         }
10066         buf[x++] = c & ttpmsk;
10067 #ifdef RLOGCODE
10068 #ifdef CK_KERBEROS
10069         /* It is impossible to know how many characters are waiting */
10070         /* to be read when you are using Encrypted Rlogin or SSL    */
10071         /* as the transport since the number of real data bytes     */
10072         /* can be greater or less than the number of bytes on the   */
10073         /* wire which is what ttchk() returns.                      */
10074         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
10075           if (ttchk() <= 0)
10076             break;
10077 #endif /* CK_KERBEROS */
10078 #endif /* RLOGCODE */
10079 #ifdef CK_SSL
10080         if (ssl_active_flag || tls_active_flag)
10081           if (ttchk() <= 0)
10082             break;
10083 #endif /* CK_SSL */
10084     }
10085 #else
10086     debug(F101,"ttxin READ","",n);
10087     x = read(fd,buf,n);
10088     for (c = 0; c < n; c++)             /* Strip any parity */
10089       buf[c] &= ttpmsk;
10090 #endif /* MYREAD */
10091
10092     debug(F101,"ttxin x","",x);         /* Done */
10093     if (x > 0) buf[x] = '\0';
10094     if (x < 0) x = -1;
10095     return(x);
10096 }
10097
10098 /*  T T O L  --  Write string s, length n, to communication device.  */
10099 /*
10100   Returns:
10101    >= 0 on success, number of characters actually written.
10102    -1 on failure.
10103 */
10104 #ifdef CK_ENCRYPTION
10105 CHAR * xpacket = NULL;
10106 int nxpacket = 0;
10107 #endif /* CK_ENCRYPTION */
10108
10109 #define TTOLMAXT 5
10110 int
10111 ttol(s,n) int n; CHAR *s; {
10112     int x, len, tries, fd;
10113 #ifdef CKXXCHAR
10114     extern int dblflag;                 /* For SET SEND DOUBLE-CHARACTER */
10115     extern short dblt[];
10116     CHAR *p = NULL, *p2, *s2, c;
10117     int n2 = 0;
10118 #endif /* CKXXCHAR */
10119
10120     if (ttyfd < 0)                      /* Not open? */
10121       return(-3);
10122 #ifdef DEBUG
10123     if (deblog) hexdump("ttol s",s,n);
10124 #endif /* DEBUG */
10125
10126 #ifdef NETCMD
10127     if (ttpipe)
10128       fd = fdout;
10129     else
10130 #endif /* NETCMD */
10131       fd = ttyfd;
10132
10133 #ifdef CKXXCHAR
10134 /*  Double any characters that must be doubled.  */
10135     debug(F101,"ttol dblflag","",dblflag);
10136     if (dblflag) {
10137         p = (CHAR *) malloc(n + n + 1);
10138         if (p) {
10139             s2 = s;
10140             p2 = p;
10141             n2 = 0;
10142             while (*s2) {
10143                 c = *s2++;
10144                 *p2++ = c;
10145                 n2++;
10146                 if (dblt[(unsigned) c] & 2) {
10147                     *p2++ = c;
10148                     n2++;
10149                 }
10150             }
10151             s = p;
10152             n = n2;
10153             s[n] = '\0';
10154         }
10155 #ifdef DEBUG
10156         if (deblog) hexdump("ttol doubled s",s,n);
10157 #endif /* DEBUG */
10158     }
10159 #endif /* CKXXCHAR */
10160
10161     tries = TTOLMAXT;                   /* Allow up to this many tries */
10162     len = n;                            /* Remember original length */
10163
10164 #ifdef CK_ENCRYPTION
10165 /*
10166   This is to avoid encrypting a packet that is already encrypted, e.g.
10167   when we resend a packet directly out of the packet buffer, and also to
10168   avoid encrypting a constant (literal) string, which can cause a memory
10169   fault.
10170 */
10171     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
10172         int x;
10173         if (nxpacket < n) {
10174             if (xpacket) {
10175                 free(xpacket);
10176                 xpacket = NULL;
10177                 nxpacket = 0;
10178             }
10179             x = n > 10240 ? n : 10240;
10180             xpacket = (CHAR *)malloc(x);
10181             if (!xpacket) {
10182                 fprintf(stderr,"ttol malloc failure\n");
10183                 return(-1);
10184             } else
10185               nxpacket = x;
10186         }
10187         memcpy((char *)xpacket,(char *)s,n);
10188         s = xpacket;
10189         ck_tn_encrypt((char *)s,n);
10190     }
10191 #endif /* CK_ENCRYPTION */
10192
10193     while (n > 0 &&
10194            (tries-- > 0
10195 #ifdef CK_ENCRYPTION
10196             /* keep trying if we are encrypting */
10197             || TELOPT_ME(TELOPT_ENCRYPTION)
10198 #endif /* CK_ENCRYPTION */
10199             )) {                        /* Be persistent */
10200         debug(F101,"ttol try","",TTOLMAXT - tries);
10201 #ifdef BEOSORBEBOX
10202         if (netconn && !ttpipe && !ttpty)
10203           x = nettol((char *)s,n);      /* Write string to device */
10204         else
10205 #endif /* BEOSORBEBOX */
10206 #ifdef IBMX25
10207           if (ttnet == NET_IX25)
10208             /*
10209              * this is a more controlled way of writing to X25
10210              * STREAMS, however write should also work!
10211              */
10212             x = x25write(ttyfd, s, n);
10213           else
10214 #endif /* IBMX25 */
10215 #ifdef CK_SSL
10216             if (ssl_active_flag || tls_active_flag) {
10217                 int error;
10218                 /* Write using SSL */
10219                 ssl_retry:
10220                 if (ssl_active_flag)
10221                   x = SSL_write(ssl_con, s, n);
10222                 else
10223                   x = SSL_write(tls_con, s, n);
10224                 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
10225                 case SSL_ERROR_NONE:
10226                     if (x == n)
10227                       return(len);
10228                     s += x;
10229                     n -= x;
10230                     goto ssl_retry;
10231                   case SSL_ERROR_WANT_WRITE:
10232                   case SSL_ERROR_WANT_READ:
10233                     x = 0;
10234                     break;
10235                   case SSL_ERROR_SYSCALL:
10236                     if (x != 0)
10237                       return(-1);
10238                   case SSL_ERROR_WANT_X509_LOOKUP:
10239                   case SSL_ERROR_SSL:
10240                   case SSL_ERROR_ZERO_RETURN:
10241                   default:
10242                     ttclos(0);
10243                     return(-3);
10244                 }
10245             } else
10246 #endif /* CK_SSL */
10247 #ifdef CK_KERBEROS
10248 #ifdef KRB4
10249 #ifdef RLOGCODE
10250             if (ttnproto == NP_EK4LOGIN) {
10251                 return(krb4_des_write(ttyfd,s,n));
10252             } else
10253 #endif /* RLOGCODE */
10254 #endif /* KRB4 */
10255 #ifdef KRB5
10256 #ifdef RLOGCODE
10257             if (ttnproto == NP_EK5LOGIN) {
10258                 return(krb5_des_write(ttyfd,s,n,0));
10259             } else
10260 #endif /* RLOGCODE */
10261 #ifdef KRB5_U2U
10262             if (ttnproto == NP_K5U2U) {
10263                 return(krb5_u2u_write(ttyfd,s,n));
10264             } else
10265 #endif /* KRB5_U2U */
10266 #endif /* KRB5 */
10267 #endif /* CK_KERBEROS */
10268               x = write(fd,s,n);        /* Write string to device */
10269
10270         if (x == n) {                   /* Worked? */
10271             debug(F101,"ttol ok","",x); /* OK */
10272 #ifdef CKXXCHAR
10273             if (p) free(p);
10274 #endif /* CKXXCHAR */
10275             return(len);                /* Done */
10276         } else if (x < 0) {             /* No, got error? */
10277             debug(F101,"ttol write error","",errno);
10278 #ifdef EWOULDBLOCK
10279             if (errno == EWOULDBLOCK) {
10280                 msleep(10);
10281                 continue;
10282             } else
10283 #endif /* EWOULDBLOCK */
10284 #ifdef TCPSOCKET
10285             if (netconn && ttnet == NET_TCPB) {
10286                 debug(F101,"ttol TCP error","",errno);
10287                 ttclos(0);              /* Close the connection. */
10288                 x = -3;
10289             }
10290 #endif /* TCPSOCKET */
10291 #ifdef CKXXCHAR
10292             if (p) free(p);
10293 #endif /* CKXXCHAR */
10294             return(x);
10295         } else {                        /* No error, so partial success */
10296             debug(F101,"ttol partial","",x); /* This never happens */
10297             s += x;                     /* Point to part not written yet */
10298             n -= x;                     /* Adjust length */
10299             if (x > 0) msleep(10);      /* Wait 10 msec */
10300         }                               /* Go back and try again */
10301     }
10302 #ifdef CKXXCHAR
10303     if (p) free(p);
10304 #endif /* CKXXCHAR */
10305     return(n < 1 ? len : -1);           /* Return the results */
10306 }
10307
10308 /*  T T O C  --  Output a character to the communication line  */
10309
10310 /*
10311  This function should only be used for interactive, character-mode operations,
10312  like terminal connection, script execution, dialer i/o, where the overhead
10313  of the signals and alarms does not create a bottleneck.
10314 */
10315 int
10316 #ifdef CK_ANSIC
10317 ttoc(char c)
10318 #else
10319 ttoc(c) char c;
10320 #endif /* CK_ANSIC */
10321 /* ttoc */ {
10322 #define TTOC_TMO 15                     /* Timeout in case we get stuck */
10323     int xx, fd;
10324
10325     if (ttyfd < 0)                      /* Check for not open. */
10326       return(-1);
10327
10328 #ifdef NETCMD
10329     if (ttpipe)
10330       fd = fdout;
10331     else
10332 #endif /* NETCMD */
10333       fd = ttyfd;
10334
10335     c &= 0xff;
10336     /* debug(F101,"ttoc","",(CHAR) c); */
10337     saval = signal(SIGALRM,timerh);     /* Enable timer interrupt */
10338     xx = alarm(TTOC_TMO);               /* for this many seconds. */
10339     if (xx < 0) xx = 0;                 /* Save old alarm value. */
10340     /* debug(F101,"ttoc alarm","",xx); */
10341     if (
10342 #ifdef CK_POSIX_SIG
10343         sigsetjmp(sjbuf,1)
10344 #else
10345         setjmp(sjbuf)
10346 #endif /* CK_POSIX_SIG */
10347         ) {             /* Timer went off? */
10348         ttimoff();                      /* Yes, cancel this alarm. */
10349         if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
10350         /* debug(F100,"ttoc timeout","",0); */
10351 #ifdef NETCONN
10352         if (!netconn) {
10353 #endif /* NETCONN */
10354             debug(F101,"ttoc timeout","",c);
10355             if (ttflow == FLO_XONX) {
10356                 debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
10357 #ifndef Plan9
10358 #ifdef POSIX
10359                 /* POSIX way to unstick. */
10360                 debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
10361 #else
10362 #ifdef BSD4                             /* Berkeley way to do it. */
10363 #ifdef TIOCSTART
10364 /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
10365                 {
10366                   int x = 0;
10367                   debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
10368                 }
10369 #endif /* TIOCSTART */
10370 #endif /* BSD4 */
10371                                         /* Is there a Sys V way to do this? */
10372 #endif /* POSIX */
10373 #endif /* Plan9 */
10374             }
10375 #ifdef NETCONN
10376         }
10377 #endif /* NETCONN */
10378         return(-1);                     /* Return failure code. */
10379     } else {
10380         int rc;
10381 #ifdef BEOSORBEBOX
10382 #ifdef NETCONN
10383         if (netconn && !ttpipe && !ttpty)
10384           rc = nettoc(c);
10385         else
10386 #endif /*  BEOSORBEBOX */
10387 #endif /* NETCONN */
10388 #ifdef CK_ENCRYPTION
10389           if (TELOPT_ME(TELOPT_ENCRYPTION))
10390             ck_tn_encrypt(&c,1);
10391 #endif /* CK_ENCRYPTION */
10392 #ifdef IBMX25
10393         /* riehm: maybe this isn't necessary after all. Test program
10394          * worked fine with data being sent and retrieved with normal
10395          * read's and writes!
10396          */
10397         if (ttnet == NET_IX25)
10398           rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
10399         else
10400 #endif /* IBMX25 */
10401 #ifdef CK_SSL
10402           if (ssl_active_flag || tls_active_flag) {
10403               int error;
10404               /* Write using SSL */
10405               if (ssl_active_flag)
10406                 rc = SSL_write(ssl_con, &c, 1);
10407               else
10408                 rc = SSL_write(tls_con, &c, 1);
10409               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
10410                 case SSL_ERROR_NONE:
10411                   break;
10412                 case SSL_ERROR_WANT_WRITE:
10413                 case SSL_ERROR_WANT_READ:
10414                   rc = 0;
10415                   break;
10416                 case SSL_ERROR_SYSCALL:
10417                   if (rc != 0)
10418                     return(-1);
10419                 case SSL_ERROR_WANT_X509_LOOKUP:
10420                 case SSL_ERROR_SSL:
10421                 case SSL_ERROR_ZERO_RETURN:
10422                 default:
10423                   ttclos(0);
10424                   return(-1);
10425               }
10426           } else
10427 #endif /* CK_SSL */
10428 #ifdef CK_KERBEROS
10429 #ifdef KRB4
10430 #ifdef RLOGCODE
10431           if (ttnproto == NP_EK4LOGIN) {
10432               rc = (krb4_des_write(ttyfd,&c,1) == 1);
10433           } else
10434 #endif /* RLOGCODE */
10435 #endif /* KRB4 */
10436 #ifdef KRB5
10437 #ifdef RLOGCODE
10438           if (ttnproto == NP_EK5LOGIN) {
10439               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
10440           } else
10441 #endif /* RLOGCODE */
10442 #ifdef KRB5_U2U
10443           if (ttnproto == NP_K5U2U) {
10444               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
10445           } else
10446 #endif /* KRB5_U2U */
10447 #endif /* KRB5 */
10448 #endif /* CK_KERBEROS */
10449             rc = write(fd,&c,1);        /* Try to write the character. */
10450         if (rc < 1) {                   /* Failed */
10451             ttimoff();                  /* Turn off the alarm. */
10452             alarm(xx);                  /* Restore previous alarm. */
10453             debug(F101,"ttoc errno","",errno); /* Log the error, */
10454             return(-1);                 /* and return the error code. */
10455         }
10456     }
10457     ttimoff();                          /* Success, turn off the alarm. */
10458     alarm(xx);                          /* Restore previous alarm. */
10459     return(0);                          /* Return good code. */
10460 }
10461
10462 /*  T T I N L  --  Read a record (up to break character) from comm line.  */
10463 /*
10464   Reads up to "max" characters from the communication line, terminating on:
10465     (a) the packet length field if the "turn" argument is zero, or
10466     (b) on the packet-end character (eol) if the "turn" argument is nonzero
10467     (c) a certain number of Ctrl-C's in a row
10468
10469   Returns:
10470     >= 0, the number of characters read upon success;
10471     -1 if "max" exceeded, timeout, or other correctable error;
10472     -2 on user interruption (c);
10473     -3 on fatal error like connection lost.
10474
10475   The characters that were input are copied into "dest" with their parity bits
10476   stripped if parity was selected.  Returns the number of characters read.
10477   Characters after the eol are available upon the next call to this function.
10478
10479   The idea is to minimize the number of system calls per packet, and also to
10480   minimize timeouts.  This function is the inner loop of the protocol and must
10481   be as efficient as possible.  The current strategy is to use myread().
10482
10483   WARNING: This function calls parchk(), which is defined in another module.
10484   Normally, ckutio.c does not depend on code from any other module, but there
10485   is an exception in this case because all the other ck?tio.c modules also
10486   need to call parchk(), so it's better to have it defined in a common place.
10487 */
10488 #ifdef CTRLC
10489 #undef CTRLC
10490 #endif /* CTRLC */
10491 #define CTRLC '\03'
10492 /*
10493   We have four different declarations here because:
10494   (a) to allow Kermit to be built without the automatic parity sensing feature
10495   (b) one of each type for ANSI C, one for non-ANSI.
10496 */
10497
10498 static int csave = -1;
10499
10500 #ifndef NOXFER
10501 int
10502 #ifdef PARSENSE
10503 #ifdef CK_ANSIC
10504 ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
10505 #else
10506 ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
10507 #endif /* CK_ANSIC */
10508 #else /* not PARSENSE */
10509 #ifdef CK_ANSIC
10510 ttinl(CHAR *dest, int max,int timo, CHAR eol)
10511 #else
10512 ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
10513 #endif /* __SDTC__ */
10514 #endif /* PARSENSE */
10515 /* ttinl */ {
10516
10517 #ifndef MYREAD
10518     CHAR ch, dum;
10519 #endif /* MYREAD */
10520 #ifdef PARSENSE
10521     int pktlen = -1;
10522     int lplen = 0;
10523     int havelen = 0;
10524 #endif /* PARSENSE */
10525     int fd;
10526     int sopmask = 0xff;                 /* Start-Of-Packet mask */
10527 #ifdef CKXXCHAR
10528     extern short dblt[];                /* Ignore-character table */
10529     extern int ignflag;
10530 #endif /* CKXXCHAR */
10531 #ifdef TCPSOCKET
10532     extern CHAR stchr;
10533 #endif /* TCPSOCKET */
10534     int x;
10535 #ifdef STREAMING
10536     extern int streaming;
10537     extern int sndtyp;
10538 #endif /* STREAMING */
10539
10540     if (ttyfd < 0) return(-3);          /* Not open. */
10541
10542     debug(F101,"ttinl max","",max);
10543     debug(F101,"ttinl timo","",timo);
10544
10545 #ifdef NETCMD
10546     if (ttpipe)
10547       fd = fdin;
10548     else
10549 #endif /* NETCMD */
10550       fd = ttyfd;
10551
10552 #ifdef COMMENT
10553     if (xlocal && conchk() > 0)         /* Allow for console interruptions */
10554       return(-1);
10555 #endif /* COMMENT */
10556
10557     *dest = '\0';                       /* Clear destination buffer */
10558     if (timo < 0) timo = 0;             /* Safety */
10559     if (timo) {                         /* Don't time out if timo == 0 */
10560         int xx;
10561         saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
10562         xx = alarm(timo);               /* Set it. */
10563         debug(F101,"ttinl alarm","",xx);
10564     }
10565     if (
10566 #ifdef CK_POSIX_SIG
10567         sigsetjmp(sjbuf,1)
10568 #else
10569         setjmp(sjbuf)
10570 #endif /* CK_POSIX_SIG */
10571         ) {                             /* Timer went off? */
10572         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
10573         /* debug(F110," with",(char *) dest,0); */
10574         ttimoff();                      /* Turn off timer */
10575         return(-1);                     /* and return error code. */
10576     } else {
10577         register int i, n = -1;         /* local variables */
10578         int ccn = 0;
10579 #ifdef PARSENSE
10580         register int flag = 0;
10581         debug(F000,"ttinl start","",start);
10582 #endif /* PARSENSE */
10583
10584         ttpmsk = ttprty ? 0177 : 0377;  /* Set parity stripping mask. */
10585         sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
10586
10587 /* Now read into destination, stripping parity and looking for the */
10588 /* the packet terminator, and also for several Ctrl-C's typed in a row. */
10589
10590         i = 0;                          /* Destination index */
10591         debug(F101,"ttinl eol","",eol);
10592
10593         while (i < max-1) {
10594 #ifdef MYREAD
10595             /* debug(F101,"ttinl i","",i); */
10596             errno = 0;
10597             if (csave > -1) {
10598                 n = csave;
10599                 debug(F101,"ttinl unsaving","",n);
10600             } else
10601 #ifdef COMMENT
10602               if (xlocal && conchk() > 0) {
10603                   /* Here we could catch keyboard interruptions. */
10604                   /* But this would be VERY expensive. */
10605                   /* We could also do it in myread() but it would be */
10606                   /* expensive there too -- even if done with select()... */
10607               }
10608 #endif /* COMMENT */
10609               if ((n = myread()) < 0) { /* Timeout or i/o error? */
10610 #ifdef DEBUG
10611                 if (deblog) {
10612                     debug(F101,"ttinl myread failure, n","",n);
10613                     debug(F101,"ttinl myread errno","",errno);
10614                 }
10615 #endif /* DEBUG */
10616                 /* Don't let EINTR break packets. */
10617                 if (n == -3) {
10618                     if (errno == EINTR && i > 0) {
10619                         debug(F111,"ttinl EINTR myread i","continuing",i);
10620                         continue;
10621                     } else {
10622                         debug(F110,"ttinl non-EINTR -3","closing",0);
10623                         wasclosed = 1;
10624                         ttimoff();      /* Turn off timer */
10625                         ttclos(0);
10626                         return(n);
10627                     }
10628                 } else if (n == -2 && netconn /* && timo == 0 */ ) {
10629                     /* Here we try to catch broken network connections */
10630                     /* even when ioctl() and read() do not catch them */
10631                     debug(F111,"ttinl network myread failure","closing",n);
10632                     wasclosed = 1;
10633                     ttimoff();
10634                     ttclos(0);
10635                     return(-3);
10636                 }
10637 #ifdef STREAMING
10638                 /* Streaming and no data to read */
10639                 else if (n == 0 && streaming && sndtyp == 'D')
10640                   return(0);
10641 #endif /* STREAMING */
10642                 break;                  /* Break out of while loop */
10643             }
10644
10645 #else /* not MYREAD (is this code used anywhere any more?) */
10646
10647             if (csave > -1)             /* Char saved from last time */
10648               ch = csave;
10649             else if ((n = read(fd, &ch, 1)) < 1)
10650               break;                    /* Error - break out of while loop */
10651             n = ch;
10652
10653 #endif /* MYREAD */
10654
10655             /* Get here with char in n */
10656
10657 #ifdef CK_ENCRYPTION
10658             /* If csave > -1 we already decrypted this character */
10659             /* So don't decrypt it again */
10660             if (TELOPT_U(TELOPT_ENCRYPTION) && csave == -1) {
10661                 CHAR ch = n;
10662                 ck_tn_decrypt(&ch,1);
10663                 n = ch;
10664             }
10665 #endif /* CK_ENCRYPTION */
10666
10667             csave = -1;                 /* Unflag that we unsaved a char */
10668
10669 #ifdef TCPSOCKET
10670             if (n == IAC &&             /* Handle Telnet options */
10671                 ((xlocal && netconn && IS_TELNET()) ||
10672                 (!xlocal && sstelnet))) {
10673                 n = tt_tnopt(n);
10674                 if (n < 0)
10675                   return(n);
10676 #ifndef NOPARSEN
10677                 else if (n == 1)
10678                   start = stchr;
10679 #endif /* NOPARSEN */
10680                 if (n != 255)           /* No data - go back for next char */
10681                   continue;
10682             }                           /* Quoted IAC - keep going */
10683 #endif /* TCPSOCKET */
10684 #ifdef CKXXCHAR
10685             if (ignflag)
10686               if (dblt[(unsigned) n] & 1) /* Character to ignore? */
10687                 continue;
10688 #endif /* CKXXCHAR */
10689
10690 /*
10691   Use parity mask, rather than always stripping parity, to check for
10692   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
10693   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
10694   unlikely due to run-length encoding.)
10695 */
10696             /* Check cancellation */
10697             if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
10698                 if (++ccn >= xfrnum) {  /* If xfrnum in a row, bail out. */
10699                     if (timo) {         /* Clear timer. */
10700                         ttimoff();
10701                     }
10702                     if (xfrchr < 32)
10703                       printf("^%c...\r\n",(char)(xfrchr+64));
10704                     else
10705                       printf("Canceled...\r\n");
10706                     return(-2);
10707                 }
10708             } else ccn = 0;             /* No cancellation, reset counter, */
10709
10710 #ifdef PARSENSE
10711             if (flag == 0) {            /* Find the Start-Of-Packet. */
10712                 if ((n & sopmask) == start) { /* Got it */
10713                     flag = 1;
10714                 } else {                /* Keep looking... */
10715                     debug(F000,"ttinl skipping","",n);
10716                     continue;
10717                 }
10718             }
10719             dest[i++] = n & ttpmsk;
10720 /*
10721   If we have not been instructed to wait for a turnaround character, we
10722   can go by the packet length field.  If turn != 0, we must wait for the
10723   end of line (eol) character before returning.  This is an egregious
10724   violation of all principles of layering...
10725 */
10726             if (!havelen) {
10727                 if (i == 2) {
10728                     pktlen = xunchar(dest[1] & 0x7f);
10729                     if (pktlen > 1) {
10730                         havelen = 1;
10731                         debug(F101,"ttinl length","",pktlen);
10732                     }
10733                 } else if (i == 5 && pktlen == 0) {
10734                     lplen = xunchar(dest[4] & 0x7f);
10735                 } else if (i == 6 && pktlen == 0) {
10736                     pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
10737                     havelen = 1;
10738                     debug(F101,"ttinl extended length","",pktlen);
10739                 }
10740             }
10741
10742 /*
10743   Suppose we looked at the sequence number here and found it was out of
10744   range?  This would mean either (a) incoming packets had SOP unprefixed
10745   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
10746   practice, let's ignore it.  So what should we do here if we know the
10747   packet is damaged?
10748
10749    1. Nothing -- keep trying to read the packet till we find what we think
10750       is the end, or we time out, and let the upper layer decide what to
10751       do.  But since either the packet is corrupt or we are out of sync,
10752       our criterion for finding the end does not apply and we are likely
10753       to time out (or swallow a piece of the next packet) if our assumed
10754       length is too long.  (This was the behavior prior to version 7.0.)
10755
10756    2. set flag = 0 and continue?  This would force us to wait for the
10757       next packet to come in, and therefore (in the nonwindowing case),
10758       would force a timeout in the other Kermit.
10759
10760    3. set flag = 0 and continue, but only if the window size is > 1 and
10761       the window is not blocked?  Talk about cheating!
10762
10763    4. Return a failure code and let the upper layer decide what to do.
10764       This should be equivalent to 3, but without the cheating.  So let's
10765       do it that way...  But note that we must ignore the parity bit
10766       in case this is the first packet and we have not yet run parchk().
10767 */
10768             if (i == 3) {               /* Peek at sequence number */
10769                 x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
10770                 if (x < 0 || x > 63) {
10771                     debug(F111,"ttinl bad seq",dest,x);
10772                     if (timo) ttimoff();
10773                     return(-1);         /* return a nonfatal error */
10774                 }
10775             }
10776
10777 #else /* PARSENSE */
10778             dest[i++] = n & ttpmsk;
10779 #endif /* PARSENSE */
10780
10781     /* Check for end of packet */
10782
10783             if (
10784 #ifdef PARSENSE
10785 /*
10786   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
10787   This allows packet terminators and handshake characters to appear
10788   literally inside a packet data field.
10789 */
10790                 (havelen && (i > pktlen+1) &&
10791                  (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
10792 #else /* !PARSENSE */
10793 /*
10794   Built without PARSENSE, so just look for packet terminator.
10795 */
10796                 ((n & 0x7f) == eol)
10797 #endif /* PARSENSE */
10798                 ) {
10799 #ifndef PARSENSE
10800                 debug(F101,"ttinl got eol","",eol); /* (or turn) */
10801                 dest[i] = '\0';         /* Yes, terminate the string, */
10802                 /* debug(F101,"ttinl i","",i); */
10803 #else
10804 #ifdef DEBUG
10805                 if (deblog) {
10806                     if ((n & 0x7f) != eol) {
10807                         debug(F101,"ttinl EOP length","",pktlen);
10808                         debug(F101,"ttinl i","",i);
10809 #ifdef MYREAD
10810 #ifdef PARSENSE
10811 /*
10812   We read a packet based on its length.  This leaves the EOP character still
10813   unread, and so ttchk() will always return at least 1 because of this.  But
10814   if we know it is there, we can safely get rid of it.  So...
10815 */
10816                         {
10817                             int x;
10818                             while (my_count > 0) {
10819                                 x = ttinc(0);
10820                                 /* Start of next packet */
10821                                 if (x == start) { /* Save for next time */
10822                                     csave = (unsigned)((unsigned)x & 0xff);
10823                                     debug(F000,"ttinl csaved","",x);
10824                                     break;
10825                                 }
10826                                 debug(F000,"ttinl removed","",x);
10827                             }
10828                         }
10829 #endif /* PARSENSE */
10830 #endif /* MYREAD */
10831
10832                     } else debug(F101,"ttinl got eol","",eol); /* (or turn) */
10833                 }
10834 #endif /* DEBUG */
10835                 dest[i] = '\0';         /* Terminate the string, */
10836                 if (needpchk) {         /* Parity checked yet? */
10837                     if (ttprty == 0) {  /* No, check. */
10838                         if ((ttprty = parchk(dest,start,i)) > 0) {
10839                             int j;
10840                             debug(F101,"ttinl senses parity","",ttprty);
10841                             debug(F110,"ttinl packet before",dest,0);
10842                             ttpmsk = 0x7f;
10843                             for (j = 0; j < i; j++)
10844                               dest[j] &= 0x7f;  /* Strip parity from packet */
10845                             debug(F110,"ttinl packet after ",dest,0);
10846                         } else ttprty = 0; /* Restore if parchk error */
10847                     }
10848                     sopmask = ttprty;
10849                     needpchk = 0;
10850                 }
10851 #endif /* PARSENSE */
10852                 if (timo) {             /* Turn off timer. */
10853                     ttimoff();
10854                 }
10855 #ifdef COMMENT
10856                 debug(F011,"ttinl got", dest, (i < 60) ? i : -60);
10857 #else /* COMMENT */
10858                 hexdump("ttinl got",dest,i);
10859 #endif /* COMMENT */
10860 #ifdef STREAMING
10861                 /* ttinl() was called because there was non-packet */
10862                 /* data sitting int the channel.  Ignore it.       */
10863                 if (streaming && sndtyp == 'D')
10864                   return(-1);
10865 #endif /* STREAMING */
10866                 return(i);
10867             }
10868         } /* End of while() */
10869         ttimoff();
10870         return(n);
10871     }
10872 }
10873 #endif /* NOXFER */
10874
10875 /*  T T I N C --  Read a character from the communication line  */
10876 /*
10877  On success, returns the character that was read, >= 0.
10878  On failure, returns -1 or other negative myread error code,
10879    or -2 if connection is broken or ttyfd < 0.
10880    or -3 if session limit has expired,
10881    or -4 if something or other...
10882  NOTE: The API does not provide for ttinc() returning a special code
10883  upon timeout, but we need it.  So for this we have a global variable,
10884  ttinctimo.
10885 */
10886 static int ttinctimo = 0;               /* Yuk */
10887
10888 int
10889 ttinc(timo) int timo; {
10890
10891     int n = 0, fd;
10892     int is_tn = 0;
10893     CHAR ch = 0;
10894
10895     ttinctimo = 0;
10896
10897     if (ttyfd < 0) return(-2);          /* Not open. */
10898
10899     is_tn = (xlocal && netconn && IS_TELNET()) ||
10900             (!xlocal && sstelnet);
10901
10902 #ifdef TTLEBUF
10903     if (ttpush >= 0) {
10904         debug(F111,"ttinc","ttpush",ttpush);
10905         ch = ttpush;
10906         ttpush = -1;
10907         return(ch);
10908     }
10909     if (le_data) {
10910         if (le_getchar(&ch) > 0) {
10911             debug(F111,"ttinc le_getchar","ch",ch);
10912             return(ch);
10913         }
10914     }
10915 #endif /* TTLEBUF */
10916
10917 #ifdef NETCMD
10918     if (ttpipe)
10919       fd = fdin;
10920     else
10921 #endif /* NETCMD */
10922       fd = ttyfd;
10923
10924     if ((timo <= 0)                     /* Untimed. */
10925 #ifdef MYREAD
10926         || (my_count > 0)               /* Buffered char already waiting. */
10927 #endif /* MYREAD */
10928         ) {
10929 #ifdef MYREAD
10930         /* Comm line failure returns -1 thru myread, so no &= 0377 */
10931         n = myread();                   /* Wait for a character... */
10932         /* debug(F000,"ttinc MYREAD n","",n); */
10933 #ifdef CK_ENCRYPTION
10934         /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
10935         if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
10936             ch = n;
10937             ck_tn_decrypt(&ch,1);
10938             n = ch;
10939         }
10940 #endif /* CK_ENCRYPTION */
10941
10942 #ifdef NETPTY
10943         if (ttpty && n < 0) {
10944             debug(F101,"ttinc error on pty","",n);
10945             ttclos(0);
10946             return(n);
10947         }
10948 #endif /* NETPTY */
10949
10950 #ifdef TNCODE
10951         if ((n > -1) && is_tn)
10952           return((unsigned)(n & 0xff));
10953         else
10954 #endif /* TNCODE */
10955           return(n < 0 ? n : (unsigned)(n & ttpmsk));
10956
10957 #else  /* MYREAD */
10958
10959         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
10960         /* Shouldn't have to loop in ver 5A. */
10961 #ifdef NETCONN
10962           if (netconn) {                /* Special handling for net */
10963               netclos();                /* If read() returns 0 it means */
10964               netconn = 0;              /* the connection has dropped. */
10965               errno = ENOTCONN;
10966               return(-2);
10967           }
10968 #endif /* NETCONN */
10969           ;
10970         /* debug(F101,"ttinc","",ch); */
10971 #ifdef TNCODE
10972         if ((n > 0) && is_tn) {
10973 #ifdef CK_ENCRYPTION
10974             if (TELOPT_U(TELOPT_ENCRYPTION)) {
10975                 ck_tn_decrypt(&ch,1);
10976                 n = ch;
10977             }
10978 #endif /* CK_ENCRYPTION */
10979             return((unsigned)(ch & 0xff));
10980         } else
10981 #endif /* TNCODE */
10982         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
10983 #endif /* MYREAD */
10984
10985     } else {                            /* Timed read */
10986
10987         int oldalarm;
10988         saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
10989         oldalarm = alarm(timo);         /* Set alarm, save old one. */
10990         if (
10991 #ifdef CK_POSIX_SIG
10992             sigsetjmp(sjbuf,1)
10993 #else
10994             setjmp(sjbuf)
10995 #endif /* CK_POSIX_SIG */
10996             ) {                         /* Timer expired */
10997             ttinctimo = 1;
10998             n = -1;                     /* set flag */
10999         } else {
11000 #ifdef MYREAD
11001             n = myread();               /* If managing own buffer... */
11002             debug(F101,"ttinc myread","",n);
11003             ch = n;
11004 #else
11005             n = read(fd,&ch,1);         /* Otherwise call the system. */
11006             if (n == 0) n = -1;
11007             debug(F101,"ttinc read","",n);
11008 #endif /* MYREAD */
11009
11010 #ifdef CK_ENCRYPTION
11011             if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11012                 ck_tn_decrypt(&ch,1);
11013             }
11014 #endif /* CK_ENCRYPTION */
11015             if (n >= 0)
11016               n = (unsigned) (ch & 0xff);
11017             else
11018               n = (n < 0) ? -4 : -2;    /* Special return codes. */
11019         }
11020         ttimoff();                      /* Turn off the timer */
11021         if (oldalarm > 0) {
11022             if (n == -1)                /* and restore any previous alarm */
11023               oldalarm -= timo;
11024             if (oldalarm < 0)           /* adjusted by our timeout interval */
11025               oldalarm = 0;
11026             if (oldalarm) {
11027                 debug(F101,"ttinc restoring oldalarm","",oldalarm);
11028                 alarm(oldalarm);
11029             }
11030         }
11031 #ifdef NETCONN
11032         if (netconn) {
11033             if (n == -2) {              /* read() returns 0 */
11034                 netclos();              /* on network read failure */
11035                 netconn = 0;
11036                 errno = ENOTCONN;
11037             }
11038         }
11039 #endif  /* NETCONN */
11040 #ifdef TNCODE
11041         if ((n > -1) && is_tn)
11042           return((unsigned)(n & 0xff));
11043         else
11044 #endif /* TNCODE */
11045           /* Return masked char or neg. */
11046           return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
11047     }
11048 }
11049
11050 /*  S N D B R K  --  Send a BREAK signal of the given duration  */
11051
11052 static int
11053 #ifdef CK_ANSIC
11054 sndbrk(int msec) {                      /* Argument is milliseconds */
11055 #else
11056 sndbrk(msec) int msec; {
11057 #endif /* CK_ANSIC */
11058 #ifndef POSIX
11059     int x, n;
11060 #endif /* POSIX */
11061
11062 #ifdef OXOS
11063 #define BSDBREAK
11064 #endif /* OXOS */
11065
11066 #ifdef ANYBSD
11067 #define BSDBREAK
11068 #endif /* ANYBSD */
11069
11070 #ifdef BSD44
11071 #define BSDBREAK
11072 #endif /* BSD44 */
11073
11074 #ifdef COHERENT
11075 #ifdef BSDBREAK
11076 #undef BSDBREAK
11077 #endif /* BSDBREAK */
11078 #endif /* COHERENT */
11079
11080 #ifdef BELLV10
11081 #ifdef BSDBREAK
11082 #undef BSDBREAK
11083 #endif /* BSDBREAK */
11084 #endif /* BELLV10 */
11085
11086 #ifdef PROVX1
11087     char spd;
11088 #endif /* PROVX1 */
11089
11090     debug(F101,"ttsndb ttyfd","",ttyfd);
11091     if (ttyfd < 0) return(-1);          /* Not open. */
11092
11093 #ifdef Plan9
11094     return p9sndbrk(msec);
11095 #else
11096 #ifdef NETCONN
11097 #ifdef NETCMD
11098     if (ttpipe)                         /* Pipe */
11099       return(ttoc('\0'));
11100 #endif /* NETCMD */
11101 #ifdef NETPTY
11102     if (ttpty)
11103       return(ttoc('\0'));
11104 #endif /* NETPTY */
11105     if (netconn)                        /* Send network BREAK */
11106       return(netbreak());
11107 #endif /* NETCONN */
11108
11109     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
11110
11111 #ifdef POSIX                            /* Easy in POSIX */
11112     {
11113         int x;
11114         debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
11115         errno = 0;
11116         x = tcsendbreak(ttyfd,msec / 375);
11117         debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
11118         return(x);
11119     }
11120 #else
11121 #ifdef PROVX1
11122     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
11123     spd = ttbuf.sg_ospeed;              /* Save speed */
11124     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
11125     stty(ttyfd,&ttbuf);                 /*  ... */
11126     n = (int)strlen(brnuls);            /* Send the right number of nulls */
11127     x = msec / 91;
11128     if (x > n) x = n;
11129     write(ttyfd,brnuls,n);
11130     ttbuf.sg_ospeed = spd;              /* Restore speed */
11131     stty(ttyfd,&ttbuf);                 /*  ... */
11132     return(0);
11133 #else
11134 #ifdef aegis
11135     sio_$control((short)ttyfd, sio_$send_break, msec, st);
11136     return(0);
11137 #else
11138 #ifdef BSDBREAK
11139     n = FWRITE;                         /* Flush output queue. */
11140 /* Watch out for int vs long problems in &n arg! */
11141     debug(F101,"sndbrk BSDBREAK","",msec);
11142     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
11143     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
11144         perror("Can't send BREAK");
11145         return(-1);
11146     }
11147     x = msleep(msec);                    /* Sleep for so many milliseconds */
11148     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
11149         perror("BREAK stuck!!!");
11150         doexit(BAD_EXIT,-1);            /* Get out, closing the line. */
11151                                         /*   with bad exit status */
11152     }
11153     return(x);
11154 #else
11155 #ifdef ATTSV
11156 /*
11157   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
11158   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
11159   but there's no way for this code to know for sure.)
11160 */
11161     debug(F101,"sndbrk ATTSV","",msec);
11162     x = msec / 275;
11163     for (n = 0; n < x; n++) {
11164         /* Reportedly the cast breaks this function on some systems */
11165         /* But then why was it here in the first place? */
11166         if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
11167             perror("Can't send BREAK");
11168             return(-1);
11169         }
11170     }
11171     return(0);
11172 #else
11173 #ifdef  V7
11174     debug(F101,"sndbrk V7","",msec);
11175     return(genbrk(ttyfd,250));          /* Simulate a BREAK */
11176 #else
11177     debug(F101,"sndbrk catchall","",msec);
11178     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
11179     return(0);
11180 #endif /* V7 */
11181 #endif /* BSDBREAK */
11182 #endif /* ATTSV */
11183 #endif /* aegis */
11184 #endif /* PROVX1 */
11185 #endif /* POSIX */
11186 #endif /* Plan9 */
11187 }
11188
11189 /*  T T S N D B  --  Send a BREAK signal  */
11190
11191 int
11192 ttsndb() {
11193 #ifdef TN_COMPORT
11194     if (netconn && istncomport())
11195       return((tnsndb(275L) >= 0) ? 0 : -1);
11196     else
11197 #endif /* TN_COMPORT */
11198       return(sndbrk(275));
11199 }
11200
11201 /*  T T S N D L B  --  Send a Long BREAK signal  */
11202
11203 int
11204 ttsndlb() {
11205 #ifdef TN_COMPORT
11206     if (netconn && istncomport())
11207       return((tnsndb(1800L) >= 0) ? 0 : -1);
11208     else
11209 #endif /* TN_COMPORT */
11210     return(sndbrk(1500));
11211 }
11212
11213 /*  M S L E E P  --  Millisecond version of sleep().  */
11214
11215 /*
11216   Call with number of milliseconds (thousandths of seconds) to sleep.
11217   Intended only for small intervals.  For big ones, just use sleep().
11218   Highly system-dependent.
11219   Returns 0 always, even if it didn't work.
11220 */
11221
11222 /* Define MSLFTIME for systems that must use an ftime() loop. */
11223 #ifdef ANYBSD                           /* For pre-4.2 BSD versions */
11224 #ifndef BSD4
11225 #define MSLFTIME
11226 #endif /* BSD4 */
11227 #endif /* ANYBSD */
11228
11229 #ifdef TOWER1                           /* NCR Tower OS 1.0 */
11230 #define MSLFTIME
11231 #endif /* TOWER1 */
11232
11233 #ifdef COHERENT         /* Coherent... */
11234 #ifndef _I386           /* Maybe Coherent/386 should get this, too */
11235 #define MSLFTIME        /* Opinions are divided */
11236 #endif /* _I386 */
11237 #endif /* COHERENT */
11238
11239 #ifdef COMMENT
11240 #ifdef GETMSEC
11241
11242 /* Millisecond timer */
11243
11244 static long msecbase = 0L;              /* Unsigned long not portable */
11245
11246 long
11247 getmsec() {                             /* Milliseconds since base time */
11248     struct timeval xv;
11249     struct timezone xz;
11250     long secs, msecs;
11251     if (
11252 #ifdef GTODONEARG
11253         gettimeofday(&tv)
11254 #else
11255 #ifdef PTX
11256         gettimeofday(&tv, NULL)
11257 #else
11258         gettimeofday(&tv, &tz)
11259 #endif /* PTX */
11260 #endif /* GTODONEARG */
11261         < 0)
11262       return(-1);
11263     if (msecbase == 0L) {               /* First call, set base time. */
11264         msecbase = tv.tv_sec;
11265         debug(F101,"getmsec base","",msecbase);
11266     }
11267     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
11268 }
11269 #endif /* GETMSEC */
11270 #endif /* COMMENT */
11271
11272 #ifdef SELECT
11273 int
11274 ttwait(fd, secs) int fd, secs; {
11275     int x;
11276     fd_set rfds;
11277     FD_ZERO(&rfds);
11278     FD_SET(fd,&rfds);
11279     tv.tv_sec = secs;
11280     tv.tv_usec = 0L;
11281     errno = 0;
11282     if ((x = select(FD_SETSIZE,
11283 #ifdef HPUX9
11284                     (int *)
11285 #else
11286 #ifdef HPUX1000
11287                     (int *)
11288 #endif /* HPUX1000 */
11289 #endif /* HPUX9 */
11290                     &rfds,
11291                     0, 0, &tv)) < 0) {
11292         debug(F101,"ttwait select errno","",errno);
11293         return(0);
11294     } else {
11295         debug(F101,"ttwait OK","",errno);
11296         x = FD_ISSET(fd, &rfds);
11297         debug(F101,"ttwait select x","",x);
11298         return(x ? 1 : 0);
11299     }
11300 }
11301 #endif /* SELECT */
11302
11303 int
11304 msleep(m) int m; {
11305 /*
11306   Other possibilities here are:
11307    nanosleep(), reportedly defined in POSIX.4.
11308    sginap(), IRIX only (back to what IRIX version I don't know).
11309 */
11310 #ifdef Plan9
11311     return _SLEEP(m);
11312 #else
11313 #ifdef BEOSORBEBOX
11314     snooze(m*1000);
11315 #else /* BEOSORBEBOX */
11316 #ifdef SELECT
11317     int t1, x;
11318     debug(F101,"msleep SELECT 1","",m);
11319     if (m <= 0) return(0);
11320     if (m >= 1000) {                    /* Catch big arguments. */
11321         sleep(m/1000);
11322         m = m % 1000;
11323         if (m < 10) return(0);
11324     }
11325     debug(F101,"msleep SELECT 2","",m);
11326 #ifdef BELLV10
11327     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
11328     debug(F101,"msleep BELLV10 select","",x);
11329 #else /* BELLV10 */
11330 #ifdef HPUX9
11331     gettimeofday(&tv, &tz);
11332 #else
11333
11334 #ifndef COHERENT
11335 #ifdef GTODONEARG
11336     if (gettimeofday(&tv) < 0)
11337 #else
11338 #ifdef PTX
11339     if (gettimeofday(&tv,NULL) < 0)
11340 #else
11341 #ifdef NOTIMEZONE
11342     if (gettimeofday(&tv, NULL) < 0)    /* wonder what this does... */
11343 #else
11344     if (gettimeofday(&tv, &tz) < 0)
11345 #endif /* NOTIMEZONE */
11346 #endif /* PTX */
11347 #endif /* GTODONEARG */
11348       return(-1);
11349     t1 = tv.tv_sec;                     /* Seconds */
11350 #endif /* COHERENT */
11351 #endif /* HPUX9 */
11352     tv.tv_sec = 0;                      /* Use select() */
11353     tv.tv_usec = m * 1000L;
11354 #ifdef BSD44
11355     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11356     debug(F101,"msleep BSD44 select","",x);
11357 #else /* BSD44 */
11358 #ifdef __linux__
11359     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11360     debug(F101,"msleep __linux__ select","",x);
11361 #else /* __linux__ */
11362 #ifdef BSD43
11363     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11364     debug(F101,"msleep BSD43 select","",x);
11365 #else /* BSD43 */
11366 #ifdef QNX6
11367     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11368     debug(F101,"msleep QNX6 select","",x);
11369 #else /* QNX6 */
11370 #ifdef QNX
11371     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11372     debug(F101,"msleep QNX select","",x);
11373 #else /* QNX */
11374 #ifdef COHERENT
11375     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11376     debug(F101,"msleep COHERENT select","",x);
11377 #else /* COHERENT */
11378 #ifdef HPUX1000                         /* 10.00 only, not 10.10 or later */
11379     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11380     debug(F101,"msleep HP-UX 10.00 select","",x);
11381 #else /* HPUX1000 */
11382 #ifdef SVR4
11383     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11384     debug(F101,"msleep SVR4 select","",x);
11385 #else /* SVR4 */
11386 #ifdef OSF40
11387     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11388     debug(F101,"msleep OSF40 select","",x);
11389 #else /* OSF40 */
11390 #ifdef PTX
11391     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11392     debug(F101,"msleep OSF40 select","",x);
11393 #else
11394     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11395     debug(F101,"msleep catch-all select","",x);
11396 #endif /* PTX */
11397 #endif /* OSF40 */
11398 #endif /* HP1000 */
11399 #endif /* SVR4 */
11400 #endif /* COHERENT */
11401 #endif /* QNX */
11402 #endif /* QNX6 */
11403 #endif /* BSD43 */
11404 #endif /* __linux__ */
11405 #endif /* BSD44 */
11406 #endif /* BELLV10 */
11407     return(0);
11408
11409 #else                                   /* Not SELECT */
11410 #ifdef CK_POLL                          /* We have poll() */
11411     struct pollfd pfd;                  /* Supply a valid address for poll() */
11412
11413 #ifdef ODT30                            /* But in SCO ODT 3.0 */
11414 #ifdef NAP                              /* we should use nap() instead */
11415     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
11416     nap((long)m);                          /* seems to break dialing. */
11417     return(0);
11418 #else
11419     debug(F101,"msleep ODT 3.0 POLL","",m);
11420     poll(&pfd, 0, m);
11421     return(0);
11422 #endif /* NAP */
11423 #else
11424     debug(F101,"msleep POLL","",m);
11425     poll(&pfd, 0, m);
11426     return(0);
11427 #endif /* ODT30 */
11428
11429 /*
11430   We could handle the above more cleanly by just letting nap() always
11431   take precedence over poll() in this routine, but there is no way to know
11432   whether that would break something else.
11433 */
11434
11435 #else                                   /* Not POLL */
11436 #ifdef USLEEP
11437 /*
11438   "This routine is implemented using setitimer(2); it requires eight
11439   system calls...".  In other words, it might take 5 minutes to sleep
11440   10 milliseconds...
11441 */
11442     debug(F101,"msleep USLEEP","",m);
11443     if (m >= 1000) {                    /* Catch big arguments. */
11444         sleep(m/1000);
11445         m = m % 1000;
11446         if (m < 10) return(0);
11447     }
11448     usleep((unsigned int)(m * 1000));
11449     return(0);
11450 #else
11451 #ifdef aegis
11452     time_$clock_t dur;
11453     debug(F101,"msleep aegis","",m);
11454     dur.c2.high16 = 0;
11455     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
11456     time_$wait(time_$relative, dur, st);
11457     return(0);
11458 #else
11459 #ifdef PROVX1
11460     debug(F101,"msleep Venix","",m);
11461     if (m <= 0) return(0);
11462     sleep(-((m * 60 + 500) / 1000));
11463     return(0);
11464 #else
11465 #ifdef NAP
11466     debug(F101,"msleep NAP","",m);
11467     nap((long)m);
11468     return(0);
11469 #else
11470 #ifdef ATTSV
11471 #ifndef BSD44
11472     extern long times();                /* Or #include <times.h> ? */
11473 #endif /* BSD44 */
11474     long t1, t2, tarray[4];
11475     int t3;
11476     char *cp = getenv("HZ");
11477     int CLOCK_TICK;
11478     int hertz;
11479
11480     if (cp && (hertz = atoi(cp))) {
11481         CLOCK_TICK  = 1000 / hertz;
11482     } else {                            /* probably single user mode */
11483 #ifdef HZ
11484         CLOCK_TICK  = 1000 / HZ;
11485 #else
11486         static warned = 0;
11487         /* HZ always exists in, for instance, SCO Xenix, so you don't have to
11488          * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
11489          * have Xenix, you have should have nap(), so the best is to use -DNAP
11490          * in the makefile. Most systems have HZ.
11491          */
11492         CLOCK_TICK = 17;                /* 1/60 sec */
11493         if (!warned) {
11494           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
11495                  1000 / CLOCK_TICK);
11496           warned = 1;
11497         }
11498 #endif /* !HZ */
11499     }
11500     debug(F101,"msleep ATTSV","",m);
11501     if (m <= 0) return(0);
11502     if (m >= 1000) {                    /* Catch big arguments. */
11503         sleep(m/1000);
11504         m = m % 1000;
11505         if (m < 10) return(0);
11506     }
11507     if ((t1 = times(tarray)) < 0) return(-1);
11508     while (1) {
11509         if ((t2 = times(tarray)) < 0) return(-1);
11510         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
11511         if (t3 > m) return(t3);
11512     }
11513 #else /* Not ATTSV */
11514 #ifdef MSLFTIME                         /* Use ftime() loop... */
11515     int t1, t3 = 0;
11516     debug(F101,"msleep MSLFTIME","",m);
11517     if (m <= 0) return(0);
11518     if (m >= 1000) {                    /* Catch big arguments. */
11519         sleep(m/1000);
11520         m = m % 1000;
11521         if (m < 10) return(0);
11522     }
11523 #ifdef QNX
11524     ftime(&ftp);                        /* void ftime() in QNX */
11525 #else
11526     if (ftime(&ftp) < 0) return(-1);    /* Get base time. */
11527 #endif /* QNX */
11528     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
11529     while (1) {
11530         ftime(&ftp);                    /* Get current time and compare. */
11531         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
11532         if (t3 > m) return(0);
11533     }
11534 #else
11535 /* This includes true POSIX, which has no way to do this. */
11536     debug(F101,"msleep busy loop","",m);
11537     if (m >= 1000) {                    /* Catch big arguments. */
11538         sleep(m/1000);
11539         m = m % 1000;
11540         if (m < 10) return(0);
11541     }
11542     if (m > 0) while (m > 0) m--;       /* Just a dumb busy loop */
11543     return(0);
11544 #endif /* MSLFTIME */
11545 #endif /* ATTSV */
11546 #endif /* NAP */
11547 #endif /* PROVX1 */
11548 #endif /* aegis */
11549 #endif /* CK_POLL */
11550 #endif /* SELECT */
11551 #endif /* BEOSORBEBOX */
11552 #endif /* USLEEP */
11553 #endif /* Plan9 */
11554 }
11555
11556 /*  R T I M E R --  Reset elapsed time counter  */
11557
11558 VOID
11559 rtimer() {
11560     tcount = time( (time_t *) 0 );
11561 }
11562
11563
11564 /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
11565
11566 int
11567 gtimer() {
11568     int x;
11569     x = (int) (time( (time_t *) 0 ) - tcount);
11570     debug(F101,"gtimer","",x);
11571     return( (x < 0) ? 0 : x );
11572 }
11573
11574 #ifdef GFTIMER
11575 /*
11576   Floating-point timers.  Require not only floating point support, but
11577   also gettimeofday().
11578 */
11579 static struct timeval tzero;
11580
11581 VOID
11582 rftimer() {
11583 #ifdef GTODONEARG                       /* Account for Mot's definition */
11584     (VOID) gettimeofday(&tzero);
11585 #else
11586     (VOID) gettimeofday(&tzero, (struct timezone *)0);
11587 #endif /* GTODONEARG */
11588 }
11589
11590 CKFLOAT
11591 gftimer() {
11592     struct timeval tnow, tdelta;
11593     CKFLOAT s;
11594 #ifdef DEBUG
11595     char fpbuf[64];
11596 #endif /* DEBUG */
11597 #ifdef GTODONEARG                       /* Account for Mot's definition */
11598     (VOID) gettimeofday(&tnow);
11599 #else
11600     (VOID) gettimeofday(&tnow, (struct timezone *)0);
11601 #endif /* GTODONEARG */
11602
11603     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
11604     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
11605
11606     if (tdelta.tv_usec < 0) {
11607         tdelta.tv_sec--;
11608         tdelta.tv_usec += 1000000;
11609     }
11610     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
11611     if (s < GFMINTIME)
11612       s = GFMINTIME;
11613 #ifdef DEBUG
11614     if (deblog) {
11615         sprintf(fpbuf,"%f",s);
11616         debug(F110,"gftimer",fpbuf,0);
11617     }
11618 #endif /* DEBUG */
11619     return(s);
11620 }
11621 #endif /* GFTIMER */
11622
11623 /*  Z T I M E  --  Return asctime()-format date/time string  */
11624 /*
11625   NOTE: as a side effect of calling this routine, we can also set the
11626   following two variables, giving the micro- and milliseconds (fractions of
11627   seconds) of the clock time.  Currently this is done only in BSD-based builds
11628   that use gettimeofday().  When these variables are not filled in, they are
11629   left with a value of -1L.
11630 */
11631 static char asctmbuf[64];
11632
11633 VOID
11634 ztime(s) char **s; {
11635
11636 #ifdef GFTIMER
11637 /*
11638   The gettimeofday() method, which also sets ztmsec and ztusec, works for
11639   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
11640   and extern declarations for them are in ckcdeb.h; thus they are
11641   declared in this file by inclusion of ckcdeb.h.
11642 */
11643     char *asctime();
11644     struct tm *localtime();
11645     struct tm *tp;
11646     ztmsec = -1L;
11647     ztusec = -1L;
11648
11649     if (!s)
11650       debug(F100,"ztime s==NULL","",0);
11651
11652 #ifdef GTODONEARG
11653     /* No 2nd arg in Motorola SV88 and some others */
11654     if (gettimeofday(&tv) > -1)
11655 #else
11656 #ifndef COHERENT
11657 #ifdef PTX
11658     if (gettimeofday(&tv,NULL) > -1)
11659 #else
11660 #ifdef NOTIMEZONE
11661     if (gettimeofday(&tv, NULL) > -1)   /* wonder what this does... */
11662 #else
11663     if (gettimeofday(&tv, &tz) > -1)
11664 #endif /* NOTIMEZONE */
11665 #endif /* PTX */
11666 #endif /* COHERENT */
11667 #endif /* GTODONEARG */
11668       {                                 /* Fill in tm struct */
11669         ztusec = tv.tv_usec;            /* Microseconds */
11670         ztmsec = ztusec / 1000L;        /* Milliseconds */
11671 #ifdef HPUX9
11672         {
11673             time_t zz;
11674             zz = tv.tv_sec;
11675             tp = localtime(&zz);        /* Convert to local time */
11676         }
11677 #else
11678 #ifdef HPUX1000
11679         {
11680             time_t zz;
11681             zz = tv.tv_sec;
11682             tp = localtime(&zz);
11683         }
11684 #else
11685 #ifdef LINUX
11686         {   /* avoid unaligned access trap on 64-bit platforms */
11687             time_t zz;
11688             zz = tv.tv_sec;
11689             tp = localtime(&zz);
11690         }
11691 #else
11692 #ifdef MACOSX
11693         tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
11694 #else
11695         tp = localtime(&tv.tv_sec);
11696 #endif /* MACOSX */
11697 #endif /* LINUX */
11698 #endif /* HPUX1000 */
11699 #endif /* HPUX9 */
11700         if (s) {
11701             char * s2;
11702             s2 = asctime(tp);           /* Convert result to ASCII string */
11703             asctmbuf[0] = '\0';
11704             if (s2) ckstrncpy(asctmbuf,s2,64);
11705             *s = asctmbuf;
11706             debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
11707         }
11708     }
11709 #else  /* Not GFTIMER */
11710
11711 #undef ZTIMEV7                          /* Which systems need to use */
11712 #ifdef COHERENT                         /* old UNIX Version 7 way... */
11713 #define ZTIMEV7
11714 #endif /* COHERENT */
11715 #ifdef TOWER1
11716 #define ZTIMEV7
11717 #endif /* TOWER1 */
11718 #ifdef ANYBSD
11719 #ifndef BSD42
11720 #define ZTIMEV7
11721 #endif /* BSD42 */
11722 #endif /* ANYBSD */
11723 #ifdef V7
11724 #ifndef MINIX
11725 #define ZTIMEV7
11726 #endif /* MINIX */
11727 #endif /* V7 */
11728 #ifdef POSIX
11729 #define ZTIMEV7
11730 #endif /* POSIX */
11731
11732 #ifdef HPUX1020
11733 /*
11734   Prototypes are in <time.h>, included above.
11735 */
11736     time_t clock_storage;
11737     clock_storage = time((void *) 0);
11738     if (s) {
11739         *s = ctime(&clock_storage);
11740         debug(F110,"ztime: HPUX 10.20",*s,0);
11741     }
11742 #else
11743 #ifdef ATTSV                            /* AT&T way */
11744 /*  extern long time(); */              /* Theoretically these should */
11745     char *ctime();                      /* already been dcl'd in <time.h> */
11746     time_t clock_storage;
11747     clock_storage = time(
11748 #ifdef IRIX60
11749                          (time_t *)
11750 #else
11751 #ifdef BSD44
11752                          (time_t *)
11753 #else
11754                          (long *)
11755 #endif /* BSD44 */
11756 #endif /* IRIX60 */
11757                          0 );
11758     if (s) {
11759         *s = ctime( &clock_storage );
11760         debug(F110,"ztime: ATTSV",*s,0);
11761     }
11762 #else
11763 #ifdef PROVX1                           /* Venix 1.0 way */
11764     int utime[2];
11765     time(utime);
11766     if (s) {
11767         *s = ctime(utime);
11768         debug(F110,"ztime: PROVX1",*s,0);
11769     }
11770 #else
11771 #ifdef BSD42                            /* 4.2BSD way */
11772     char *asctime();
11773     struct tm *localtime();
11774     struct tm *tp;
11775     gettimeofday(&tv, &tz);
11776     ztusec = tv.tv_usec;
11777     ztmsec = tv.tv_usec / 1000L;
11778     tp = localtime(&tv.tv_sec);
11779     if (s) {
11780         *s = asctime(tp);
11781         debug(F111,"ztime: BSD42",*s,ztusec);
11782     }
11783 #else
11784 #ifdef MINIX                            /* MINIX way */
11785 #ifdef COMMENT
11786     extern long time();                 /* Already got these from <time.h> */
11787     extern char *ctime();
11788 #endif /* COMMENT */
11789     time_t utime[2];
11790     time(utime);
11791     if (s) {
11792         *s = ctime(utime);
11793         debug(F110,"ztime: MINIX",*s,0);
11794     }
11795 #else
11796 #ifdef ZTIMEV7                          /* The regular way */
11797     char *asctime();
11798     struct tm *localtime();
11799     struct tm *tp;
11800     long xclock;                        /* or unsigned long for BeBox? */
11801     time(&xclock);
11802     tp = localtime(&xclock);
11803     if (s) {
11804         *s = asctime(tp);
11805         debug(F110,"ztime: ZTIMEV7",*s,0);
11806     }
11807 #else                                   /* Catch-all for others... */
11808     if (s) {
11809         *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
11810         debug(F110,"ztime: catch-all",*s,0);
11811     }
11812 #endif /* ZTIMEV7 */
11813 #endif /* MINIX */
11814 #endif /* BSD42 */
11815 #endif /* PROVX1 */
11816 #endif /* ATTSV */
11817 #endif /* HPUX1020 */
11818 #endif /* GFTIMER */
11819 }
11820
11821 /*  C O N G M  --  Get console terminal modes.  */
11822
11823 /*
11824   Saves initial console mode, and establishes variables for switching
11825   between current (presumably normal) mode and other modes.
11826   Should be called when program starts, but only after establishing
11827   whether program is in the foreground or background.
11828   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
11829 */
11830 int
11831 congm() {
11832     int fd;
11833     if (backgrd || !isatty(0)) {        /* If in background. */
11834         cgmf = -1;                      /* Don't bother, modes are garbage. */
11835         return(-1);
11836     }
11837     if (cgmf > 0) return(0);            /* Already did this. */
11838     debug(F100,"congm getting modes","",0); /* Need to do it. */
11839 #ifdef aegis
11840     ios_$inq_type_uid(ios_$stdin, conuid, st);
11841     if (st.all != status_$ok) {
11842         fprintf(stderr, "problem getting stdin objtype: ");
11843         error_$print(st);
11844     }
11845     concrp = (conuid == mbx_$uid);
11846     conbufn = 0;
11847 #endif /* aegis */
11848
11849 #ifndef BEBOX
11850     if ((fd = open(CTTNAM,2)) < 0) {    /* Open controlling terminal */
11851 #ifdef COMMENT
11852         fprintf(stderr,"Error opening %s\n", CTTNAM);
11853         perror("congm");
11854         return(-1);
11855 #else
11856         fd = 0;
11857 #endif /* COMMENT */
11858     }
11859 #else
11860     fd = 0;
11861 #endif /* !BEBOX */
11862 #ifdef BSD44ORPOSIX
11863     if (tcgetattr(fd,&ccold) < 0) return(-1);
11864     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
11865     if (tcgetattr(fd,&ccraw) < 0) return(-1);
11866 #else
11867 #ifdef ATTSV
11868     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
11869     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
11870     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
11871 #ifdef VXVE
11872     cccbrk.c_line = 0;                  /* STTY line 0 for CDC VX/VE */
11873     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
11874     ccraw.c_line = 0;                   /* STTY line 0 for CDC VX/VE */
11875     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
11876 #endif /* VXVE */
11877 #else
11878 #ifdef BELLV10
11879     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
11880     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
11881     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
11882     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
11883 #else
11884     if (gtty(fd,&ccold) < 0) return(-1);
11885     if (gtty(fd,&cccbrk) < 0) return(-1);
11886     if (gtty(fd,&ccraw) < 0) return(-1);
11887 #endif /* BELLV10 */
11888 #endif /* ATTSV */
11889 #endif /* BSD44ORPOSIX */
11890 #ifdef sony_news                        /* Sony NEWS */
11891     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
11892         perror("congm error getting Kanji mode");
11893         debug(F101,"congm error getting Kanji mode","",0);
11894         km_con = -1;                    /* Make sure this stays undefined. */
11895         return(-1);
11896     }
11897 #endif /* sony_news */
11898     if (fd > 0)
11899       close(fd);
11900     cgmf = 1;                           /* Flag that we got them. */
11901     return(1);
11902 }
11903
11904
11905 static VOID
11906 congetbuf(x) int x; {
11907     int n;
11908     n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
11909     if (x > n) {
11910         debug(F101,"congetbuf char loss","",x-n);
11911         x = n;
11912     }
11913     x = read(0,conbufp,x);
11914     conbufn += x;
11915     debug(F111,"congetbuf readahead",conbuf,x);
11916 }
11917
11918
11919 /*  C O N C B --  Put console in cbreak mode.  */
11920
11921 /*  Returns 0 if ok, -1 if not  */
11922
11923 int
11924 #ifdef CK_ANSIC
11925 concb(char esc)
11926 #else
11927 concb(esc) char esc;
11928 #endif /* CK_ANSIC */
11929 /* concb */ {
11930     int x;
11931     debug(F101,"concb constate","",constate);
11932     debug(F101,"concb cgmf","",cgmf);
11933     debug(F101,"concb backgrd","",backgrd);
11934
11935     if (constate == CON_CB)
11936       return(0);
11937
11938     if (cgmf < 1)                       /* Did we get console modes yet? */
11939       if (!backgrd)                     /* No, in background? */
11940         congm();                        /* No, try to get them now. */
11941     if (cgmf < 1)                       /* Still don't have them? */
11942       return(0);                        /* Give up. */
11943     debug(F101,"concb ttyfd","",ttyfd);
11944     debug(F101,"concb ttfdflg","",ttfdflg);
11945 #ifdef COMMENT
11946     /* This breaks returning to prompt after protocol with "-l 0" */
11947     /* Commented out July 1998 */
11948     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
11949       return(0);
11950 #endif /* COMMENT */
11951     x = isatty(0);
11952     debug(F101,"concb isatty","",x);
11953     if (!x) return(0);                  /* Only when running on real ttys */
11954     debug(F101,"concb xsuspend","",xsuspend);
11955     if (backgrd)                        /* Do nothing if in background. */
11956       return(0);
11957     escchr = esc;                       /* Make this available to other fns */
11958     ckxech = 1;                         /* Program can echo characters */
11959 #ifdef aegis
11960     conbufn = 0;
11961     if (concrp) return(write(1, "\035\002", 2));
11962     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
11963 #endif /* aegis */
11964
11965 #ifdef COHERENT
11966 #define SVORPOSIX
11967 #endif /* COHERENT */
11968
11969 #ifdef Plan9
11970     x = p9concb();
11971 #else
11972 #ifndef SVORPOSIX                       /* BSD, V7, etc */
11973     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
11974     debug(F101,"concb stty CBREAK","",0);
11975     cccbrk.sg_flags |= (CBREAK|CRMOD);  /* Set to character wakeup, */
11976     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
11977     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
11978     errno = 0;
11979 /*
11980   BSD stty() clears the console buffer.  So if anything is waiting in it,
11981   we have to read it now to avoid losing it.
11982 */
11983     x = conchk();
11984     if (x > 0)
11985       congetbuf(x);
11986
11987 #ifdef BELLV10
11988     x = ioctl(0,TIOCSETP,&cccbrk);
11989 #else
11990     x = stty(0,&cccbrk);
11991     debug(F101,"cccbrk.sg_flags concb x","", x);
11992 #endif /* BELLV10 */
11993 #else                                   /* Sys V and POSIX */
11994 #ifndef OXOS
11995     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
11996 #ifdef QNX
11997     /* Don't mess with IEXTEN */
11998     cccbrk.c_lflag &= ~(ICANON|ECHO);
11999 #else
12000 #ifdef COHERENT
12001     cccbrk.c_lflag &= ~(ICANON|ECHO);
12002 #else
12003     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
12004 #endif /* COHERENT */
12005 #endif /* QNX */
12006     cccbrk.c_lflag |= ISIG;             /* Allow signals in command mode. */
12007     cccbrk.c_iflag |= IGNBRK;           /* But ignore BREAK signal */
12008     cccbrk.c_iflag &= ~BRKINT;
12009
12010 #else /* OXOS */
12011     debug(F100,"concb OXOS is defined","",0);
12012     cccbrk.c_lflag &= ~(ICANON|ECHO);
12013     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
12014 #endif /* OXOS */
12015 #ifdef COMMENT
12016 /*
12017   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
12018   array reference is out of bounds.  It's only a debug() call so who needs it.
12019 */
12020 #ifdef VSUSP
12021     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
12022 #endif /* VSUSP */
12023 #endif /* COMMENT */
12024 #ifndef VINTR
12025     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
12026     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
12027 #else
12028     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
12029     cccbrk.c_cc[VINTR] = 003;
12030 #endif /* VINTR */
12031 #ifndef VQUIT
12032     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
12033 #else
12034     cccbrk.c_cc[VQUIT] = escchr;
12035 #endif /* VQUIT */
12036 #ifndef VEOF
12037     cccbrk.c_cc[4] = 1;
12038 #else
12039 #ifndef OXOS
12040 #ifdef VMIN
12041     cccbrk.c_cc[VMIN] = 1;
12042 #endif /* VMIN */
12043 #else /* OXOS */
12044     cccbrk.c_min = 1;
12045 #endif /* OXOS */
12046 #endif /* VEOF */
12047 #ifdef ZILOG
12048     cccbrk.c_cc[5] = 0;
12049 #else
12050 #ifndef VEOL
12051     cccbrk.c_cc[5] = 1;
12052 #else
12053 #ifndef OXOS
12054 #ifdef VTIME
12055     cccbrk.c_cc[VTIME] = 1;
12056 #endif /* VTIME */
12057 #else /* OXOS */
12058     cccbrk.c_time = 1;
12059 #endif /* OXOS */
12060 #endif /* VEOL */
12061 #endif /* ZILOG */
12062     errno = 0;
12063 #ifdef BSD44ORPOSIX                     /* Set new modes */
12064     x = tcsetattr(0,TCSADRAIN,&cccbrk);
12065 #else /* ATTSV */                       /* or the POSIX way */
12066     x = ioctl(0,TCSETAW,&cccbrk);       /* the Sys V way */
12067 #endif /* BSD44ORPOSIX */
12068 #endif /* SVORPOSIX */
12069
12070 #ifdef COHERENT
12071 #undef SVORPOSIX
12072 #endif /* COHERENT */
12073     debug(F101,"concb x","",x);
12074     debug(F101,"concb errno","",errno);
12075 #ifdef NONOSETBUF
12076     if (x > -1) {
12077         setbuf(stdout,NULL);    /* Make console unbuffered. */
12078         debug(F100,"concb setbuf A","",0);
12079     }
12080 #else
12081 #ifndef aegis
12082 #ifndef NOSETBUF
12083     if (x > -1) {
12084         setbuf(stdout,NULL);    /* Make console unbuffered. */
12085         debug(F100,"concb setbuf B","",0);
12086     }
12087 #endif /* NOSETBUF */
12088 #endif /* aegis */
12089 #endif /* NONOSETBUF */
12090
12091 #ifdef  V7
12092 #ifndef MINIX
12093     if (kmem[CON] < 0) {
12094         qaddr[CON] = initrawq(0);
12095         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
12096             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
12097             perror("/dev/kmem");
12098             exit(1);
12099         }
12100     }
12101 #endif /* MINIX */
12102 #endif /* V7 */
12103 #endif /* Plan9 */
12104
12105     if (x > -1)
12106       constate = CON_CB;
12107
12108     debug(F101,"concb returns","",x);
12109     return(x);
12110 }
12111
12112 /*  C O N B I N  --  Put console in binary mode  */
12113
12114 /*  Returns 0 if ok, -1 if not  */
12115
12116 int
12117 #ifdef CK_ANSIC
12118 conbin(char esc)
12119 #else
12120 conbin(esc) char esc;
12121 #endif /* CK_ANSIC */
12122 /* conbin */  {
12123
12124     int x;
12125
12126     debug(F101,"conbin constate","",constate);
12127
12128     if (constate == CON_BIN)
12129       return(0);
12130
12131     if (!isatty(0)) return(0);          /* only for real ttys */
12132     congm();                            /* Get modes if necessary. */
12133     debug(F100,"conbin","",0);
12134     escchr = esc;                       /* Make this available to other fns */
12135     ckxech = 1;                         /* Program can echo characters */
12136 #ifdef aegis
12137     conbufn = 0;
12138     if (concrp) return(write(1, "\035\002", 2));
12139     if (conuid == input_pad_$uid) {
12140         pad_$raw(ios_$stdin, st);
12141         return(0);
12142       }
12143 #endif /* aegis */
12144
12145 #ifdef COHERENT
12146 #define SVORPOSIX
12147 #endif /* COHERENT */
12148
12149 #ifdef Plan9
12150     return p9conbin();
12151 #else
12152 #ifdef SVORPOSIX
12153 #ifndef OXOS
12154 #ifdef QNX
12155     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12156 #else
12157 #ifdef COHERENT
12158     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12159 #else
12160     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
12161 #endif /* COHERENT */
12162 #endif /* QNX */
12163 #else /* OXOS */
12164     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12165     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
12166 #endif /* OXOS */
12167     ccraw.c_iflag |= IGNPAR;
12168 /*
12169   Note that for terminal sessions we disable Xon/Xoff flow control to allow
12170   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
12171   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
12172   control, if in use, is not affected.
12173 */
12174 #ifdef ATTSV
12175 #ifdef BSD44
12176     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
12177                         |INPCK|ISTRIP);
12178 #else
12179     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
12180                         |INPCK|ISTRIP);
12181 #endif /* BSD44 */
12182 #else /* POSIX */
12183     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
12184 #endif /* ATTSV */
12185     ccraw.c_oflag &= ~OPOST;
12186 #ifdef COMMENT
12187 /*
12188   WHAT THE HECK WAS THIS FOR?
12189   The B9600 setting (obviously) prevents CONNECT from working at any
12190   speed other than 9600 when you are logged in to the 7300 on a serial
12191   line.  Maybe some of the other flags are necessary -- if so, put back
12192   the ones that are needed.  This code is supposed to work the same, no
12193   matter whether you are logged in to the 7300 on the real console device,
12194   or through a serial port.
12195 */
12196 #ifdef ATT7300
12197     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
12198 #endif /* ATT7300 */
12199 #endif /* COMMENT */
12200
12201 /*** Kermit used to put the console in 8-bit raw mode, but some users have
12202  *** pointed out that this should not be done, since some sites actually
12203  *** use terminals with parity settings on their Unix systems, and if we
12204  *** override the current settings and stop doing parity, then their terminals
12205  *** will display blotches for characters whose parity is wrong.  Therefore,
12206  *** the following two lines are commented out (Larry Afrin, Clemson U):
12207  ***
12208  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
12209  ***   ccraw.c_cflag |= (CS8|CREAD);
12210  ***
12211  *** Sys III/V sites that have trouble with this can restore these lines.
12212  ***/
12213 #ifndef VINTR
12214     ccraw.c_cc[0] = 003;                /* Interrupt char is Ctrl-C */
12215 #else
12216     ccraw.c_cc[VINTR] = 003;
12217 #endif /* VINTR */
12218 #ifndef VQUIT
12219     ccraw.c_cc[1] = escchr;             /* Escape during packet mode */
12220 #else
12221     ccraw.c_cc[VQUIT] = escchr;
12222 #endif /* VQUIT */
12223 #ifndef VEOF
12224     ccraw.c_cc[4] = 1;
12225 #else
12226 #ifndef OXOS
12227 #ifdef VMIN
12228     ccraw.c_cc[VMIN] = 1;
12229 #endif /* VMIN */
12230 #else /* OXOS */
12231     ccraw.c_min = 1;
12232 #endif /* OXOS */
12233 #endif /* VEOF */
12234
12235 #ifdef ZILOG
12236     ccraw.c_cc[5] = 0;
12237 #else
12238 #ifndef VEOL
12239     ccraw.c_cc[5] = 1;
12240 #else
12241 #ifndef OXOS
12242 #ifdef VTIME
12243     ccraw.c_cc[VTIME] = 1;
12244 #endif /* VTIME */
12245 #else /* OXOS */
12246     ccraw.c_time = 1;
12247 #endif /* OXOS */
12248 #endif /* VEOL */
12249 #endif /* ZILOG */
12250
12251 #ifdef BSD44ORPOSIX
12252     x = tcsetattr(0,TCSADRAIN,&ccraw);  /* Set new modes. */
12253 #else
12254     x = ioctl(0,TCSETAW,&ccraw);
12255 #endif /* BSD44ORPOSIX */
12256 #else /* Berkeley, etc. */
12257     x = conchk();                       /* Because stty() is destructive */
12258     if (x > 0)
12259       congetbuf(x);
12260     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
12261     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
12262 #ifdef BELLV10
12263     x = ioctl(0,TIOCSETP,&ccraw);
12264 #else
12265     x = stty(0,&ccraw);
12266 #endif /* BELLV10 */
12267 #endif /* SVORPOSIX */
12268 #endif /* Plan9 */
12269
12270     if (x > -1)
12271       constate = CON_BIN;
12272
12273     debug(F101,"conbin returns","",x);
12274     return(x);
12275
12276 #ifdef COHERENT
12277 #undef SVORPOSIX
12278 #endif /* COHERENT */
12279
12280 }
12281
12282
12283 /*  C O N R E S  --  Restore the console terminal  */
12284
12285 int
12286 conres() {
12287     int x;
12288     debug(F101,"conres cgmf","",cgmf);
12289     debug(F101,"conres constate","",constate);
12290
12291     if (cgmf < 1)                       /* Do nothing if modes unchanged */
12292       return(0);
12293     if (constate == CON_RES)
12294       return(0);
12295
12296     if (!isatty(0)) return(0);          /* only for real ttys */
12297     debug(F100,"conres isatty ok","",0);
12298     ckxech = 0;                         /* System should echo chars */
12299
12300 #ifdef aegis
12301     conbufn = 0;
12302     if (concrp) return(write(1, "\035\001", 2));
12303     if (conuid == input_pad_$uid) {
12304         pad_$cooked(ios_$stdin, st);
12305         constate = CON_RES;
12306         return(0);
12307     }
12308 #endif /* aegis */
12309
12310 #ifdef Plan9
12311     p9conres();
12312 #else
12313 #ifdef BSD44ORPOSIX
12314     debug(F100,"conres restoring tcsetattr","",0);
12315     x = tcsetattr(0,TCSADRAIN,&ccold);
12316 #else
12317 #ifdef ATTSV
12318     debug(F100,"conres restoring ioctl","",0);
12319     x = ioctl(0,TCSETAW,&ccold);
12320 #else /* BSD, V7, and friends */
12321 #ifdef sony_news                        /* Sony NEWS */
12322     if (km_con != -1)
12323       ioctl(0,TIOCKSET,&km_con);        /* Restore console Kanji mode */
12324 #endif /* sony_news */
12325     msleep(100);
12326     debug(F100,"conres restoring stty","",0);
12327     x = conchk();                       /* Because stty() is destructive */
12328     if (x > 0)
12329       congetbuf(x);
12330 #ifdef BELLV10
12331     x = ioctl(0,TIOCSETP,&ccold);
12332 #else
12333     x = stty(0,&ccold);
12334 #endif /* BELLV10 */
12335 #endif /* ATTSV */
12336 #endif /* BSD44ORPOSIX */
12337 #endif /* Plan9 */
12338     if (x > -1)
12339       constate = CON_RES;
12340
12341     debug(F101,"conres returns","",x);
12342     return(x);
12343 }
12344
12345 /*  C O N O C  --  Output a character to the console terminal  */
12346
12347 int
12348 #ifdef CK_ANSIC
12349 conoc(char c)
12350 #else
12351 conoc(c) char c;
12352 #endif /* CK_ANSIC */
12353 /* conoc */ {
12354
12355 #ifdef IKSD
12356     if (inserver && !local)
12357       return(ttoc(c));
12358
12359 #ifdef CK_ENCRYPTION
12360     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12361         ck_tn_encrypt(&c,1);
12362 #endif /* CK_ENCRYPTION */
12363 #endif /* IKSD */
12364
12365 #ifdef Plan9
12366     return conwrite(&c,1);
12367 #else
12368     return(write(1,&c,1));
12369 #endif /* Plan9 */
12370 }
12371
12372 /*  C O N X O  --  Write x characters to the console terminal  */
12373
12374 int
12375 conxo(x,s) int x; char *s; {
12376
12377 #ifdef IKSD
12378     if (inserver && !local)
12379       return(ttol((CHAR *)s,x));
12380
12381 #ifdef CK_ENCRYPTION
12382     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12383         ck_tn_encrypt(s,x);
12384 #endif /* CK_ENCRYPTION */
12385 #endif /* IKSD */
12386
12387 #ifdef Plan9
12388     return(conwrite(s,x));
12389 #else
12390     return(write(1,s,x));
12391 #endif /* Plan9 */
12392 }
12393
12394 /*  C O N O L  --  Write a line to the console terminal  */
12395
12396 int
12397 conol(s) char *s; {
12398     int len;
12399     if (!s) s = "";                     /* Always do this! */
12400     len = strlen(s);
12401     if (len == 0)
12402       return(0);
12403
12404 #ifdef IKSD
12405     if (inserver && !local)
12406       return(ttol((CHAR *)s,len));
12407
12408 #ifdef CK_ENCRYPTION
12409     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
12410         if (nxpacket < len) {
12411             if (xpacket) {
12412                 free(xpacket);
12413                 xpacket = NULL;
12414                 nxpacket = 0;
12415             }
12416             len = len > 10240 ? len : 10240;
12417             xpacket = (char *)malloc(len);
12418             if (!xpacket) {
12419                 fprintf(stderr,"ttol malloc failure\n");
12420                 return(-1);
12421             } else
12422               nxpacket = len;
12423         }
12424         memcpy(xpacket,s,len);
12425         s = xpacket;
12426         ck_tn_encrypt(s,len);
12427     }
12428 #endif /* CK_ENCRYPTION */
12429 #endif /* IKSD */
12430
12431 #ifdef Plan9
12432     return(conwrite(s,len));
12433 #else
12434     return(write(1,s,len));
12435 #endif /* Plan9 */
12436 }
12437
12438 /*  C O N O L A  --  Write an array of lines to the console terminal */
12439
12440 int
12441 conola(s) char *s[]; {
12442     char * p;
12443     int i, x;
12444
12445
12446     if (!s) return(0);
12447     for (i = 0; ; i++) {
12448         p = s[i];
12449         if (!p) p = "";                 /* Let's not dump core shall we? */
12450         if (!*p)
12451           break;
12452 #ifdef IKSD
12453         if (inserver && !local)
12454           x = ttol((CHAR *)p,(int)strlen(p));
12455         else
12456 #endif /* IKSD */
12457           x = conol(p);
12458         if (x < 0)
12459           return(-1);
12460     }
12461     return(0);
12462 }
12463
12464 /*  C O N O L L  --  Output a string followed by CRLF  */
12465
12466 int
12467 conoll(s) char *s; {
12468     CHAR buf[3];
12469     buf[0] = '\r';
12470     buf[1] = '\n';
12471     buf[2] = '\0';
12472     if (!s) s = "";
12473
12474 #ifdef IKSD
12475     if (inserver && !local) {
12476         if (*s) ttol((CHAR *)s,(int)strlen(s));
12477         return(ttol(buf,2));
12478     }
12479 #endif /* IKSD */
12480
12481     if (*s) conol(s);
12482 #ifdef IKSD
12483 #ifdef CK_ENCRYPTION
12484     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12485       ck_tn_encrypt(buf,2);
12486 #endif /* CK_ENCRYPTION */
12487 #endif /* IKSD */
12488
12489 #ifdef Plan9
12490     return(conwrite(buf, 2));
12491 #else
12492     return(write(1,buf,2));
12493 #endif /* Plan9 */
12494 }
12495
12496 /*  C O N C H K  --  Return how many characters available at console  */
12497 /*
12498   We could also use select() here to cover a few more systems that are not
12499   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
12500 */
12501 int
12502 conchk() {
12503     static int contyp = 0;              /* +1 for isatty, -1 otherwise */
12504
12505     if (contyp == 0)                    /* This prevents unnecessary */
12506       contyp = (isatty(0) ? 1 : -1);    /* duplicated calls to isatty() */
12507     debug(F101,"conchk contyp","",contyp);
12508     if (backgrd || (contyp < 0))
12509       return(0);
12510
12511 #ifdef aegis
12512     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
12513
12514     /* read in more characters */
12515     conbufn = ios_$get(ios_$stdin,
12516               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
12517     if (st.all != status_$ok) conbufn = 0;
12518     conbufp = conbuf;
12519     return(conbufn);
12520 #else
12521 #ifdef IKSD
12522     if (inserver && !local)
12523       return(in_chk(1,ttyfd));
12524     else
12525 #endif /* IKSD */
12526       return(in_chk(0,0));
12527 #endif /* aegis */
12528 }
12529
12530 /*  C O N I N C  --  Get a character from the console  */
12531 /*
12532   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
12533   read.  Upon success, returns the character.  Upon failure, returns -1.
12534   A timed read that does not complete within the timeout period returns -2.
12535 */
12536 int
12537 coninc(timo) int timo; {
12538     int n = 0; CHAR ch;
12539     int xx;
12540
12541     if (conbufn > 0) {                  /* If something already buffered */
12542         --conbufn;
12543         return((unsigned)(*conbufp++ & 0xff));
12544     }
12545
12546     errno = 0;                          /* Clear this */
12547 #ifdef IKSD
12548     if (inserver && !local) {
12549         xx = ttinc(timo);
12550         if (xx < 0)
12551           return(ttinctimo ? -2 : -1);
12552         else
12553           return(xx);
12554     }
12555 #endif /* IKSD */
12556
12557 #ifdef aegis                            /* Apollo Aegis only... */
12558     debug(F101,"coninc timo","",timo);
12559     fflush(stdout);
12560     if (conchk() > 0) {
12561         --conbufn;
12562         return((unsigned)(*conbufp++ & 0xff));
12563     }
12564 #endif /* aegis */
12565
12566 #ifdef TTLEBUF
12567     if (
12568 #ifdef IKSD
12569         inserver &&
12570 #endif /* IKSD */
12571         !xlocal
12572         ) {
12573         if (ttpush >= 0) {
12574             debug(F111,"ttinc","ttpush",ttpush);
12575             ch = ttpush;
12576             ttpush = -1;
12577             return(ch);
12578         }
12579         if (le_data) {
12580             if (le_getchar(&ch) > 0) {
12581                 debug(F111,"ttinc LocalEchoInBuf","ch",ch);
12582                 return(ch);
12583             }
12584         }
12585     }
12586 #endif /* TTLEBUF */
12587
12588     if (timo <= 0) {                    /* Untimed, blocking read. */
12589         while (1) {                     /* Keep trying till we get one. */
12590             n = read(0, &ch, 1);        /* Read a character. */
12591             if (n == 0) continue;       /* Shouldn't happen. */
12592             if (n > 0) {                /* If read was successful, */
12593 #ifdef IKSD
12594 #ifdef CK_ENCRYPTION
12595                 debug(F100,"coninc decrypt 1","",0);
12596                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12597                   ck_tn_decrypt(&ch,1);
12598 #endif /* CK_ENCRYPTION */
12599 #endif /* IKSD */
12600                 return((unsigned)(ch & 0xff)); /* return the character. */
12601             }
12602
12603 /* Come here if read() returned an error. */
12604
12605             debug(F101, "coninc(0) errno","",errno); /* Log the error. */
12606 #ifndef OXOS
12607 #ifdef SVORPOSIX
12608 #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
12609 #ifndef EINTR
12610 #define EINTR 4
12611 #endif /* EINTR */
12612 #endif /* CIE */
12613 /*
12614   This routine is used for several different purposes.  In CONNECT mode, it is
12615   used to do an untimed, blocking read from the keyboard in the lower CONNECT
12616   fork.  During local-mode file transfer, it reads a character from the
12617   console to interrupt the file transfer (like A for a status report, X to
12618   cancel a file, etc).  Obviously, we don't want the reads in the latter case
12619   to be blocking, or the file transfer would stop until the user typed
12620   something.  Unfortunately, System V does not allow the console device input
12621   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
12622   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
12623   and trapped by esctrp(), and this routine pretends to have read the quit
12624   character from the keyboard normally.  But, kludge or no kludge, the read()
12625   issued by this command, under System V only, can fail if a signal -- ANY
12626   signal -- is caught while the read is pending.  This can occur not only when
12627   the user types the quit character, but also during telnet negotiations, when
12628   the lower CONNECT fork signals the upper one about an echoing mode change.
12629   When this happens, we have to post the read() again.  This is apparently not
12630   a problem in BSD-based UNIX versions.
12631 */
12632             if (errno == EINTR)         /* Read interrupted. */
12633               if (conesc)  {            /* If by SIGQUIT, */
12634                  conesc = 0;            /* the conesc variable is set, */
12635                  return(escchr);        /* so return the escape character. */
12636              } else continue;           /* By other signal, try again. */
12637 #else
12638 /*
12639   This might be dangerous, but let's do this on non-System V versions too,
12640   since at least one SunOS 4.1.2 user complains of immediate disconnections
12641   upon first making a TELNET connection.
12642 */
12643             if (errno == EINTR)         /* Read interrupted. */
12644               continue;
12645 #endif /* SVORPOSIX */
12646 #else /* OXOS */
12647             if (errno == EINTR)         /* Read interrupted. */
12648               continue;
12649 #endif /* OXOS */
12650             return(-1);                 /* Error */
12651         }
12652     }
12653 #ifdef DEBUG
12654     if (deblog && timo <= 0) {
12655         debug(F100,"coninc timeout logic error","",0);
12656         timo = 1;
12657     }
12658 #endif /* DEBUG */
12659
12660 /* Timed read... */
12661
12662     saval = signal(SIGALRM,timerh);     /* Set up timeout handler. */
12663     xx = alarm(timo);                   /* Set the alarm. */
12664     debug(F101,"coninc alarm set","",timo);
12665     if (
12666 #ifdef CK_POSIX_SIG
12667         sigsetjmp(sjbuf,1)
12668 #else
12669         setjmp(sjbuf)
12670 #endif /* CK_POSIX_SIG */
12671         )                               /* The read() timed out. */
12672       n = -2;                           /* Code for timeout. */
12673     else
12674       n = read(0, &ch, 1);
12675     ttimoff();                          /* Turn off timer */
12676     if (n > 0) {                        /* Got character OK. */
12677 #ifdef IKSD
12678 #ifdef CK_ENCRYPTION
12679         debug(F100,"coninc decrypt 2","",0);
12680         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12681           ck_tn_decrypt(&ch,1);
12682 #endif /* CK_ENCRYPTION */
12683 #endif /* IKSD */
12684         return((unsigned)(ch & 0xff));  /* Return it. */
12685     }
12686 /*
12687   read() returned an error.  Same deal as above, but without the loop.
12688 */
12689     debug(F101, "coninc(timo) n","",n);
12690     debug(F101, "coninc(timo) errno","",errno);
12691 #ifndef OXOS
12692 #ifdef SVORPOSIX
12693     if (n == -1 && errno == EINTR && conesc != 0) {
12694         conesc = 0;
12695         return(escchr);                 /* User entered escape character. */
12696     }
12697 #endif /* SVORPOSIX */
12698     if (n == 0 && errno > 0) {          /* It's an error */
12699         return(-1);
12700     }
12701 #endif /* ! OXOS */
12702     return(n);
12703 }
12704
12705 /*  C O N G K S  --  Console Get Keyboard Scancode  */
12706
12707 #ifndef congks
12708 /*
12709   This function needs to be filled in with the various system-dependent
12710   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
12711   keyboard scan code.  Unfortunately there aren't any.
12712 */
12713 int
12714 congks(timo) int timo; {
12715
12716 #ifdef IKSD
12717     if (inserver && !local)
12718       return(ttinc(timo));
12719 #endif /* IKSD */
12720
12721     return(coninc(timo));
12722 }
12723 #endif /* congks */
12724
12725 #ifdef ATT7300
12726
12727 /*  A T T D I A L  --  Dial up the remote system using internal modem
12728  * Purpose: to open and dial a number on the internal modem available on the
12729  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
12730  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
12731  * Uses information in <sys/phone.h> and our status int attmodem.
12732  */
12733 attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
12734     char *telnum;
12735
12736     attmodem &= ~ISMODEM;                       /* modem not in use yet */
12737                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
12738                     /* We turn this flag off once the dial is complete */
12739     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
12740
12741     /* Condition line, check availability & DATA mode, turn on speaker */
12742     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
12743         printf("cannot access phone\n");
12744         ttclos(0);
12745         return (-2);
12746     }
12747     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
12748
12749     if (dialer.c_lineparam & VOICE) {   /* phone must be in DATA mode */
12750         printf(" Should not dial with modem in VOICE mode.\n");
12751         printf(" Exit Kermit, switch to DATA and retry call.\n");
12752         ttclos(0);
12753         return (-2);
12754     }
12755 #ifdef ATTTONED                         /* Old way, tone dialing only. */
12756     dialer.c_lineparam = DATA | DTMF;   /* Dial with tones, */
12757     dialer.c_lineparam &= ~PULSE;       /* not with pulses. */
12758 #else
12759     /* Leave current pulse/tone state alone. */
12760     /* But what about DATA?  Add it back if you have trouble. */
12761     /* sys/phone says you get DATA automatically by opening device RDWR */
12762 #endif
12763     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
12764 #ifdef COMMENT
12765     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
12766 #else
12767     /* sys/phone says RINGON used only for incoming voice calls */
12768     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
12769     dialer.c_feedback |= SPEAKERON|NORMSPK;
12770 #endif
12771     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
12772     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
12773         printf("Cannot set modem characteristics\n");
12774         ttclos(0);
12775         return (-2);
12776     }
12777     ioctl(ttyfd,PIOCRECONN,0);          /* Turns on speaker for pulse */
12778
12779 #ifdef COMMENT
12780     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
12781 line_status:%o feedback:%o\n",
12782     dialer.c_lineparam, dialer.c_waitdialtone,
12783     dialer.c_linestatus, dialer.c_feedback);
12784 #endif
12785
12786     attmodem |= ISMODEM;                        /* modem is now in-use */
12787     sleep(1);
12788     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
12789 #ifdef ATTTONED
12790       /* Tone dialing only */
12791       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
12792           perror("Error in dialing");
12793           ttclos(0);
12794           return(-2);
12795       }
12796 #else /* Allow Pulse or Tone dialing */
12797     switch (*telnum) {
12798       case 't': case 'T': case '%':     /* Tone dialing requested */
12799         dialer.c_lineparam |= DTMF;
12800         dialer.c_lineparam &= ~PULSE;
12801         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
12802             printf("Cannot set modem to tone dialing\n");
12803             ttclos(0);
12804             return(-2);
12805         }
12806         break;
12807       case 'd': case 'D': case 'p': case 'P': case '^':
12808         dialer.c_lineparam |= PULSE;
12809         dialer.c_lineparam &= ~DTMF;
12810         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
12811             printf("Cannot set modem to pulse dialing\n");
12812             ttclos(0);
12813             return(-2);
12814         }
12815         break;
12816       default:
12817         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
12818             perror("Dialing error");
12819             ttclos(0);
12820             return(-2);
12821         }
12822         break;
12823     }
12824 #endif
12825
12826     ioctl(ttyfd,PIOCDIAL,"@");          /* terminator for data call */
12827     do {                                /* wait for modems to Connect */
12828         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
12829             perror("Cannot get modems to connect");
12830             ttclos(0);
12831             return(-2);
12832         }
12833     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
12834     /* Turn off O_NDELAY flag now. */
12835     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
12836     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
12837     return(0);                          /* return success */
12838 }
12839
12840 /*
12841   Offgetty, ongetty functions. These function get the 'getty(1m)' off
12842   and restore it to the indicated line.  Shell's return codes are:
12843     0: Can't do it.  Probably a user logged on.
12844     1: No need.  No getty on that line.
12845     2: Done, you should restore the getty when you're done.
12846   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
12847   Thanks to Kevin O'Gorman, Anarm Software Systems.
12848
12849    getoff.sh looks like:   geton.sh looks like:
12850      setgetty $1 0           setgetty $1 1
12851      err=$?                  exit $?
12852      sleep 2
12853      exit $err
12854 */
12855
12856 /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
12857  * and get status so it can be restarted after the line is hung up.
12858  */
12859 int
12860 offgetty(ttname) char *ttname; {
12861     char temp[30];
12862     while (*ttname != '\0') ttname++;       /* seek terminator of path */
12863     ttname -= 3;                            /* get last 3 chars of name */
12864     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
12865     return(zsyscmd(temp));
12866 }
12867
12868 /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
12869
12870 int
12871 ongetty(ttname) char *ttname; {
12872     char temp[30];
12873     while (*ttname != '\0') ttname++;       /* comms tty path name */
12874     ttname -= 3;
12875     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
12876     return(zsyscmd(temp));
12877 }
12878 #endif /* ATT7300 */
12879
12880 /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
12881  *
12882  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
12883  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
12884  *  2 = Auto: For "modem direct": The same as "Off".
12885  *            For real modem types: Heed carrier during connect, but ignore
12886  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
12887  *
12888  * As you can see, this setting does not affect dialing, which always ignores
12889  * carrier (unless there is some special exception for some modem type).  It
12890  * does affect ttopen() if it is set before ttopen() is used.  This setting
12891  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
12892  * (or should be) always called before any communications is tried, which
12893  * means that, practically speaking, the effect is immediate.
12894  *
12895  * Of course, nothing of this applies to remote mode (xlocal = 0).
12896  *
12897  * Someone has yet to uncover how to manipulate the carrier in the BSD
12898  * environment (or any non-termio using environment).  Until that time, this
12899  * will simply be a no-op for BSD.
12900  *
12901  * Note that in previous versions, the carrier was most often left unchanged
12902  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
12903  * has changed.  Now it is controlled by ttcarr in conjunction with these
12904  * modes.
12905  */
12906 int
12907 ttscarr(carrier) int carrier; {
12908     ttcarr = carrier;
12909     debug(F101, "ttscarr","",ttcarr);
12910     return(ttcarr);
12911 }
12912
12913 /* C A R R C T L  --  Set tty modes for carrier treatment.
12914  *
12915  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
12916  * (actually, there are no bits in sgttyb for that), or performs any other
12917  * operations needed to control this on the current system.  The function does
12918  * not do the actual TCSETA or stty, since often we want to set other bits too
12919  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
12920  *
12921  * We don't know how to do anything like carrier control on non-ATTSV systems,
12922  * except, apparently, ultrix.  See above.  It is also known that this doesn't
12923  * have much effect on a Xenix system.  For Xenix, one should switch back and
12924  * forth between the upper and lower case device files.  Maybe later.
12925  * Presently, Xenix will stick to the mode it was opened with.
12926  *
12927  * carrier: 0 = ignore carrier, 1 = require carrier.
12928  * The current state is saved in curcarr, and checked to save labour.
12929  */
12930 #ifdef SVORPOSIX
12931 int
12932 #ifdef BSD44ORPOSIX
12933 carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
12934 #else /* ATTSV */
12935 carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
12936 #endif /* BSD44ORPOSIX */
12937 /* carrctl */ {
12938     debug(F101, "carrctl","",carrier);
12939     if (carrier)
12940       ttpar->c_cflag &= ~CLOCAL;
12941     else
12942       ttpar->c_cflag |= CLOCAL;
12943     return(0);
12944 }
12945 #else /* Berkeley, V7, et al... */
12946 int
12947 carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
12948     debug(F101, "carrctl","",carrier);
12949     if (carrier == curcarr)
12950       return(0);
12951     curcarr = carrier;
12952 #ifdef ultrix
12953 #ifdef COMMENT
12954 /*
12955   Old code from somebody at DEC that tends to get stuck, time out, etc.
12956 */
12957     if (carrier) {
12958         ioctl(ttyfd, TIOCMODEM, &temp);
12959         ioctl(ttyfd, TIOCHPCL, 0);
12960     } else {
12961         /* (According to the manuals, TIOCNCAR should be preferred */
12962         /* over TIOCNMODEM...) */
12963         ioctl(ttyfd, TIOCNMODEM, &temp);
12964     }
12965 #else
12966 /*
12967   New code from Jamie Watson that, he says, eliminates the problems.
12968 */
12969     if (carrier) {
12970         ioctl(ttyfd, TIOCCAR);
12971         ioctl(ttyfd, TIOCHPCL);
12972     } else {
12973         ioctl(ttyfd, TIOCNCAR);
12974     }
12975 #endif /* COMMENT */
12976 #endif /* ultrix */
12977     return(0);
12978 }
12979 #endif /* SVORPOSIX */
12980
12981
12982 /*  T T G M D M  --  Get modem signals  */
12983 /*
12984  Looks for RS-232 modem signals, and returns those that are on in as its
12985  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
12986  Returns:
12987  -3 Not implemented
12988  -2 if the communication device does not have modem control (e.g. telnet)
12989  -1 on error.
12990  >= 0 on success, with a bit mask containing the modem signals that are on.
12991 */
12992
12993 /*
12994   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
12995   modem control, namely the TIOCMGET ioctl.
12996 */
12997
12998 #ifdef BSD43
12999 #define K_MDMCTL
13000 #endif /* BSD43 */
13001
13002 #ifdef SUNOS4
13003 #define K_MDMCTL
13004 #endif /* SUNOS4 */
13005
13006 /*
13007   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
13008   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
13009   must be defined in order to get the high serial speeds that are new to
13010   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
13011   ioctl() returns -1 with errno 22 (invalid function).  But third-party
13012   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
13013   driven by those drivers.
13014 */
13015 #ifdef SCO_OSR504
13016 #ifndef TIOCMGET
13017 #define TIOCMGET (('t'<<8)|29)
13018 #endif /* TIOCMGET */
13019 #endif /* SCO_OSR504 */
13020
13021 #ifdef CK_SCOV5
13022 /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
13023 #ifndef TIOCM_DTR
13024 #define TIOCM_DTR       0x0002          /* data terminal ready */
13025 #define TIOCM_RTS       0x0004          /* request to send */
13026 #define TIOCM_CTS       0x0020          /* clear to send */
13027 #define TIOCM_CAR       0x0040          /* carrier detect */
13028 #define TIOCM_RNG       0x0080          /* ring */
13029 #define TIOCM_DSR       0x0100          /* data set ready */
13030 #define TIOCM_CD        TIOCM_CAR
13031 #define TIOCM_RI        TIOCM_RNG
13032 #endif /* TIOCM_DTR */
13033 #endif /* CK_SCOV5 */
13034
13035 #ifdef QNX
13036 #define K_MDMCTL
13037 #else
13038 #ifdef TIOCMGET
13039 #define K_MDMCTL
13040 #endif /* TIOCMGET */
13041 #endif /* QNX */
13042 /*
13043   "A serial communication program that can't read modem signals
13044    is like a car without windows."
13045 */
13046 int
13047 ttgmdm() {
13048
13049 #ifdef QNX
13050 #include <sys/qioctl.h>
13051
13052     unsigned long y, mdmbits[2];
13053     int x, z = 0;
13054
13055     if (xlocal && ttyfd < 0)
13056       return(-1);
13057
13058 #ifdef NETCONN
13059     if (netconn) {                      /* Network connection */
13060 #ifdef TN_COMPORT
13061         if (istncomport()) {
13062             gotsigs = 1;
13063             return(tngmdm());
13064         } else
13065 #endif /* TN_COMPORT */
13066           return(-2);                   /* No modem signals */
13067     }
13068 #endif /* NETCONN */
13069
13070 #ifdef NETCMD
13071     if (ttpipe) return(-2);
13072 #endif /* NETCMD */
13073 #ifdef NETPTY
13074     if (ttpty) return(-2);
13075 #endif /* NETPTY */
13076
13077     mdmbits[0] = 0L;
13078     mdmbits[1] = 0L;
13079 /*
13080  * From <sys/qioctl.h>:
13081  *
13082  * SERIAL devices   (all Dev.ser versions)
13083  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
13084  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
13085  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
13086  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
13087  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
13088  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
13089  * 6 - reserved     14 : Break        22 = RI           30 - reserved
13090  * 7 - reserved     15 = 0            23 = CD           31 - reserved
13091  */
13092     errno = 0;
13093     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
13094     debug(F101,"ttgmdm qnx_ioctl","",x);
13095     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
13096     if (!x) {
13097         debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
13098         debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
13099         y = mdmbits[0];
13100         if (y & 0x000001L) z |= BM_DTR; /* Bit  0 */
13101         if (y & 0x000002L) z |= BM_RTS; /* Bit  1 */
13102         if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
13103         if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
13104         if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
13105         if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
13106         debug(F101,"ttgmdm qnx result","",z);
13107         debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
13108         gotsigs = 1;
13109         return(z);
13110     } else return(-1);
13111 #else /* QNX */
13112 #ifdef HPUX                             /* HPUX has its own way */
13113     int x, z;
13114
13115 #ifdef HPUX10                           /* Modem flag word */
13116     mflag y;                            /* mflag typedef'd in <sys/modem.h> */
13117 #else
13118 #ifdef HPUX9
13119     mflag y;
13120 #else
13121 #ifdef HPUX8
13122     mflag y;
13123 #else
13124     unsigned long y;                    /* Not sure about pre-8.0... */
13125 #endif /* HPUX8 */
13126 #endif /* HPUX9 */
13127 #endif /* HPUX10 */
13128
13129     if (xlocal && ttyfd < 0)
13130       return(-1);
13131
13132 #ifdef NETCONN
13133     if (netconn) {                      /* Network connection */
13134 #ifdef TN_COMPORT
13135         if (istncomport()) {
13136             gotsigs = 1;
13137             return(tngmdm());
13138         } else
13139 #endif /* TN_COMPORT */
13140           return(-2);                   /* No modem signals */
13141     }
13142 #endif /* NETCONN */
13143
13144 #ifdef NETCMD
13145     if (ttpipe) return(-2);
13146 #endif /* NETCMD */
13147 #ifdef NETPTY
13148     if (ttpty) return(-2);
13149 #endif /* NETPTY */
13150
13151     if (xlocal)                         /* Get modem signals */
13152       x = ioctl(ttyfd,MCGETA,&y);
13153     else
13154       x = ioctl(0,MCGETA,&y);
13155     if (x < 0) return(-1);
13156     debug(F101,"ttgmdm","",y);
13157
13158     z = 0;                              /* Initialize return value */
13159
13160 /* Now set bits for each modem signal that is reported to be on. */
13161
13162 #ifdef MCTS
13163     /* Clear To Send */
13164     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
13165     if (y & MCTS) z |= BM_CTS;
13166 #endif
13167 #ifdef MDSR
13168     /* Data Set Ready */
13169     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
13170     if (y & MDSR) z |= BM_DSR;
13171 #endif
13172 #ifdef MDCD
13173     /* Carrier */
13174     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
13175     if (y & MDCD) z |= BM_DCD;
13176 #endif
13177 #ifdef MRI
13178     /* Ring Indicate */
13179     debug(F101,"ttgmdm HPUX RI","",y & MRI);
13180     if (y & MRI) z |= BM_RNG;
13181 #endif
13182 #ifdef MDTR
13183     /* Data Terminal Ready */
13184     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
13185     if (y & MDTR) z |= BM_DTR;
13186 #endif
13187 #ifdef MRTS
13188     /* Request To Send */
13189     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
13190     if (y & MRTS) z |= BM_RTS;
13191 #endif
13192     gotsigs = 1;
13193     return(z);
13194
13195 #else /* ! HPUX */
13196
13197 #ifdef K_MDMCTL
13198 /*
13199   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
13200   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
13201   are needed.
13202 */
13203 #ifndef TIOCMGET
13204 #include <sys/ttycom.h>
13205 #endif /* TIOCMGET */
13206
13207     int x, y, z;
13208
13209     debug(F100,"ttgmdm K_MDMCTL defined","",0);
13210
13211 #ifdef NETCONN
13212     if (netconn) {                      /* Network connection */
13213 #ifdef TN_COMPORT
13214         if (istncomport()) {
13215             gotsigs = 1;
13216             return(tngmdm());
13217         } else
13218 #endif /* TN_COMPORT */
13219           return(-2);                   /* No modem signals */
13220     }
13221 #endif /* NETCONN */
13222
13223 #ifdef NETCMD
13224     if (ttpipe) return(-2);
13225 #endif /* NETCMD */
13226 #ifdef NETPTY
13227     if (ttpty) return(-2);
13228 #endif /* NETPTY */
13229
13230     if (xlocal && ttyfd < 0)
13231       return(-1);
13232
13233     if (xlocal)
13234       x = ioctl(ttyfd,TIOCMGET,&y);     /* Get modem signals. */
13235     else
13236       x = ioctl(0,TIOCMGET,&y);
13237     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
13238     if (x < 0) {
13239         debug(F101,"ttgmdm errno","",errno);
13240         return(-1);
13241     }
13242     debug(F101,"ttgmdm bits","",y);
13243
13244     z = 0;                              /* Initialize return value. */
13245 #ifdef TIOCM_CTS
13246     /* Clear To Send */
13247     if (y & TIOCM_CTS) z |= BM_CTS;
13248     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); 
13249 #else
13250     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
13251 #endif
13252 #ifdef TIOCM_DSR
13253     /* Data Set Ready */
13254     if (y & TIOCM_DSR) z |= BM_DSR;
13255     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); 
13256 #else
13257     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
13258 #endif
13259 #ifdef TIOCM_CAR
13260     /* Carrier */
13261     if (y & TIOCM_CAR) z |= BM_DCD;
13262     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); 
13263 #else
13264     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
13265 #endif
13266 #ifdef TIOCM_RNG
13267     /* Ring Indicate */
13268     if (y & TIOCM_RNG) z |= BM_RNG;
13269     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); 
13270 #else
13271     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
13272 #endif
13273 #ifdef TIOCM_DTR
13274     /* Data Terminal Ready */
13275     if (y & TIOCM_DTR) z |= BM_DTR;
13276     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); 
13277 #else
13278     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
13279 #endif
13280 #ifdef TIOCM_RTS
13281     /* Request To Send */
13282     if (y & TIOCM_RTS) z |= BM_RTS;
13283     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); 
13284 #else
13285     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
13286 #endif
13287     gotsigs = 1;
13288     return(z);
13289
13290 #else /* !K_MDMCTL catch-All */
13291
13292     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
13293 #ifdef TIOCMGET
13294     debug(F100,"ttgmdm TIOCMGET defined","",0);
13295 #else
13296     debug(F100,"ttgmdm TIOCMGET not defined","",0);
13297 #endif /* TIOCMGET */
13298 #ifdef _SVID3
13299     debug(F100,"ttgmdm _SVID3 defined","",0);
13300 #else
13301     debug(F100,"ttgmdm _SVID3 not defined","",0);
13302 #endif /* _SVID3 */
13303
13304 #ifdef NETCONN
13305     if (netconn) {                      /* Network connection */
13306 #ifdef TN_COMPORT
13307         if (istncomport()) {
13308             gotsigs = 1;
13309             return(tngmdm());
13310         } else
13311 #endif /* TN_COMPORT */
13312           return(-2);                   /* No modem signals */
13313     }
13314 #endif /* NETCONN */
13315
13316 #ifdef NETCMD
13317     if (ttpipe) return(-2);
13318 #endif /* NETCMD */
13319 #ifdef NETPTY
13320     if (ttpty) return(-2);
13321 #endif /* NETPTY */
13322
13323     return(-3);                         /* Sorry, I don't know how... */
13324
13325 #endif /* K_MDMCTL */
13326 #endif /* HPUX */
13327 #endif /* QNX */
13328 }
13329
13330 /*  P S U S P E N D  --  Put this process in the background.  */
13331
13332 /*
13333   Call with flag nonzero if suspending is allowed, zero if not allowed.
13334   Returns 0 on apparent success, -1 on failure (flag was zero, or
13335   kill() returned an error code.
13336 */
13337 int
13338 psuspend(flag) int flag; {
13339
13340 #ifdef RTU
13341     extern int rtu_bug;
13342 #endif /* RTU */
13343
13344     if (flag == 0) return(-1);
13345
13346 #ifdef NOJC
13347     return(-1);
13348 #else
13349 #ifdef SIGTSTP
13350 /*
13351   The big question here is whether job control is *really* supported.
13352   There's no way Kermit can know for sure.  The fact that SIGTSTP is
13353   defined does not guarantee the Unix kernel supports it, and the fact
13354   that the Unix kernel supports it doesn't guarantee that the user's
13355   shell (or other process that invoked Kermit) supports it.
13356 */
13357 #ifdef RTU
13358     rtu_bug = 1;
13359 #endif /* RTU */
13360     if (kill(0,SIGSTOP) < 0
13361 #ifdef MIPS
13362 /* Let's try this for MIPS too. */
13363         && kill(getpid(),SIGSTOP) < 0
13364 #endif /* MIPS */
13365         ) {                             /* If job control, suspend the job */
13366         perror("suspend");
13367         debug(F101,"psuspend error","",errno);
13368         return(-1);
13369     }
13370     debug(F100,"psuspend ok","",0);
13371     return(0);
13372 #else
13373     return(-1);
13374 #endif /* SIGTSTP */
13375 #endif /* NOJC */
13376 }
13377
13378 /*
13379   setuid package, by Kristoffer Eriksson, with contributions from Dean
13380   Long and fdc.
13381 */
13382
13383 /* The following is for SCO when CK_ANSILIBS is defined... */
13384 #ifdef M_UNIX
13385 #ifdef CK_ANSILIBS
13386 #ifndef NOGETID_PROTOS
13387 #define NOGETID_PROTOS
13388 #endif /* NOGETID_PROTOS */
13389 #endif /* CK_ANSILIBS */
13390 #endif /* M_UNIX */
13391
13392 #ifndef _POSIX_SOURCE
13393 #ifndef SUNOS4
13394 #ifndef NEXT
13395 #ifndef PS2AIX10
13396 #ifndef sequent
13397 #ifndef HPUX9
13398 #ifndef COHERENT
13399 #ifndef NOGETID_PROTOS
13400 extern UID_T getuid(), geteuid(), getreuid();
13401 extern GID_T getgid(), getegid(), getregid();
13402 #endif /* NOGETID_PROTOS */
13403 #else
13404 extern UID_T getreuid();
13405 extern GID_T getregid();
13406 #endif /* COHERENT */
13407 #endif /* HPUX9 */
13408 #endif /* sequent */
13409 #endif /* PS2AIX10 */
13410 #endif /* NEXT */
13411 #endif /* SUNOS4 */
13412 #endif /* _POSIX_SOURCE */
13413
13414 /*
13415 Subject: Set-user-id
13416 To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
13417 Date: Sat, 21 Apr 90 4:48:25 MES
13418 From: Kristoffer Eriksson <ske@pkmab.se>
13419
13420 This is a set of functions to be used in programs that may be run set-user-id
13421 and/or set-group-id. They handle both the case where the program is not run
13422 with such privileges (nothing special happens then), and the case where one
13423 or both of these set-id modes are used.  The program is made to run with the
13424 user's real user and group ids most of the time, except for when more
13425 privileges are needed.  Don't set-user-id to "root".
13426
13427 This works on System V and POSIX.  In BSD, it depends on the
13428 "saved-set-user-id" feature.
13429 */
13430
13431 #define UID_ROOT 0                      /* Root user and group ids */
13432 #define GID_ROOT 0
13433
13434 /*
13435   The following code defines the symbol SETEUID for UNIX systems based
13436   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
13437   seteuid() and setegid() instead of setuid() and setgid(), which still
13438   don't allow arbitrary switching.  It also avoids setreuid() and
13439   setregid(), which are included in BSD4.4 for compatibility only, are
13440   insecure, and print warnings to stderr under at least one system (NetBSD
13441   1.0).  Note that POSIX systems should still use setuid() and setgid();
13442   the seteuid() and setegid() functions are BSD4.4 extensions to the
13443   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
13444 */
13445 #ifdef BSD44
13446 #define SETEUID
13447 #endif /* BSD44 */
13448
13449 /*
13450   The following construction automatically defines the symbol SETREUID for
13451   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
13452   defined, then this program will use getreuid() and getregid() calls in
13453   preference to getuid() and getgid(), which in Berkeley-based Unixes do
13454   not allow arbitrary switching back and forth of real & effective uid.
13455   This construction also allows -DSETREUID to be put on the cc command line
13456   for any system that has and wants to use setre[ug]id().  It also prevents
13457   automatic definition of SETREUID if -DNOSETREU is included on the cc
13458   command line (or otherwise defined).
13459 */
13460 #ifdef FT18                             /* None of this for Fortune. */
13461 #define NOSETREU
13462 #endif /* FT18 */
13463
13464 #ifdef ANYBSD
13465 #ifndef BSD29
13466 #ifndef BSD41
13467 #ifndef SETREUID
13468 #ifndef NOSETREU
13469 #ifndef SETEUID
13470 #define SETREUID
13471 #endif /* SETEUID */
13472 #endif /* NOSETREU */
13473 #endif /* SETREUID */
13474 #endif /* !BSD41 */
13475 #endif /* !BSD29 */
13476 #endif /* ANYBSD */
13477
13478 /* Variables for user and group IDs. */
13479
13480 static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
13481 static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
13482
13483
13484 /* P R I V _ I N I  --  Initialize privileges package  */
13485
13486 /* Called as early as possible in a set-uid or set-gid program to store the
13487  * set-to uid and/or gid and step down to the users real uid and gid. The
13488  * stored id's can be temporarily restored (allowed in System V) during
13489  * operations that require the privilege.  Most of the time, the program
13490  * should execute in unpriviliged state, to not impose any security threat.
13491  *
13492  * Note: Don't forget that access() always uses the real id:s to determine
13493  * file access, even with privileges restored.
13494  *
13495  * Returns an error mask, with error values or:ed together:
13496  *   1 if setuid() fails,
13497  *   2 if setgid() fails, and
13498  *   4 if the program is set-user-id to "root", which can't be handled.
13499  *
13500  * Only the return value 0 indicates real success. In case of failure,
13501  * those privileges that could be reduced have been, at least, but the
13502  * program should be aborted none-the-less.
13503  *
13504  * Also note that these functions do not expect the uid or gid to change
13505  * without their knowing. It may work if it is only done temporarily, but
13506  * you're on your own.
13507  */
13508 int
13509 priv_ini() {
13510     int err = 0;
13511
13512 #ifndef HAVE_BAUDBOY
13513
13514     /* Save real ID:s. */
13515     realuid = getuid();
13516     realgid = getgid();
13517
13518     /* Save current effective ID:s, those set to at program exec. */
13519     privuid = geteuid();
13520     privgid = getegid();
13521
13522     /* If running set-uid, go down to real uid, otherwise remember that
13523      * no privileged uid is available.
13524      *
13525      * Exceptions:
13526      *
13527      * 1) If the real uid is already "root" and the set-uid uid (the
13528      * initial effective uid) is not "root", then we would have trouble
13529      * if we went "down" to "root" here, and then temporarily back to the
13530      * set-uid uid (not "root") and then again tried to become "root". I
13531      * think the "saved set-uid" is lost when changing uid from effective
13532      * uid "root", which changes all uid, not only the effective uid. But
13533      * in this situation, we can simply go to "root" and stay there all
13534      * the time. That should give sufficient privilege (understatement!),
13535      * and give the right uids for subprocesses.
13536      *
13537      * 2) If the set-uid (the initial effective uid) is "root", and we
13538      * change uid to the real uid, we can't change it back to "root" when
13539      * we need the privilege, for the same reason as in 1). Thus, we can't
13540      * handle programs that are set-user-id to "root" at all. The program
13541      * should be stopped.  Use some other uid.  "root" is probably too
13542      * privileged for such things, anyway. (The uid is reverted to the
13543      * real uid until termination.)
13544      *
13545      * These two exceptions have the effect that the "root" uid will never
13546      * be one of the two uids that are being switched between, which also
13547      * means we don't have to check for such cases in the switching
13548      * functions.
13549      *
13550      * Note that exception 1) is handled by these routines (by constantly
13551      * running with uid "root", while exception 2) is a serious error, and
13552      * is not provided for at all in the switching functions.
13553      */
13554     if (realuid == privuid)
13555         privuid = (UID_T) -1;           /* Not running set-user-id. */
13556
13557     /* If running set-gid, go down to real gid, otherwise remember that
13558      * no privileged gid is available.
13559      *
13560      * There are no exception like there is for the user id, since there
13561      * is no group id that is privileged in the manner of uid "root".
13562      * There could be equivalent problems for group changing if the
13563      * program sometimes ran with uid "root" and sometimes not, but
13564      * that is already avoided as explained above.
13565      *
13566      * Thus we can expect always to be able to switch to the "saved set-
13567      * gid" when we want, and back to the real gid again. You may also
13568      * draw the conclusion that set-gid provides for fewer hassles than
13569      * set-uid.
13570      */
13571
13572 #ifdef SUIDDEBUG
13573     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
13574     fprintf(stderr,"realuid=%d\n",realuid);
13575     fprintf(stderr,"privuid=%d\n",privuid);
13576 #endif /* SUIDDEBUG */
13577
13578     if (realgid == privgid)             /* If not running set-user-id, */
13579       privgid = (GID_T) -1;             /*  remember it this way. */
13580
13581     err = priv_off();                   /* Turn off setuid privilege. */
13582
13583     if (privuid == UID_ROOT)            /* If setuid to root, */
13584       err |= 4;                         /* return this error. */
13585
13586     if (realuid == UID_ROOT) {          /* If real id is root, */
13587         privuid = (UID_T) -1;           /* stay root at all times. */
13588 #ifdef ATT7300
13589         /* If Kermit installed SUID uucp and user is running as root */
13590         err &= ~1;                      /* System V R0 does not save UID */
13591 #endif /* ATT7300 */
13592     }
13593 #endif /* HAVE_BAUDBOY */
13594     return(err);
13595 }
13596
13597
13598 /* Macros for hiding the differences in UID/GID setting between various Unix
13599  * systems. These macros should always be called with both the privileged ID
13600  * and the non-privileged ID. The one in the second argument, will become the
13601  * effective ID. The one in the first argument will be retained for later
13602  * retrieval.
13603  */
13604 #ifdef SETREUID
13605 #ifdef SAVEDUID
13606 /* On BSD systems with the saved-UID feature, we just juggle the effective
13607  * UID back and forth, and leave the real UID at its true value.  The kernel
13608  * allows switching to both the current real UID, the effective UID, and the
13609  * UID which the program is set-UID to.  The saved set-UID always holds the
13610  * privileged UID for us, and the real UID will always be the non-privileged,
13611  * and we can freely choose one of them for the effective UID at any time.
13612  */
13613 #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
13614 #define switchgid(hidden,active) setregid( (GID_T) -1, active)
13615
13616 #else   /* SETREUID,!SAVEDUID */
13617
13618 /* On systems with setreXid() but without the saved-UID feature, notably
13619  * BSD 4.2, we swap the real and effective UIDs each time.  It's
13620  * the effective UID that we are interested in, but we have to retain the
13621  * unused UID somewhere to enable us to restore it later, and we do this
13622  * in the real UID.  The kernel only allows switching to either the current
13623  * real or the effective UID, unless you're "root".
13624  */
13625 #define switchuid(hidden,active)        setreuid(hidden,active)
13626 #define switchgid(hidden,active)        setregid(hidden,active)
13627 #endif
13628
13629 #else /* !SETREUID, !SAVEDUID */
13630
13631 #ifdef SETEUID
13632 /*
13633   BSD 4.4 works similarly to System V and POSIX (see below), but uses
13634   seteXid() instead of setXid() to change effective IDs.  In addition, the
13635   seteXid() functions work the same for "root" as for other users.
13636 */
13637 #define switchuid(hidden,active)        seteuid(active)
13638 #define switchgid(hidden,active)        setegid(active)
13639
13640 #else /* !SETEUID */
13641
13642 /* On System V and POSIX, the only thing we can change is the effective UID
13643  * (unless the current effective UID is "root", but initsuid() avoids that for
13644  * us).  The kernel allows switching to the current real UID or to the saved
13645  * set-UID.  These are always set to the non-privileged UID and the privileged
13646  * UID, respectively, and we only change the effective UID.  This breaks if
13647  * the current effective UID is "root", though, because for "root" setuid/gid
13648  * becomes more powerful, which is why initsuid() treats "root" specially.
13649  * Note: That special treatment maybe could be ignored for BSD?  Note: For
13650  * systems that don't fit any of these four cases, we simply can't support
13651  * set-UID.
13652  */
13653 #define switchuid(hidden,active)        setuid(active)
13654 #define switchgid(hidden,active)        setgid(active)
13655
13656 #endif /* SETEUID */
13657 #endif /* SETREUID */
13658
13659
13660 /* P R I V _ O N  --  Turn on the setuid and/or setgid */
13661
13662 /* Go to the privileged uid (gid) that the program is set-user-id
13663  * (set-group-id) to, unless the program is running unprivileged.
13664  * If setuid() fails, return value will be 1. If getuid() fails it
13665  * will be 2.  Return immediately after first failure, and the function
13666  * tries to restore any partial work done.  Returns 0 on success.
13667  * Group id is changed first, since it is less serious than user id.
13668  */
13669 int
13670 priv_on() {
13671 #ifndef HAVE_BAUDBOY
13672     if (privgid != (GID_T) -1)
13673       if (switchgid(realgid,privgid))
13674         return(2);
13675
13676     if (privuid != (UID_T) -1)
13677       if (switchuid(realuid,privuid)) {
13678           if (privgid != (GID_T) -1)
13679             switchgid(privgid,realgid);
13680           return(1);
13681       }
13682 #endif /* HAVE_BAUDBOY */
13683     return(0);
13684 }
13685
13686 /* P R I V _ O F F  --  Turn on the real uid and gid */
13687
13688 /* Return to the unprivileged uid (gid) after an temporary visit to
13689  * privileged status, unless the program is running without set-user-id
13690  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
13691  * in setgid() or:ed together. The functions tries to return both uid
13692  * and gid to unprivileged state, regardless of errors. Returns 0 on
13693  * success.
13694  */
13695 int
13696 priv_off() {
13697     int err = 0;
13698 #ifndef HAVE_BAUDBOY
13699     if (privuid != (UID_T) -1)
13700        if (switchuid(privuid,realuid))
13701           err |= 1;
13702
13703     if (privgid != (GID_T) -1)
13704        if (switchgid(privgid,realgid))
13705         err |= 2;
13706 #endif /* HAVE_BAUDBOY */
13707     return(err);
13708 }
13709
13710 /* Turn off privilege permanently.  No going back.  This is necessary before
13711  * a fork() on BSD43 machines that don't save the setUID or setGID, because
13712  * we swap the real and effective ids, and we don't want to let the forked
13713  * process swap them again and get the privilege back. It will work on other
13714  * machines too, such that you can rely on its effect always being the same,
13715  * for instance, even when you're in priv_on() state when this is called.
13716  * (Well, that part about "permanent" is on System V only true if you follow
13717  * this with a call to exec(), but that's what we want it for anyway.)
13718  * Added by Dean Long -- dlong@midgard.ucsc.edu
13719  */
13720 int
13721 priv_can() {
13722 #ifndef HAVE_BAUDBOY
13723 #ifdef SETREUID
13724     int err = 0;
13725     if (privuid != (UID_T) -1)
13726        if (setreuid(realuid,realuid))
13727           err |= 1;
13728
13729     if (privgid != (GID_T) -1)
13730         if (setregid(realgid,realgid))
13731           err |= 2;
13732
13733     return(err);
13734
13735 #else
13736 #ifdef SETEUID
13737     int err = 0;
13738     if (privuid != (UID_T) -1)
13739         if (setuid(realuid)) {
13740             debug(F101,"setuid failed","",errno);
13741             err |= 1;
13742             debug(F101,"ruid","",getuid());
13743             debug(F101,"euid","",geteuid());
13744         }
13745     debug(F101,"setuid","",realuid);
13746     if (privgid != (GID_T) -1)
13747         if (setgid(realgid)) {
13748             debug(F101,"setgid failed","",errno);
13749             err |= 2;
13750             debug(F101,"rgid","",getgid());
13751             debug(F101,"egid","",getegid());
13752         }
13753     debug(F101,"setgid","",realgid);
13754     return(err);
13755 #else
13756     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
13757     return(priv_off());
13758 #endif /* SETEUID */
13759 #endif /* SETREUID */
13760 #else
13761     return(0);
13762 #endif /* HAVE_BAUDBOY */
13763 }
13764
13765 /* P R I V _ O P N  --  For opening protected files or devices. */
13766
13767 int
13768 priv_opn(name, modes) char *name; int modes; {
13769     int x;
13770     priv_on();                          /* Turn privileges on */
13771     debug(F111,"priv_opn",name,modes);
13772     errno = 0;
13773     x = open(name, modes);              /* Try to open the device */
13774     debug(F101,"priv_opn result","",x);
13775     debug(F101,"priv_opn errno","",errno);
13776     priv_off();                         /* Turn privileges off */
13777     return(x);                          /* Return open's return code */
13778 }
13779
13780 /*  P R I V _ C H K  --  Check privileges.  */
13781
13782 /*  Try to turn them off.  If turning them off did not succeed, cancel them */
13783
13784 int
13785 priv_chk() {
13786     int x, y = 0;
13787     x = priv_off();                     /* Turn off privs. */
13788     if (x != 0 || getuid() == privuid || geteuid() == privuid)
13789       y = priv_can();
13790     if (x != 0 || getgid() == privgid || getegid() == privgid)
13791       y = y | priv_can();
13792     return(y);
13793 }
13794
13795 UID_T
13796 real_uid() {
13797     return(realuid);
13798 }
13799
13800 VOID
13801 ttimoff() {                             /* Turn off any timer interrupts */
13802     /* int xx; */
13803 /*
13804   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
13805   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
13806   cure (mask, really) a deeper problem with stray alarms that occurs on some
13807   systems, possibly having to do with sleep(), that caused core dumps.  It
13808   should be OK to do this, because no code in this module uses nested alarms.
13809   (But we still have to watch out for SCRIPT and DIAL...)
13810 */
13811     /* xx = */ alarm(0);
13812     /* debug(F101,"ttimoff alarm","",xx); */
13813     if (saval) {                        /* Restore any previous */
13814         signal(SIGALRM,saval);          /* alarm handler. */
13815         /* debug(F101,"ttimoff alarm restoring saval","",saval); */
13816         saval = NULL;
13817     } else {
13818         signal(SIGALRM,SIG_IGN);        /* Used to be SIG_DFL */
13819         /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
13820     }
13821 }
13822
13823 /* T T R U N C M D  --  Redirect an external command over the connection. */
13824
13825 #ifdef CK_REDIR
13826 int
13827 ttruncmd(s) char *s; {
13828     PID_T pid;                          /* pid of lower fork */
13829     int wstat;                          /* for wait() */
13830     int x;
13831     int statusp;
13832
13833     if (ttyfd == -1) {
13834         printf("?Sorry, device is not open\n");
13835         return(0);
13836     }
13837     if (nopush) {
13838         debug(F100,"ttruncmd fail: nopush","",0);
13839         return(0);
13840     }
13841     conres();                           /* Make console normal  */
13842     pexitstat = -4;
13843     if ((pid = fork()) == 0) {          /* Make a child fork */
13844         if (priv_can())                 /* Child: turn off privs. */
13845           exit(1);
13846         dup2(ttyfd, 0);                 /* Give stdin/out to the line */
13847         dup2(ttyfd, 1);
13848         x = system(s);
13849         debug(F101,"ttruncmd system",s,x);
13850         _exit(x ? BAD_EXIT : 0);
13851     } else {
13852         SIGTYP (*istat)(), (*qstat)();
13853         if (pid == (PID_T) -1)          /* fork() failed? */
13854           return(0);
13855         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
13856         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
13857
13858 #ifdef COMMENT
13859         while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
13860 #else  /* Not COMMENT */
13861         while (1) {
13862             wstat = wait(&statusp);
13863             debug(F101,"ttruncmd wait","",wstat);
13864             if (wstat == pid || wstat == -1)
13865               break;
13866         }
13867 #endif /* COMMENT */
13868
13869         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
13870         debug(F101,"ttruncmd wait statusp","",statusp);
13871         debug(F101,"ttruncmd wait pexitstat","",pexitstat);
13872         signal(SIGINT,istat);           /* Restore interrupts */
13873         signal(SIGQUIT,qstat);
13874     }
13875     concb((char)escchr);                /* Restore console to CBREAK mode */
13876     return(statusp == 0 ? 1 : 0);
13877 }
13878 #endif /* CK_REDIR */
13879
13880 struct tm *
13881 #ifdef CK_ANSIC
13882 cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
13883 #else
13884 cmdate2tm(date,gmt) char * date; int gmt;
13885 #endif
13886 {
13887     /* date as "yyyymmdd hh:mm:ss" */
13888     static struct tm _tm;
13889     time_t now;
13890
13891     if (strlen(date) != 17 ||
13892         date[8] != ' ' ||
13893         date[11] != ':' ||
13894         date[14] != ':')
13895       return(NULL);
13896
13897     time(&now);
13898     if (gmt)
13899       _tm = *gmtime(&now);
13900     else
13901       _tm = *localtime(&now);
13902     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
13903                   (date[2]-'0')*10   + (date[3]-'0')-1900;
13904     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
13905     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
13906     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
13907     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
13908     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
13909
13910     /* Should we set _tm.tm_isdst to -1 here? */
13911
13912     _tm.tm_wday = 0;
13913     _tm.tm_yday = 0;
13914
13915     return(&_tm);
13916 }
13917
13918 #ifdef OXOS
13919 #undef kill
13920 #endif /* OXOS */
13921
13922 #ifdef OXOS
13923 int
13924 priv_kill(pid, sig) int pid, sig; {
13925     int i;
13926
13927     if (priv_on())
13928         debug(F100,"priv_kill priv_on failed","",0);
13929     i = kill(pid, sig);
13930     if (priv_off())
13931         debug(F100,"priv_kill priv_off failed","",0);
13932     return(i);
13933 }
13934 #endif /* OXOS */
13935
13936 #ifdef BEOSORBEBOX
13937 /* #ifdef BE_DR_7 */
13938 /*
13939   alarm() function not supplied with Be OS DR7 - this one contributed by
13940   Neal P. Murphy.
13941 */
13942
13943 /*
13944   This should mimic the UNIX/POSIX alarm() function well enough, with the
13945   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
13946   and wait for the alarm thread to finish.
13947 */
13948 unsigned int
13949 alarm(unsigned int seconds) {
13950     long time_left = 0;
13951
13952 /* If an alarm is active, turn it off, saving the unused time */
13953     if (alarm_thread != -1) {
13954         /* We'll be generous and count partial seconds as whole seconds. */
13955         time_left = alarm_struct.time -
13956           ((system_time() - time_started) / 1000000.0);
13957
13958         /* Kill the alarm thread */
13959         kill_thread (alarm_thread);
13960
13961         /* We need to clean up as though the alarm occured. */
13962         time_started = 0;
13963         alarm_struct.thread = -1;
13964         alarm_struct.time = 0;
13965         alarm_expired();
13966     }
13967
13968 /* Set a new alarm clock, if requested. */
13969     if (seconds > 0) {
13970         alarm_struct.thread = find_thread(NULL);
13971         alarm_struct.time = seconds;
13972         time_started = system_time();
13973         alarm_thread = spawn_thread (do_alarm,
13974                                      "alarm_thread",
13975                                      B_NORMAL_PRIORITY,
13976                                      (void *) &alarm_struct
13977                                      );
13978         resume_thread (alarm_thread);
13979     }
13980
13981 /* Now return [unused time | 0] */
13982     return ((unsigned int) time_left);
13983 }
13984
13985 /*
13986   This function is the departure from UNIX/POSIX alarm handling. In the case
13987   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
13988   handler. When Be implements alarm(), this function call can be eliminated
13989   from user's SIGALRM signal handlers.
13990 */
13991
13992 void
13993 alarm_expired(void) {
13994     long ret_val;
13995
13996     if (alarm_thread != -1) {
13997         wait_for_thread (alarm_thread, &ret_val);
13998         alarm_thread = -1;
13999     }
14000 }
14001
14002 /*
14003   This is the function that snoozes the requisite number of seconds and then
14004   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
14005   uses thread_id; currently they are both typdef'ed as long, but I'll do the
14006   cast anyway. This function is run in a separate thread.
14007 */
14008
14009 long
14010 do_alarm (void *alarm_struct) {
14011     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
14012     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
14013     time_started = 0;
14014     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
14015     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
14016 }
14017 /* #endif */ /* BE_DR_7 */
14018 #endif /* BEOSORBEBOX */
14019
14020 #ifdef Plan9
14021
14022 int
14023 p9ttyctl(char letter, int num, int param) {
14024     char cmd[20];
14025     int len;
14026
14027     if (ttyctlfd < 0)
14028       return -1;
14029
14030     cmd[0] = letter;
14031     if (num)
14032       len = sprintf(cmd + 1, "%d", param) + 1;
14033     else {
14034         cmd[1] = param;
14035         len = 2;
14036     }
14037     if (write(ttyctlfd, cmd, len) == len) {
14038         cmd[len] = 0;
14039         /* fprintf(stdout, "wrote '%s'\n", cmd); */
14040         return 0;
14041     }
14042     return -1;
14043 }
14044
14045 int
14046 p9ttyparity(char l) {
14047     return p9ttyctl('p', 0, l);
14048 }
14049
14050 int
14051 p9tthflow(int flow, int status) {
14052     return p9ttyctl('m', 1, status);
14053 }
14054
14055 int
14056 p9ttsspd(int cps) {
14057     if (p9ttyctl('b', 1, cps * 10) < 0)
14058       return -1;
14059     ttylastspeed = cps * 10;
14060     return 0;
14061 }
14062
14063 int
14064 p9openttyctl(char *ttname) {
14065     char name[100];
14066
14067     if (ttyctlfd >= 0) {
14068         close(ttyctlfd);
14069         ttyctlfd = -1;
14070         ttylastspeed = -1;
14071     }
14072     sprintf(name, "%sctl", ttname);
14073     ttyctlfd = open(name, 1);
14074     return ttyctlfd;
14075 }
14076
14077 int
14078 p9concb() {
14079     if (consctlfd >= 0) {
14080         if (write(consctlfd, "rawon", 5) == 5)
14081           return 0;
14082     }
14083     return -1;
14084 }
14085
14086 int
14087 p9conbin() {
14088     return p9concb();
14089 }
14090
14091 int
14092 p9conres() {
14093     if (consctlfd >= 0) {
14094         if (write(consctlfd, "rawoff", 6) == 6)
14095           return 0;
14096     }
14097     return -1;
14098 }
14099
14100 int
14101 p9sndbrk(int msec) {
14102     if (ttyctlfd >= 0) {
14103         char cmd[20];
14104         int i = sprintf(cmd, "k%d", msec);
14105         if (write(ttyctlfd, cmd, i) == i)
14106           return 0;
14107     }
14108     return -1;
14109 }
14110
14111 int
14112 conwrite(char *buf, int n) {
14113     int x;
14114     static int length = 0;
14115     static int holdingcr = 0;
14116     int normal = 0;
14117     for (x = 0; x < n; x++) {
14118         char c = buf[x];
14119         if (c == 007) {
14120             if (normal) {
14121                 write(1, buf + (x - normal), normal);
14122                 length += normal;
14123                 normal = 0;
14124             }
14125             /* write(noisefd, "1000 300", 8); */
14126             holdingcr = 0;
14127         } else if (c == '\r') {
14128             if (normal) {
14129                 write(1, buf + (x - normal), normal);
14130                 length += normal;
14131                 normal = 0;
14132             }
14133             holdingcr = 1;
14134         } else if (c == '\n') {
14135             write(1, buf + (x - normal), normal + 1);
14136             normal = 0;
14137             length = 0;
14138             holdingcr = 0;
14139         } else if (c == '\b') {
14140             if (normal) {
14141                 write(1, buf + (x - normal), normal);
14142                 length += normal;
14143                 normal = 0;
14144             }
14145             if (length) {
14146                 write(1, &c, 1);
14147                 length--;
14148             }
14149             holdingcr = 0;
14150         } else {
14151             if (holdingcr) {
14152                 char b = '\b';
14153                 while (length-- > 0)
14154                   write(1, &b, 1);
14155                 length = 0;     /* compiler bug */
14156             }
14157             holdingcr = 0;
14158             normal++;
14159         }
14160     }
14161     if (normal) {
14162         write(1, buf + (x - normal), normal);
14163         length += normal;
14164     }
14165     return n;
14166 }
14167
14168 void
14169 conprint(char *fmt, ...) {
14170     static char buf[1000];              /* not safe if on the stack */
14171
14172     va_list ap;
14173     int i;
14174
14175     va_start(ap, fmt);
14176     i = vsprintf(buf, fmt, ap);
14177     conwrite(buf, i);
14178 }
14179 #endif /* Plan9 */
14180
14181 /* fprintf, printf, perror replacements... */
14182
14183 /* f p r i n t f */
14184
14185 #ifdef UNIX
14186 #ifdef CK_ANSIC
14187 #include <stdarg.h>
14188 #else /* CK_ANSIC */
14189 #include <varargs.h>
14190 #endif /* CK_ANSIC */
14191 #ifdef fprintf
14192 #undef fprintf
14193 static char str1[4096];
14194 static char str2[4096];
14195 int
14196 #ifdef CK_ANSIC
14197 ckxfprintf(FILE * file, const char * format, ...)
14198 #else /* CK_ANSIC */
14199 ckxfprintf(va_alist) va_dcl
14200 #endif /* CK_ANSIC */
14201 /* ckxfprintf */ {
14202     int i, j, len, got_cr;
14203     va_list args;
14204     int rc = 0;
14205
14206 #ifdef CK_ANSIC
14207     va_start(args, format);
14208 #else /* CK_ANSIC */
14209     char * format;
14210     FILE * file;
14211     va_start(args);
14212     file = va_arg(args,FILE *);
14213     format = va_arg(args,char *);
14214 #endif /* CK_ANSIC */
14215
14216     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
14217         rc = vfprintf(file,format,args);
14218     } else {
14219         unsigned int c;
14220         rc = vsprintf(str1, format, args);
14221         len = strlen(str1);
14222         if (len >= sizeof(str1)) {
14223             debug(F101,"ckxfprintf() buffer overflow","",len);
14224             doexit(BAD_EXIT,1);
14225         }
14226         for (i = 0, j = 0, got_cr = 0;
14227              i < len && j < sizeof(str1)-2;
14228              i++, j++ ) {
14229             /* We can't use 255 as a case label because of signed chars */
14230             c = (unsigned)(str1[i] & 0xff);
14231 #ifdef TNCODE
14232             if (c == 255) {
14233                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
14234                   str2[j++] = '\0';
14235                 str2[j++] = IAC;
14236                 str2[j] = IAC;
14237                 got_cr = 0;
14238             } else
14239 #endif /* TNCODE */
14240             switch (c) {
14241               case '\r':
14242                 if (got_cr
14243 #ifdef TNCODE
14244                     && !TELOPT_ME(TELOPT_BINARY)
14245 #endif /* TNCODE */
14246                     )
14247                   str2[j++] = '\0';
14248                 str2[j] = str1[i];
14249                 got_cr = 1;
14250                 break;
14251               case '\n':
14252                 if (!got_cr)
14253                   str2[j++] = '\r';
14254                 str2[j] = str1[i];
14255                 got_cr = 0;
14256                 break;
14257               default:
14258                 if (got_cr
14259 #ifdef TNCODE
14260                     && !TELOPT_ME(TELOPT_BINARY)
14261 #endif /* TNCODE */
14262                     )
14263                   str2[j++] = '\0';
14264                 str2[j] = str1[i];
14265                 got_cr = 0;
14266             }
14267         }
14268         if (got_cr
14269 #ifdef TNCODE
14270              && !TELOPT_ME(TELOPT_BINARY)
14271 #endif /* TNCODE */
14272              )
14273             str2[j++] = '\0';
14274 #ifdef CK_ENCRYPTION
14275 #ifdef TNCODE
14276         if (TELOPT_ME(TELOPT_ENCRYPTION))
14277           ck_tn_encrypt(str2,j);
14278 #endif /* TNCODE */
14279 #endif /* CK_ENCRYPTION */
14280 #ifdef CK_SSL
14281         if (inserver && (ssl_active_flag || tls_active_flag)) {
14282             /* Write using SSL */
14283             char * p = str2;
14284           ssl_retry:
14285             if (ssl_active_flag)
14286               rc = SSL_write(ssl_con, p, j);
14287             else
14288               rc = SSL_write(tls_con, p, j);
14289             debug(F111,"ckxfprintf","SSL_write",rc);
14290             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
14291               case SSL_ERROR_NONE:
14292                 if (rc == j)
14293                   break;
14294                 p += rc;
14295                 j -= rc;
14296                 goto ssl_retry;
14297               case SSL_ERROR_WANT_WRITE:
14298               case SSL_ERROR_WANT_READ:
14299               case SSL_ERROR_SYSCALL:
14300                 if (rc != 0)
14301                   return(-1);
14302               case SSL_ERROR_WANT_X509_LOOKUP:
14303               case SSL_ERROR_SSL:
14304               case SSL_ERROR_ZERO_RETURN:
14305               default:
14306                 rc = 0;
14307             }
14308         } else
14309 #endif /* CK_SSL */
14310         fwrite(str2,sizeof(char),j,stdout);
14311     }
14312     va_end(args);
14313     return(rc);
14314 }
14315 #endif /* fprintf */
14316
14317 /* p r i n t f */
14318
14319 #ifdef printf
14320 #undef printf
14321 int
14322 #ifdef CK_ANSIC
14323 ckxprintf(const char * format, ...)
14324 #else /* CK_ANSIC */
14325 ckxprintf(va_alist) va_dcl
14326 #endif /* CK_ANSIC */
14327 /* ckxprintf */ {
14328     int i, j, len, got_cr;
14329     va_list args;
14330     int rc = 0;
14331
14332 #ifdef CK_ANSIC
14333     va_start(args, format);
14334 #else /* CK_ANSIC */
14335     char * format;
14336     va_start(args);
14337     format = va_arg(args,char *);
14338 #endif /* CK_ANSIC */
14339
14340     if (!inserver) {
14341         rc = vprintf(format, args);
14342     } else {
14343         unsigned int c;
14344         rc = vsprintf(str1, format, args);
14345         len = strlen(str1);
14346         if (len >= sizeof(str1)) {
14347             debug(F101,"ckxprintf() buffer overflow","",len);
14348             doexit(BAD_EXIT,1);
14349         }
14350         for (i = 0, j = 0, got_cr=0;
14351              i < len && j < sizeof(str1)-2;
14352              i++, j++ ) {
14353             c = (unsigned)(str1[i] & 0xff);
14354 #ifdef TNCODE
14355             if (c == 255) {
14356                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
14357                   str2[j++] = '\0';
14358                 str2[j++] = IAC;
14359                 str2[j] = IAC;
14360                 got_cr = 0;
14361             } else
14362 #endif /* TNCODE */
14363             switch (c) {
14364               case '\r':
14365                 if (got_cr
14366 #ifdef TNCODE
14367                     && !TELOPT_ME(TELOPT_BINARY)
14368 #endif /* TNCODE */
14369                     )
14370                   str2[j++] = '\0';
14371                 str2[j] = str1[i];
14372                 got_cr = 1;
14373                 break;
14374               case '\n':
14375                 if (!got_cr)
14376                   str2[j++] = '\r';
14377                 str2[j] = str1[i];
14378                 got_cr = 0;
14379                 break;
14380               default:
14381                 if (got_cr
14382 #ifdef TNCODE
14383                     && !TELOPT_ME(TELOPT_BINARY)
14384 #endif /* TNCODE */
14385                     )
14386                   str2[j++] = '\0';
14387                 str2[j] = str1[i];
14388                 got_cr = 0;
14389                 break;
14390             }
14391         }
14392         if (got_cr
14393 #ifdef TNCODE
14394              && !TELOPT_ME(TELOPT_BINARY)
14395 #endif /* TNCODE */
14396              )
14397             str2[j++] = '\0';
14398 #ifdef CK_ENCRYPTION
14399 #ifdef TNCODE
14400         if (TELOPT_ME(TELOPT_ENCRYPTION))
14401           ck_tn_encrypt(str2,j);
14402 #endif /* TNCODE */
14403 #endif /* CK_ENCRYPTION */
14404 #ifdef CK_SSL
14405         if (inserver && (ssl_active_flag || tls_active_flag)) {
14406             char * p = str2;
14407             /* Write using SSL */
14408           ssl_retry:
14409             if (ssl_active_flag)
14410               rc = SSL_write(ssl_con, p, j);
14411             else
14412               rc = SSL_write(tls_con, p, j);
14413             debug(F111,"ckxprintf","SSL_write",rc);
14414             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
14415               case SSL_ERROR_NONE:
14416                 if (rc == j)
14417                   break;
14418                 p += rc;
14419                 j -= rc;
14420                 goto ssl_retry;
14421               case SSL_ERROR_WANT_WRITE:
14422               case SSL_ERROR_WANT_READ:
14423               case SSL_ERROR_SYSCALL:
14424                 if (rc != 0)
14425                   return(-1);
14426               case SSL_ERROR_WANT_X509_LOOKUP:
14427               case SSL_ERROR_SSL:
14428               case SSL_ERROR_ZERO_RETURN:
14429               default:
14430                 rc = 0;
14431             }
14432         } else
14433 #endif /* CK_SSL */
14434           rc = fwrite(str2,sizeof(char),j,stdout);
14435     }
14436     va_end(args);
14437     return(rc);
14438 }
14439 #endif /* printf */
14440
14441 /*  p e r r o r  */
14442
14443 #ifdef perror
14444 #undef perror
14445 _PROTOTYP(char * ck_errstr,(VOID));
14446 #ifdef NEXT
14447 void
14448 #else
14449 #ifdef CK_SCOV5
14450 void
14451 #else
14452 int
14453 #endif /* CK_SCOV5 */
14454 #endif /* NEXT */
14455 #ifdef CK_ANSIC
14456 ckxperror(const char * str)
14457 #else /* CK_ANSIC */
14458 ckxperror(str) char * str;
14459 #endif /* CK_ANSIC */
14460 /* ckxperror */ {
14461     char * errstr = ck_errstr();
14462 #ifndef NEXT
14463 #ifndef CK_SCOV5
14464     return
14465 #endif /* CK_SCOV5 */
14466 #endif /* NEXT */
14467       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
14468 }
14469 #endif /* perror */
14470 #endif /* UNIX */
14471
14472 #ifdef MINIX2
14473
14474 /* Minix doesn't have a gettimeofday call. We fake one here using time(2) */
14475
14476 int
14477 gettimeofday(struct timeval *tp, struct timezone *tzp) {
14478     tp->tv_usec = 0L;                   /* Close enough for horseshoes */
14479     if(time(&(tp->tv_sec))==-1)
14480       return(-1);
14481     return(0);
14482 }
14483
14484 /* Minix does not support symbolic links. We implement a version of
14485    readlink that always fails */
14486
14487 int
14488 readlink(const char *path, void *buf, size_t bufsiz) {
14489     errno = ENOSYS;
14490     return(-1);
14491 }
14492 #endif /* MINIX2 */