Annotation of coherent/e/bin/cku179/ckutio.c, revision 1.1

1.1     ! root        1: char *ckxv = "UNIX tty I/O, 5A(087), 8 Feb 92";
        !             2: 
        !             3: /*  C K U T I O  */
        !             4: 
        !             5: /* C-Kermit interrupt, terminal control & i/o functions for UNIX */
        !             6: 
        !             7: /*
        !             8:  Author: Frank da Cruz ([email protected], [email protected]),
        !             9:  Columbia University Center for Computing Activities.  Many other contributors.
        !            10:  First released January 1985.
        !            11:  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
        !            12:  York.  Permission is granted to any individual or institution to use, copy, or
        !            13:  redistribute this software so long as it is not sold for profit, provided this
        !            14:  copyright notice is retained.
        !            15: */
        !            16: 
        !            17: /* Includes for all Unixes (conditional includes come later) */
        !            18: 
        !            19: #include "ckcdeb.h"                    /* This moved to here. */
        !            20: #include "ckcnet.h"                    /* Symbols for network types. */
        !            21: 
        !            22: #include <errno.h>                     /* System error numbers */
        !            23: 
        !            24: #ifdef SDIRENT                         /* Directory bits... */
        !            25: #define DIRENT
        !            26: #endif /* SDIRENT */
        !            27: 
        !            28: #ifdef XNDIR
        !            29: #include <sys/ndir.h>
        !            30: #else /* !XNDIR */
        !            31: #ifdef NDIR
        !            32: #include <ndir.h>
        !            33: #else /* !NDIR, !XNDIR */
        !            34: #ifdef RTU
        !            35: #include "/usr/lib/ndir.h"
        !            36: #else /* !RTU, !NDIR, !XNDIR */
        !            37: #ifdef DIRENT
        !            38: #ifdef SDIRENT
        !            39: #include <sys/dirent.h>
        !            40: #else
        !            41: #include <dirent.h>
        !            42: #endif /* SDIRENT */
        !            43: #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
        !            44: #include <sys/dir.h>
        !            45: #endif /* DIRENT */
        !            46: #endif /* RTU */
        !            47: #endif /* NDIR */
        !            48: #endif /* XNDIR */
        !            49: 
        !            50: /* Definition of HZ, used in msleep() */
        !            51: 
        !            52: #ifdef MIPS
        !            53: #define HZ ( 1000 / CLOCK_TICK )
        !            54: #else
        !            55: #ifdef ATTSV
        !            56: #ifndef NAP
        !            57: #ifndef TRS16
        !            58: #include <sys/param.h>
        !            59: #else
        !            60: #define HZ ( 1000 / CLOCK_TICK )
        !            61: #endif /* TRS16 */
        !            62: #endif /* NAP */
        !            63: #endif /* ATTSV */
        !            64: #endif /* MIPS */
        !            65: 
        !            66: #ifdef M_UNIX
        !            67: #undef NGROUPS_MAX             /* Prevent multiple definition warnings */
        !            68: #endif /* M_UNIX */
        !            69: 
        !            70: #include <signal.h>                     /* Signals */
        !            71: 
        !            72: /* For setjmp and longjmp */
        !            73: 
        !            74: #ifndef ZILOG
        !            75: #include <setjmp.h>
        !            76: #else
        !            77: #include <setret.h>
        !            78: #endif /* ZILOG */
        !            79: 
        !            80: /* Maximum length for the name of a tty device */
        !            81: 
        !            82: #ifndef DEVNAMLEN
        !            83: #define DEVNAMLEN 25
        !            84: #endif
        !            85: 
        !            86: #ifdef NETCONN
        !            87: #undef DEVNAMLEN
        !            88: #define DEVNAMLEN 50                   /* longer field for host:service */
        !            89: #endif  /* NETCONN */
        !            90: 
        !            91: /*
        !            92:   The following test differentiates between 4.1 BSD and 4.2 & later.
        !            93:   If you have a 4.1BSD system with the DIRENT library, this test could
        !            94:   mistakenly diagnose 4.2BSD and then later enable the use of system calls
        !            95:   that aren't defined.  If indeed there are such systems, we can use some
        !            96:   other way of testing for 4.1BSD, or add yet another compile-time switch.
        !            97: */  
        !            98: #ifdef BSD4
        !            99: #ifdef MAXNAMLEN
        !           100: #ifndef FT21
        !           101: #ifndef FT18                           /* Except for Fortune. */
        !           102: #define BSD42
        !           103: #endif /* FT18 */
        !           104: #endif /* FT21 */
        !           105: #endif /* MAXNAMLEN */
        !           106: #endif /* BSD4 */
        !           107: 
        !           108: /*
        !           109:  Minix support added by Charles Hedrick,
        !           110:  Rutgers University:  [email protected]
        !           111:  Minix also has V7 enabled.
        !           112: */
        !           113: #ifdef MINIX
        !           114: #define TANDEM 0
        !           115: #define MYREAD
        !           116: #include <limits.h>
        !           117: #endif /* MINIX */
        !           118: 
        !           119: #include "ckuver.h"                    /* Version herald */
        !           120: char *ckxsys = HERALD;
        !           121: 
        !           122: /* UUCP lock file name definition */
        !           123: 
        !           124: #ifndef NOUUCP
        !           125: 
        !           126: /* Name of UUCP tty device lock file */
        !           127: 
        !           128: #ifdef ACUCNTRL
        !           129: #define LCKDIR
        !           130: #endif /* ACUCNTRL */
        !           131: /*
        !           132:   LOCK_DIR is the name of the lockfile directory.
        !           133:   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
        !           134:   PIDSTRING means use ASCII string to represent pid in lockfile.
        !           135: */
        !           136: #ifndef LOCK_DIR
        !           137: #ifdef COHERENT
        !           138: #define PIDSTRING
        !           139: #define LOCK_DIR "/tmp";
        !           140: #else
        !           141: #ifdef RTAIX                           /* IBM RT PC AIX 2.2.1 */
        !           142: #define PIDSTRING
        !           143: #define LOCK_DIR "/etc/locks";
        !           144: #else
        !           145: #ifdef AIXRS
        !           146: #define PIDSTRING
        !           147: #define LOCK_DIR "/etc/locks";
        !           148: #else
        !           149: #ifdef ISIII
        !           150: #define LOCK_DIR "/etc/locks";
        !           151: #else
        !           152: #ifdef HDBUUCP
        !           153: #define PIDSTRING
        !           154: #ifdef M_SYS5  /* wht@n4hgf - SCO */
        !           155: #define LOCK_DIR "/usr/spool/uucp";
        !           156: #else
        !           157: #ifdef M_UNIX
        !           158: #define LOCK_DIR "/usr/spool/uucp";
        !           159: #else
        !           160: #ifdef SVR4
        !           161: #define LOCK_DIR "/var/spool/locks";
        !           162: #else
        !           163: #ifdef SUNOS4
        !           164: #define LOCK_DIR "/var/spool/locks";
        !           165: #else
        !           166: #define LOCK_DIR "/usr/spool/locks";
        !           167: #endif /* SUNOS4 */
        !           168: #endif /* SVR4 */
        !           169: #endif /* M_UNIX */
        !           170: #endif /* M_SYS5 */
        !           171: #else
        !           172: #ifdef LCKDIR
        !           173: #define LOCK_DIR "/usr/spool/uucp/LCK";
        !           174: #else
        !           175: #define LOCK_DIR "/usr/spool/uucp";
        !           176: #endif /* LCKDIR */
        !           177: #endif /* HDBUUCP */
        !           178: #endif /* ISIII */
        !           179: #endif /* AIXRS */
        !           180: #endif /* RTAIX */
        !           181: #endif /* COHERENT */
        !           182: #endif /* !LOCK_DIR (outside ifndef) */
        !           183:    
        !           184: #endif /* !NOUUCP */
        !           185: 
        !           186: #ifdef ATTSV
        !           187: #define MYREAD
        !           188: #endif /* ATTSV */
        !           189: 
        !           190: #ifdef ATT7300
        !           191: #define MYREAD
        !           192: /* bits for attmodem: internal modem in use, restart getty */
        !           193: #define ISMODEM 1
        !           194: #define DOGETY 512
        !           195: #endif  /* ATT7300 */
        !           196: 
        !           197: #ifdef BSD42
        !           198: #define MYREAD
        !           199: #endif /* BSD42 */
        !           200: 
        !           201: #ifdef POSIX
        !           202: #define MYREAD
        !           203: #endif /* POSIX */
        !           204: 
        !           205: /*
        !           206:  Variables available to outside world:
        !           207: 
        !           208:    dftty  -- Pointer to default tty name string, like "/dev/tty".
        !           209:    dfloc  -- 0 if dftty is console, 1 if external line.
        !           210:    dfprty -- Default parity
        !           211:    dfflow -- Default flow control
        !           212:    ckxech -- Flag for who echoes console typein:
        !           213:      1 - The program (system echo is turned off)
        !           214:      0 - The system (or front end, or terminal).
        !           215:    functions that want to do their own echoing should check this flag
        !           216:    before doing so.
        !           217: 
        !           218:    flfnam  -- Name of lock file, including its path, e.g.,
        !           219:                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
        !           220:    lkflfn  -- Name of link to lock file, including its paths
        !           221:    haslock -- Flag set if this kermit established a uucp lock.
        !           222:    backgrd -- Flag indicating program executing in background ( & on
        !           223:                 end of shell command). Used to ignore INT and QUIT signals.
        !           224:    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
        !           225:                 SIGTSTP)
        !           226: 
        !           227:  Functions for assigned communication line (either external or console tty):
        !           228: 
        !           229:    sysinit()               -- System dependent program initialization
        !           230:    syscleanup()            -- System dependent program shutdown
        !           231:    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
        !           232:    ttclos()                -- Close & reset the tty, releasing any access lock.
        !           233:    ttsspd(cps)             -- Set the transmission speed of the tty.
        !           234:    ttgspd()                -- Get (read) the the transmission speed of the tty.
        !           235:    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
        !           236:    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
        !           237:                                 or in DIALING or CONNECTED modem control state.
        !           238:    ttres()                 -- Restore original tty modes.
        !           239:    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
        !           240:    ttinl(dest,max,timo)    -- Timed read line from the tty.
        !           241:    ttinc(timo)             -- Timed read character from tty.
        !           242:    myread()                -- Raw mode bulk buffer read, gives subsequent
        !           243:                                 chars one at a time and simulates FIONREAD.
        !           244:    myunrd(c)               -- Places c back in buffer to be read (one only)
        !           245:    ttchk()                 -- See how many characters in tty input buffer.
        !           246:    ttxin(n,buf)            -- Read n characters from tty (untimed).
        !           247:    ttol(string,length)     -- Write a string to the tty.
        !           248:    ttoc(c)                 -- Write a character to the tty.
        !           249:    ttflui()                -- Flush tty input buffer.
        !           250:    ttsndb()                -- Send BREAK signal.
        !           251:    ttsndlb()               -- Send Long BREAK signal.
        !           252: 
        !           253:    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
        !           254:    ttunlck()               -- Unlock tty device.
        !           255: 
        !           256:                               For ATT7300/Unix PC, System V:
        !           257:    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
        !           258:    offgetty(ttname)        -- Turns off getty(1m) for comms line
        !           259:    ongetty(ttname)         -- Restores getty() to comms line
        !           260: */
        !           261: 
        !           262: /*
        !           263: Functions for console terminal:
        !           264: 
        !           265:    congm()   -- Get console terminal modes.
        !           266:    concb(esc) -- Put the console in single-character wakeup mode with no echo.
        !           267:    conbin(esc) -- Put the console in binary (raw) mode.
        !           268:    conres()  -- Restore the console to mode obtained by congm().
        !           269:    conoc(c)  -- Unbuffered output, one character to console.
        !           270:    conol(s)  -- Unbuffered output, null-terminated string to the console.
        !           271:    conola(s) -- Unbuffered output, array of strings to the console.
        !           272:    conxo(n,s) -- Unbuffered output, n characters to the console.
        !           273:    conchk()  -- Check if characters available at console (bsd 4.2).
        !           274:                 Check if escape char (^\) typed at console (System III/V).
        !           275:    coninc(timo)  -- Timed get a character from the console.
        !           276:    congks(timo)  -- Timed get keyboard scan code.
        !           277:    conint()  -- Enable terminal interrupts on the console if not background.
        !           278:    connoi()  -- Disable terminal interrupts on the console if not background.
        !           279: 
        !           280: Time functions
        !           281: 
        !           282:    msleep(m) -- Millisecond sleep
        !           283:    ztime(&s) -- Return pointer to date/time string
        !           284:    rtimer() --  Reset timer
        !           285:    gtimer()  -- Get elapsed time since last call to rtimer()
        !           286: */
        !           287: 
        !           288: /* Conditional Includes */
        !           289: 
        !           290: /* Whether to include <sys/file.h> */
        !           291: 
        !           292: #ifdef RTU                             /* RTU doesn't */
        !           293: #define NOFILEH
        !           294: #endif /* RTU */
        !           295: 
        !           296: #ifdef CIE                             /* CIE does. */
        !           297: #undef NOFILEH
        !           298: #endif /* CIE */
        !           299: 
        !           300: #ifdef BSD41                           /* 4.1 BSD doesn't */
        !           301: #define NOFILEH
        !           302: #endif /* BSD41 */
        !           303: 
        !           304: #ifdef is68k                           /* is68k (whatever that is)  */
        !           305: #define NOFILEH
        !           306: #endif /* is68k */
        !           307: 
        !           308: #ifdef MINIX                           /* MINIX */
        !           309: #define NOFILEH
        !           310: #endif /* MINIX */
        !           311: 
        !           312: #ifdef COHERENT                                /* Coherent */
        !           313: #define NOFILEH
        !           314: #endif /* COHERENT */
        !           315: 
        !           316: #ifndef NOFILEH                                /* Now include if selected. */
        !           317: #include <sys/file.h>
        !           318: #endif /* NOFILEH */
        !           319: 
        !           320: /* System III, System V */
        !           321: 
        !           322: #ifdef ATTSV
        !           323: #include <termio.h>
        !           324: #ifdef SVR3                            /* Sys V R3 and later */
        !           325: #ifdef TERMIOX
        !           326: /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
        !           327: #include <termiox.h>
        !           328:   struct termiox rctsx;
        !           329: #else
        !           330: #ifdef STERMIOX
        !           331: #include <sys/termiox.h>
        !           332:   struct termiox rctsx;
        !           333: #endif /* STERMIOX */
        !           334: #endif /* TERMIOX */
        !           335: #endif /* SVR3 */
        !           336: #endif /* ATTSV */
        !           337: 
        !           338: /* POSIX */
        !           339: 
        !           340: #ifdef POSIX                           /* POSIX uses termios.h */
        !           341: #include <termios.h>
        !           342: #define NOSYSIOCTLH                    /* No ioctl's allowed. */
        !           343: #undef ultrix                          /* Turn off any ultrix features. */
        !           344: #endif /* POSIX */
        !           345: 
        !           346: #ifdef MINIX                           /* MINIX uses ioctl's */
        !           347: #define NOSYSIOCTLH                    /* but has no <sys/ioctl.h> */
        !           348: #endif /* MINIX */
        !           349: 
        !           350: /* Others */
        !           351: 
        !           352: #ifndef NOSYSIOCTLH                    /* Others use ioctl() */
        !           353: #include <sys/ioctl.h>
        !           354: #endif /* NOSYSIOCTLH */
        !           355: 
        !           356: /* Whether to include <fcntl.h> */
        !           357: 
        !           358: #ifndef is68k                          /* Only a few don't have this one. */
        !           359: #ifndef BSD41
        !           360: #ifndef FT21
        !           361: #ifndef FT18
        !           362: #include <fcntl.h>
        !           363: #endif /* FT18 */
        !           364: #endif /* FT21 */
        !           365: #endif /* BSD41 */
        !           366: #endif /* not is68k */
        !           367: 
        !           368: #ifdef ATT7300                         /* Unix PC, internal modem dialer */
        !           369: #include <sys/phone.h>
        !           370: #endif /* ATT7300 */
        !           371: 
        !           372: #ifdef HPUX                            /* HP-UX variations. */
        !           373: #define HPUXJOBCTL
        !           374: #include <sys/modem.h>                 /* HP-UX modem signals */
        !           375: #ifdef hp9000s500                      /* Model 500 */
        !           376: #undef HPUXJOBCTL
        !           377: #endif /* hp9000s500 */
        !           378: #ifdef HPUXPRE65
        !           379: #undef HPUXJOBCTL
        !           380: typedef int mflag;
        !           381: #endif /* HPUXPRE65 */
        !           382: #ifdef HPUXJOBCTL
        !           383: #include <sys/bsdtty.h>                        /* HP-UX Berkeley tty support */
        !           384: #endif /* HPUXJOBCTL */
        !           385: #endif /* HPUX */
        !           386: 
        !           387: /* BSD, V7, Coherent, Minix, et al. */
        !           388: 
        !           389: #ifndef SVORPOSIX                      /* Not AT&T Sys V or POSIX */
        !           390: #include <sgtty.h>                      /* So we use <sgtty.h> */
        !           391: #ifndef PROVX1                         /* Now <sys/time.h> ... */
        !           392: #ifndef V7
        !           393: #ifndef BSD41
        !           394: #ifndef COHERENT
        !           395: #include <sys/time.h>                   /* Clock info (for break generation) */
        !           396: #endif /* COHERENT */
        !           397: #endif /* BSD41 */
        !           398: #endif /* V7 */
        !           399: #endif /* PROVX1 */
        !           400: #endif /* SVORPOSIX */
        !           401: 
        !           402: #ifdef BSD41                           /* BSD 4.1 */
        !           403: #include <sys/timeb.h>
        !           404: #endif /* BSD41 */
        !           405: 
        !           406: #ifdef FT21                            /* For:Pro 2.1 */
        !           407: #include <sys/timeb.h>
        !           408: #endif /* FT21 */
        !           409: 
        !           410: #ifdef BSD29                           /* BSD 2.9 */
        !           411: #include <sys/timeb.h>
        !           412: #endif /* BSD29 */
        !           413: 
        !           414: #ifdef TOWER1
        !           415: #include <sys/timeb.h>                  /* Clock info for NCR Tower */
        !           416: #endif /* TOWER1 */
        !           417: 
        !           418: #ifdef COHERENT
        !           419: #include <sys/timeb.h>                  /* Clock info for NCR Tower */
        !           420: #endif /* COHERENT */
        !           421: 
        !           422: #ifdef aegis
        !           423: #include "/sys/ins/base.ins.c"
        !           424: #include "/sys/ins/error.ins.c"
        !           425: #include "/sys/ins/ios.ins.c"
        !           426: #include "/sys/ins/sio.ins.c"
        !           427: #include "/sys/ins/pad.ins.c"
        !           428: #include "/sys/ins/time.ins.c"
        !           429: #include "/sys/ins/pfm.ins.c"
        !           430: #include "/sys/ins/pgm.ins.c"
        !           431: #include "/sys/ins/ec2.ins.c"
        !           432: #include "/sys/ins/type_uids.ins.c"
        !           433: #include <default_acl.h>
        !           434: #undef TIOCEXCL
        !           435: #undef FIONREAD
        !           436: #endif /* aegis */
        !           437: 
        !           438: #ifdef sxaE50                          /* PFU Compact A SX/A TISP V10/L50 */
        !           439: #undef FIONREAD
        !           440: #endif /* sxaE50 */
        !           441: 
        !           442: /* The following #defines are catch-alls for those systems */
        !           443: /* that didn't have or couldn't find <file.h>... */
        !           444: 
        !           445: #ifndef FREAD
        !           446: #define FREAD 0x01
        !           447: #endif /* FREAD */
        !           448: 
        !           449: #ifndef FWRITE
        !           450: #define FWRITE 0x10
        !           451: #endif /* FWRITE */
        !           452: 
        !           453: #ifndef O_RDONLY
        !           454: #define O_RDONLY 000
        !           455: #endif /* O_RDONLY */
        !           456: 
        !           457: /* Declarations */
        !           458: 
        !           459: #ifdef _POSIX_SOURCE                   /* This includes MINIX */
        !           460: #include <time.h>
        !           461: #ifdef __GNUC__
        !           462: #ifdef XENIX
        !           463: /*
        !           464:   Because Xenix <time.h> doesn't declare time() if we're using gcc.
        !           465: */
        !           466: time_t time();
        !           467: #endif /* XENIX */
        !           468: #endif /* __GNUC__ */
        !           469: #else
        !           470: time_t time();                         /* All Unixes should have this... */
        !           471: #endif /* _POSIX_SOURCE */
        !           472: 
        !           473: /* Special stuff for V7 input buffer peeking */
        !           474: 
        !           475: #ifdef  V7
        !           476: int kmem[2] = { -1, -1};
        !           477: char *initrawq(), *qaddr[2]={0,0};
        !           478: #define CON 0
        !           479: #define TTY 1
        !           480: #endif /* V7 */
        !           481: 
        !           482: /* dftty is the device name of the default device for file transfer */
        !           483: /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
        !           484: 
        !           485: #ifndef DFTTY
        !           486: #ifdef PROVX1
        !           487:     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
        !           488:     char *dfmdm = "none";
        !           489:     int dfloc = 1;                  /* that goes in local mode by default */
        !           490: #else
        !           491: #ifdef COHERENT
        !           492:     char *dftty = "/dev/modem";
        !           493:     char *dfmdm = "none";
        !           494:     int dfloc = 1;
        !           495: #else
        !           496:     char *dftty = CTTNAM;               /* Remote by default, use normal */
        !           497:     char *dfmdm = "none";
        !           498:     int dfloc = 0;                      /* controlling terminal name. */
        !           499: #endif /* COHERENT */
        !           500: #endif /* PROVX1 */
        !           501: #else
        !           502:     char *dftty = DFTTY;               /* Default location specified on */
        !           503:     char *dfmdm = "none";              /* command line. */
        !           504:     int dfloc = 1;                      /* controlling terminal name. */
        !           505: #endif /* DFTTY */
        !           506: 
        !           507: #ifdef RTU
        !           508:     int rtu_bug = 0;               /* set to 1 when returning from SIGTSTP */
        !           509: #endif /* RTU */
        !           510: 
        !           511:     int dfprty = 0;                     /* Default parity (0 = none) */
        !           512:     int ttprty = 0;                     /* Parity in use. */
        !           513:     static int ttpmsk = 0377;          /* Parity stripping mask. */
        !           514:     int ttmdm = 0;                      /* Modem in use. */
        !           515:     int ttcarr = CAR_AUT;              /* Carrier handling mode. */
        !           516:     int dfflow = 1;                     /* Xon/Xoff flow control */
        !           517:     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
        !           518: #ifdef ultrix
        !           519:     int iniflags = 0;                  /* fcntl flags for ttyfd */
        !           520: #endif /* ultrix */
        !           521:     int fdflag = 0;                    /* Flag for redirected stdio */
        !           522:     int ttfdflg = 0;                   /* Open File descriptor was given */
        !           523:     int tvtflg = 0;                    /* Flag that ttvt has been called */
        !           524:     long ttspeed = -1;                 /* For saving speed */
        !           525:     int ttflow = -9;                   /* For saving flow */
        !           526:     int ttld = -1;                     /* Line discipline */
        !           527: 
        !           528: #ifdef sony_news
        !           529:     static int km_con = -1;            /* Kanji mode for console tty */
        !           530:     static int km_ext = -1;            /* Kanji mode for external device */
        !           531: #endif /* sony_news */
        !           532: 
        !           533: extern int ttnproto;
        !           534: extern int ttnet;
        !           535: 
        !           536: int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
        !           537: 
        !           538: /* Declarations of variables global within this module */
        !           539: 
        !           540: static time_t tcount;                  /* Elapsed time counter */
        !           541: SIGTYP (*saval)() = NULL;              /* For saving alarm handler */
        !           542: 
        !           543: /*
        !           544:   BREAKNULS is defined for systems that simulate sending a BREAK signal
        !           545:   by sending a bunch of NUL characters at low speed.
        !           546: */
        !           547: #ifdef PROVX1
        !           548: #ifndef BREAKNULS
        !           549: #define BREAKNULS
        !           550: #endif /* BREAKNULS */
        !           551: #endif /* PROVX1 */
        !           552: 
        !           553: #ifdef V7
        !           554: #ifndef BREAKNULS
        !           555: #define BREAKNULS
        !           556: #endif /* BREAKNULS */
        !           557: #endif /* V7 */
        !           558: 
        !           559: #ifdef BREAKNULS
        !           560: static char                            /* A string of nulls */
        !           561: *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";
        !           562: #endif /* BREAKNULS */
        !           563: 
        !           564: static jmp_buf sjbuf;                  /* Longjump buffers */
        !           565: #ifdef V7
        !           566: static jmp_buf jjbuf;
        !           567: #endif /* V7 */
        !           568: 
        !           569: /* static */                           /* (Not static any more) */
        !           570: int ttyfd = -1;                                /* TTY file descriptor */
        !           571: 
        !           572: int telnetfd = 0;                      /* File descriptor is for telnet */
        !           573: int x25fd = 0;                         /* File descriptor is for X.25 */
        !           574: 
        !           575: static int lkf = 0,                     /* Line lock flag */
        !           576:     cgmf = 0,                           /* Flag that console modes saved */
        !           577:     xlocal = 0,                         /* Flag for tty local or remote */
        !           578:     curcarr = 0;                       /* Carrier mode: require/ignore. */
        !           579: 
        !           580: static int netconn = 0;                        /* 1 if network connection active */
        !           581: 
        !           582: static char escchr;                     /* Escape or attn character */
        !           583: 
        !           584: #ifdef BSD42
        !           585:     static struct timeval tv;          /* For getting time, from sys/time.h */
        !           586:     static struct timezone tz;
        !           587: #endif /* BSD42 */
        !           588: 
        !           589: #ifdef BSD29
        !           590:     static long xclock;                  /* For getting time from sys/time.h */
        !           591:     static struct timeb ftp;            /* And from sys/timeb.h */
        !           592: #endif /* BSD29 */
        !           593: 
        !           594: #ifdef BSD41
        !           595:     static long xclock;                  /* For getting time from sys/time.h */
        !           596:     static struct timeb ftp;            /* And from sys/timeb.h */
        !           597: #endif /* BSD41 */
        !           598: 
        !           599: #ifdef FT21
        !           600:     static long xclock;                  /* For getting time from sys/time.h */
        !           601:     static struct timeb ftp;            /* And from sys/timeb.h */
        !           602: #endif /* FT21 */
        !           603: 
        !           604: #ifdef TOWER1
        !           605:     static long xclock;                        /* For getting time from sys/time.h */
        !           606:     static struct timeb ftp;           /* And from sys/timeb.h */
        !           607: #endif /* TOWER1 */
        !           608: 
        !           609: #ifdef COHERENT
        !           610:     static long xclock;                        /* For getting time from sys/time.h */
        !           611:     static struct timeb ftp;           /* And from sys/timeb.h */
        !           612: #endif /* COHERENT */
        !           613: 
        !           614: #ifdef V7
        !           615:     static long xclock;
        !           616: #endif /* V7 */
        !           617: 
        !           618: /* sgtty/termio information... */
        !           619: 
        !           620: #ifdef ATTSV
        !           621: 
        !           622:   static struct termio ttold = {0}; /* Init'd for word alignment, */
        !           623:   static struct termio ttraw = {0}; /* which is important for some */
        !           624:   static struct termio tttvt = {0}; /* systems, like Zilog... */
        !           625:   static struct termio ttcur = {0};
        !           626:   static struct termio ccold = {0};
        !           627:   static struct termio ccraw = {0};
        !           628:   static struct termio cccbrk = {0};
        !           629: #else
        !           630: #ifdef POSIX                           /* POSIX */
        !           631:   static struct termios
        !           632:     ttold, ttraw, tttvt, ttcur,
        !           633:     ccold, ccraw, cccbrk;
        !           634: #else                                  /* BSD, V7, etc */
        !           635:   static struct sgttyb                  /* sgtty info... */
        !           636:     ttold, ttraw, tttvt, ttcur,        /* for communication line */
        !           637:     ccold, ccraw, cccbrk;              /* and for console */
        !           638: #ifdef TIOCGETC
        !           639: #ifdef MINIX
        !           640:   static struct sgttyb tchold, tchnoi; /* Special chars */
        !           641: #else
        !           642:   static struct tchars tchold, tchnoi;
        !           643: #endif /* MINIX */
        !           644:   static int tcharf;
        !           645: #endif /* TIOCGETC */
        !           646: #ifdef TIOCGLTC
        !           647: #ifdef MINIX
        !           648:   static struct sgttyb ltchold, ltchnoi;
        !           649: #else
        !           650:   static struct ltchars ltchold, ltchnoi;
        !           651: #endif /* MINIX */
        !           652:   static int ltcharf;
        !           653: #endif /* TIOCGLTC */
        !           654:   int lmodef = 0;                      /* Local modes */
        !           655:   int lmode = 0;
        !           656: #endif /* POSIX */
        !           657: #endif /* ATTSV */
        !           658: 
        !           659: #ifdef PROVX1
        !           660:   static struct sgttyb ttbuf;
        !           661: #endif /* PROVX1 */
        !           662: 
        !           663: #ifdef ultrix
        !           664: /* do we really need this? */
        !           665:   static struct sgttyb vanilla;
        !           666: #endif /* ultrix */
        !           667: 
        !           668: #ifdef ATT7300
        !           669: static int attmodem = 0;                /* ATT7300 internal-modem status */
        !           670: struct updata dialer = {0};            /* Condition dialer for data call */
        !           671: #endif /* ATT7300 */
        !           672: 
        !           673: char flfnam[80];                       /* uucp lock file path name */
        !           674: #ifdef RTAIX
        !           675: char lkflfn[80];                       /* and possible link to it */
        !           676: #endif /* RTAIX */
        !           677: int haslock = 0;                       /* =1 if this kermit locked uucp */
        !           678: 
        !           679: #ifdef SVORPOSIX
        !           680: static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
        !           681: #else
        !           682: #ifdef V7
        !           683: static int conesc = 0;
        !           684: #else
        !           685: #ifdef C70
        !           686: static int conesc = 0;
        !           687: #endif /* C70 */
        !           688: #endif /* V7 */
        !           689: #endif /* ATTSV */
        !           690: 
        !           691: static char ttnmsv[DEVNAMLEN];         /* Copy of open path for tthang */
        !           692: 
        !           693: #ifdef aegis
        !           694: static status_$t st;                    /* error status return value */
        !           695: static short concrp = 0;                /* true if console is CRP pad */
        !           696: #define CONBUFSIZ 10
        !           697: static char conbuf[CONBUFSIZ];          /* console readahead buffer */
        !           698: static int  conbufn = 0;                /* # chars in readahead buffer */
        !           699: static char *conbufp;                   /* next char in readahead buffer */
        !           700: static uid_$t ttyuid;                   /* tty type uid */
        !           701: static uid_$t conuid;                   /* stdout type uid */
        !           702: 
        !           703: /* APOLLO Aegis main()
        !           704:  * establish acl usage and cleanup handling
        !           705:  *    this makes sure that CRP pads
        !           706:  *    get restored to a usable mode
        !           707:  */
        !           708: main(argc,argv) int argc; char **argv; {
        !           709:         status_$t status;
        !           710:         pfm_$cleanup_rec dirty;
        !           711: 
        !           712:         PID_T pid = getpid();
        !           713: 
        !           714:         /* acl usage according to invoking environment */
        !           715:         default_acl(USE_DEFENV);
        !           716: 
        !           717:         /* establish a cleanup continuation */
        !           718:         status = pfm_$cleanup(dirty);
        !           719:         if (status.all != pfm_$cleanup_set) {
        !           720:                 /* only handle faults for the original process */
        !           721:                 if (pid == getpid() && status.all > pgm_$max_severity) {
        !           722:                    /* blew up in main process */
        !           723:                    status_$t quo;
        !           724:                    pfm_$cleanup_rec clean;
        !           725: 
        !           726:                    /* restore the console in any case */
        !           727:                    conres();
        !           728: 
        !           729:                    /* attempt a clean exit */
        !           730:                    debug(F101, "cleanup fault status", "", status.all);
        !           731: 
        !           732:                    /* doexit(), then send status to continuation */
        !           733:                    quo = pfm_$cleanup(clean);
        !           734:                    if (quo.all == pfm_$cleanup_set)
        !           735:                      doexit(pgm_$program_faulted,-1);
        !           736:                    else if (quo.all > pgm_$max_severity)
        !           737:                      pfm_$signal(quo); /* blew up in doexit() */
        !           738:                 }
        !           739:                 /* send to the original continuation */
        !           740:                 pfm_$signal(status);
        !           741:                 /*NOTREACHED*/
        !           742:            }
        !           743:         return(ckcmai(argc, argv));
        !           744: }
        !           745: #endif /* aegis */
        !           746: 
        !           747: /* ANSI-style prototypes for internal functions. */
        !           748: /* Functions used outside this module are prototyped in ckcker.h. */
        !           749: 
        !           750: #ifdef apollo
        !           751: _PROTOTYP( SIGTYP timerh, () );
        !           752: _PROTOTYP( SIGTYP cctrap, () );
        !           753: _PROTOTYP( SIGTYP esctrp, () );
        !           754: _PROTOTYP( SIGTYP sig_ign, () );
        !           755: #else
        !           756: _PROTOTYP( SIGTYP timerh, (int) );
        !           757: _PROTOTYP( SIGTYP cctrap, (int) );
        !           758: _PROTOTYP( SIGTYP esctrp, (int) );
        !           759: #endif /* apollo */
        !           760: _PROTOTYP( int do_open, (char *) );
        !           761: _PROTOTYP( int ttrpid, (char *) );
        !           762: _PROTOTYP( static int ttlock, (char *) );
        !           763: _PROTOTYP( static int ttunlck, (void) );
        !           764: _PROTOTYP( int mygetbuf, (void) );
        !           765: _PROTOTYP( int myfillbuf, (void) );
        !           766: _PROTOTYP( VOID conbgt, (void) );
        !           767: #ifdef ACUCNTRL
        !           768: _PROTOTYP( VOID acucntrl, (char *, char *) );
        !           769: #endif /* ACUCNTRL */
        !           770: 
        !           771: #ifdef ATTSV
        !           772: _PROTOTYP( int carrctl, (struct termio *, int) );
        !           773: #else
        !           774: #ifdef POSIX
        !           775: _PROTOTYP( int carrctl, (struct termios *, int) );
        !           776: #else
        !           777: _PROTOTYP( int carrctl, (struct sgttyb *, int) );
        !           778: #endif /* POSIX */
        !           779: #endif /* ATTSV */
        !           780: 
        !           781: #ifdef ATT7300
        !           782: _PROTOTYP( int attdial, (char *, long, char *) );
        !           783: _PROTOTYP( int offgetty, (char *) );
        !           784: _PROTOTYP( int ongetty, (char *) );
        !           785: #endif /* ATT7300 */
        !           786: 
        !           787: #ifdef CK_ANSIC
        !           788: static char *
        !           789: xxlast(char *s, char c)
        !           790: #else
        !           791: static char *
        !           792: xxlast(s,c) char *s; char c;
        !           793: #endif /* CK_ANSIC */
        !           794: /* xxlast */ {         /*  Last occurrence of character c in string s. */
        !           795:     int i;
        !           796:     for (i = (int)strlen(s); i > 0; i--)
        !           797:         if ( s[i-1] == c ) return( s + (i - 1) );
        !           798:     return(NULL);
        !           799: }
        !           800: 
        !           801: /* Timeout handler for communication line input functions */
        !           802: 
        !           803: SIGTYP
        !           804: timerh(foo) int foo; {
        !           805:     ttimoff();
        !           806:     longjmp(sjbuf,1);
        !           807: }
        !           808: 
        !           809: /* Control-C trap for communication line input functions */
        !           810: 
        !           811: int cc_int;                            /* Flag */
        !           812: SIGTYP (* occt)();                     /* For saving old SIGINT handler */
        !           813: 
        !           814: SIGTYP
        !           815: cctrap(foo) int foo; {                 /* Needs arg for ANSI C */
        !           816:   cc_int = 1;                          /* signal() prototype. */
        !           817:   return;
        !           818: }
        !           819: 
        !           820: /*  S Y S I N I T  --  System-dependent program initialization.  */
        !           821: 
        !           822: int
        !           823: sysinit() {
        !           824:     int x;
        !           825: 
        !           826:     conbgt();                          /* See if we're in the background */
        !           827:     congm();                           /* Get console modes */
        !           828: 
        !           829: #ifdef ultrix
        !           830:     gtty(0,&vanilla);                  /* Get sgtty info */
        !           831:     iniflags = fcntl(0,F_GETFL,0);     /* Get flags */
        !           832: #else
        !           833: #ifdef AUX
        !           834:     set42sig();                              /* Don't ask! ([email protected]) */
        !           835: #endif /* AUX */
        !           836: #endif /* ultrix */
        !           837: 
        !           838: /* Initialize the setuid package. */
        !           839: /* Change to the user's real user and group id. */
        !           840: /* If this can't be done, don't run at all. */
        !           841: 
        !           842:     if (x = priv_ini()) {
        !           843:        if (x | 1) fprintf(stderr,"Fatal: setuid failure.\n");
        !           844:        if (x | 2) fprintf(stderr,"Fatal: setgid failure.\n");
        !           845:        if (x | 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
        !           846:        exit(1);
        !           847:     }
        !           848:     return(0);
        !           849: }
        !           850: 
        !           851: /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
        !           852: 
        !           853: int
        !           854: syscleanup() {
        !           855: #ifdef ultrix
        !           856:     stty(0,&vanilla);                   /* Get sgtty info */
        !           857:     fcntl(0,F_SETFL,iniflags);         /* Restore flags */
        !           858: #endif /* ultrix */
        !           859:     /* No need to call anything in the suid package here, right? */
        !           860:     return(0);
        !           861: }
        !           862: 
        !           863: /*
        !           864:   Major change in 5A(174).  We used to use LPASS8, if it was defined, in all
        !           865:   versions except ENCORE, to allow 8-bit data and Xon/Xoff flow control at the
        !           866:   same time.  But this LPASS8 business seems to have been causing trouble for
        !           867:   everybody but me!  For example, Annex terminal servers, commonly used with
        !           868:   Encore computers, do not support LPASS8 even though the Encore itself does.
        !           869:   Now, reportedly, even vanilla 4.3 BSD systems can't do this.  So let's turn
        !           870:   it off for everybody.  That means we goes back to using
        !           871:   raw mode, with no flow control.  Phooey.
        !           872: */
        !           873: #ifdef LPASS8
        !           874: #undef LPASS8
        !           875: #endif /* LPASS8 */
        !           876: 
        !           877: /*  T T O P E N  --  Open a tty for exclusive access.  */
        !           878: 
        !           879: /*
        !           880:   Call with:
        !           881:     ttname: character string - device name or network host name.
        !           882:     lcl:
        !           883:   If called with lcl < 0, sets value of lcl as follows:
        !           884:   0: the terminal named by ttname is the job's controlling terminal.
        !           885:   1: the terminal named by ttname is not the job's controlling terminal.
        !           886:   But watch out: if a line is already open, or if requested line can't
        !           887:   be opened, then lcl remains (and is returned as) -1.
        !           888:     modem:
        !           889:   Less than zero: ttname is a network host name.
        !           890:   Zero or greater: ttname is a terminal device name.    
        !           891:   Zero means a local connection (don't use modem signals).
        !           892:   Positive means use modem signals.  
        !           893:    timo:
        !           894:   0 = no timer.
        !           895:   nonzero = number of seconds to wait for open() to return before timing out.
        !           896: 
        !           897:   Returns:
        !           898:     0 on success
        !           899:    -5 if device is in use
        !           900:    -4 if access to device is denied
        !           901:    -3 if access to lock directory denied
        !           902:    -2 upon timeout waiting for device to open
        !           903:    -1 on other error
        !           904: */
        !           905: static int ttotmo = 0;                 /* Timeout flag */
        !           906: /* Flag kept here to avoid being clobbered by longjmp.  */
        !           907: 
        !           908: int
        !           909: ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
        !           910: 
        !           911: #ifdef SVORPOSIX
        !           912: #ifndef CIE
        !           913:     extern char *ctermid();            /* Wish they all had this! */
        !           914: #else                                  /* CIE Regulus */
        !           915: #define ctermid(x) strcpy(x,"")
        !           916: #endif /* CIE */
        !           917: #endif /* SVORPOSIX */
        !           918: 
        !           919:     char *x;                           /* what's this ? */
        !           920: 
        !           921: #ifndef MINIX
        !           922:     extern char* ttyname();
        !           923: #endif /* MINIX */
        !           924:     char cname[DEVNAMLEN+4];
        !           925: 
        !           926: #define NAMEFD  /* Feature to allow name to be an open file descriptor */
        !           927: 
        !           928: #ifdef NAMEFD
        !           929:     int i, j; char *p;
        !           930: 
        !           931:     debug(F101,"ttopen telnetfd","",telnetfd);
        !           932: #endif /* NAMEFD */
        !           933: 
        !           934:     debug(F111,"ttopen entry modem",ttname,modem);
        !           935:     debug(F101," ttyfd","",ttyfd);
        !           936:     debug(F101," lcl","",*lcl);
        !           937: 
        !           938:     if (ttyfd > -1) {                  /* if device already opened */
        !           939:         if (strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
        !           940:           ttclos(ttyfd);               /* no, close old ttname, open new */
        !           941:         else                           /* else same, ignore this call, */
        !           942:          return(0);                    /* and return. */
        !           943:     }
        !           944: 
        !           945: #ifdef NETCONN
        !           946:     if (modem < 0) {                   /* modem < 0 = special code for net */
        !           947:        int x;
        !           948:        ttmdm = modem;
        !           949:        modem = -modem;                 /* Positive network type number */
        !           950:        fdflag = 0;                     /* Stdio not redirected. */
        !           951:        netconn = 1;                    /* And it's a network connection */
        !           952:        debug(F111,"ttopen net",ttname,modem);
        !           953: #ifdef NAMEFD
        !           954:        for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
        !           955:        if (*p == '\0') {
        !           956:            ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
        !           957:            ttfdflg = 1;                /* We got an open file descriptor */
        !           958:            debug(F111,"ttopen got open network fd",ttname,ttyfd);
        !           959:            strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
        !           960:            x = 1;                      /* Return code is "good". */
        !           961:            if (telnetfd) {
        !           962:                ttnet = NET_TCPB;
        !           963:                ttnproto = NP_TELNET;
        !           964: #ifdef SUNX25
        !           965:            } else if (x25fd) {
        !           966:                ttnet = NET_SX25;
        !           967:                ttnproto = NP_NONE;
        !           968: #endif /* SUNX25 */            
        !           969:            }
        !           970:        } else {                        /* Host name or address given */
        !           971: #endif /* NAMEFD */
        !           972:            x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
        !           973:            if (x > -1) {
        !           974:                strncpy(ttnmsv,ttname,DEVNAMLEN);
        !           975:            } else netconn = 0;
        !           976: #ifdef NAMEFD
        !           977:        }
        !           978: #endif /* NAMEFD */
        !           979: 
        !           980: #ifdef sony_news                       /* Sony NEWS */
        !           981:        if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
        !           982:            perror("ttopen error getting Kanji mode (network)");
        !           983:            debug(F111,"ttopen error getting Kanji mode","network",0);
        !           984:            km_ext = -1;                /* Make sure this stays undefined. */
        !           985:        }
        !           986: #endif /* sony_news */
        !           987: 
        !           988:        xlocal = *lcl = 1;              /* Network connections are local. */
        !           989:        debug(F101,"ttopen net x","",x);
        !           990: 
        !           991:        if (x > -1 && !x25fd)
        !           992:          x = tn_ini();                 /* Initialize TELNET protocol */
        !           993:        return(x);
        !           994:     } else {                           /* Terminal device */
        !           995: #endif /* NETCONN */
        !           996: 
        !           997: #ifdef NAMEFD
        !           998: /*
        !           999:   This code lets you give Kermit an open file descriptor for a serial
        !          1000:   communication device, rather than a device name.  Kermit assumes that the
        !          1001:   line is already open, locked, conditioned with the right parameters, etc.
        !          1002: */
        !          1003:        for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
        !          1004:        if (*p == '\0') {
        !          1005:            ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
        !          1006:            debug(F111,"ttopen got open fd",ttname,ttyfd);
        !          1007:            strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
        !          1008:            xlocal = *lcl = 1;          /* Assume it's local. */
        !          1009:            netconn = 0;                /* Assume it's not a network. */
        !          1010:            tvtflg = 0;                 /* Might need to initialize modes. */
        !          1011:            ttmdm = modem;              /* Remember modem type. */
        !          1012:            fdflag = 0;                 /* Stdio not redirected. */
        !          1013:            ttfdflg = 1;                /* Flag we were opened this way. */
        !          1014: 
        !          1015: #ifdef sony_news                       /* Sony NEWS */
        !          1016:            /* Get device Kanji mode */
        !          1017:            if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
        !          1018:                perror("ttopen error getting Kanji mode");
        !          1019:                debug(F101,"ttopen error getting Kanji mode","",0);
        !          1020:                km_ext = -1;            /* Make sure this stays undefined. */
        !          1021:            }
        !          1022: #endif /* sony_news */
        !          1023:            return(0);                  /* Return success */
        !          1024:        }
        !          1025: #endif /* NAMEFD */
        !          1026: #ifdef NETCONN
        !          1027:     }
        !          1028: #endif /* NETCONN */
        !          1029: 
        !          1030: /* Here we have to open a serial device of the given name. */
        !          1031: 
        !          1032:     occt = signal(SIGINT, cctrap);     /* Set Control-C trap, save old one */
        !          1033: 
        !          1034:     tvtflg = 0;                        /* Flag for use by ttvt(). */
        !          1035:                                /* 0 = ttvt not called yet for this device */
        !          1036: 
        !          1037:     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
        !          1038:     debug(F101,"ttopen fdflag","",fdflag);
        !          1039: 
        !          1040:     ttmdm = modem;                      /* Make this available to other fns */
        !          1041:     xlocal = *lcl;                      /* Make this available to other fns */
        !          1042: 
        !          1043: /* Code for handling bidirectional tty lines goes here. */
        !          1044: /* Use specified method for turning off logins and suppressing getty. */
        !          1045: 
        !          1046: #ifdef ACUCNTRL
        !          1047:     /* Should put call to priv_on() here, but that would be very risky! */
        !          1048:     acucntrl("disable",ttname);         /* acucntrl() program. */
        !          1049:     /* and priv_off() here... */
        !          1050: #else
        !          1051: #ifdef ATT7300
        !          1052:     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
        !          1053:       attmodem |= offgetty(ttname);    /* Remember response.  */
        !          1054: #endif /* ATT7300 */
        !          1055: #endif /* ACUCNTRL */
        !          1056: 
        !          1057: /*
        !          1058:  In the following section, we open the tty device for read/write.
        !          1059:  If a modem has been specified via "set modem" prior to "set line"
        !          1060:  then the O_NDELAY parameter is used in the open, provided this symbol
        !          1061:  is defined (e.g. in fcntl.h), so that the program does not hang waiting
        !          1062:  for carrier (which in most cases won't be present because a connection
        !          1063:  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
        !          1064:  would make more sense to first determine if the line is local before
        !          1065:  doing this, but because ttyname() requires a file descriptor, we have
        !          1066:  to open it first.  See do_open().
        !          1067: 
        !          1068:  Now open the device using the desired treatment of carrier.
        !          1069:  If carrier is REQUIRED, then open could hang forever, so an optional
        !          1070:  timer is provided.  If carrier is not required, the timer should never
        !          1071:  go off, and should do no harm...
        !          1072: */
        !          1073:     ttotmo = 0;                                /* Flag no timeout */
        !          1074:     saval = signal(SIGALRM,timerh);    /* Timed, set up timer. */
        !          1075:     if (timo > 0) {
        !          1076:        alarm(timo);                    /* Timed open() */
        !          1077:        if (setjmp(sjbuf)) {
        !          1078:            ttotmo = 1;                 /* Flag timeout. */
        !          1079:        } else ttyfd = do_open(ttname);
        !          1080:        ttimoff();
        !          1081:        debug(F111,"ttopen","modem",modem);
        !          1082:        debug(F101," ttyfd","",ttyfd);
        !          1083:        debug(F101," alarm return","",ttotmo);
        !          1084:     } else ttyfd = do_open(ttname);
        !          1085:     debug(F111,"ttopen ttyfd",ttname,ttyfd);
        !          1086:     if (ttyfd < 0) {                   /* If couldn't open, fail. */
        !          1087: #ifdef ATT7300
        !          1088:        if (attmodem & DOGETY)          /* was getty(1m) running before us? */
        !          1089:          ongetty(ttnmsv);              /* yes, restart on tty line */
        !          1090:        attmodem &= ~DOGETY;            /* no phone in use, getty restored */
        !          1091: #else
        !          1092: #if ACUCNTRL
        !          1093:         /* Should put call to priv_on() here, but that would be risky! */
        !          1094:        acucntrl("enable",ttname);      /* acucntrl() program. */       
        !          1095:        /* and priv_off() here... */
        !          1096: #endif /* ACUNTRL */
        !          1097: #endif /* ATT7300 */
        !          1098: 
        !          1099:        signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
        !          1100:        if (errno == EACCES) {          /* Device is protected against user */
        !          1101:            perror(ttname);             /* Print message */
        !          1102:            debug(F111,"ttopen tty access denied",ttname,errno);
        !          1103:            return(-4);
        !          1104:        } else return(ttotmo ? -2 : -1);
        !          1105:     }
        !          1106: 
        !          1107:     /* Make sure it's a real tty. */
        !          1108:     if (!isatty(ttyfd)) {
        !          1109:        fprintf(stderr,"%s is not a tty!\n",ttname);
        !          1110:        debug(F110,"ttopen not a tty",ttname,0);
        !          1111:        close(ttyfd);
        !          1112:        ttyfd = -1;
        !          1113:        signal(SIGINT,occt);
        !          1114:        return(-1);
        !          1115:     }
        !          1116: 
        !          1117: #ifdef aegis
        !          1118:        /* Apollo C runtime claims that console pads are tty devices, which
        !          1119:         * is reasonable, but they aren't any good for packet transfer. */
        !          1120:        ios_$inq_type_uid((short)ttyfd, ttyuid, st);
        !          1121:        if (st.all != status_$ok) {
        !          1122:            fprintf(stderr, "problem getting tty object type: ");
        !          1123:            error_$print(st);
        !          1124:        } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
        !          1125:            close(ttyfd); ttyfd = -1;
        !          1126:            errno = ENOTTY; perror(ttname);
        !          1127:            signal(SIGINT,occt);
        !          1128:            return(-1);
        !          1129:        }
        !          1130: #endif /* aegis */
        !          1131: 
        !          1132:     strncpy(ttnmsv,ttname,DEVNAMLEN);   /*  Keep copy of name locally. */
        !          1133: 
        !          1134: /* Caller wants us to figure out if line is controlling tty */
        !          1135: 
        !          1136:     if (*lcl < 0) {
        !          1137:        int x0 = 0, x1 = 0;
        !          1138:         if (strcmp(ttname,CTTNAM) == 0) {   /* "/dev/tty" always remote */
        !          1139:             xlocal = 0;
        !          1140:            debug(F111," ttname=CTTNAM",ttname,xlocal);
        !          1141: 
        !          1142:     /* If any of 0, 1, or 2 not redirected, we can use ttyname() to get */
        !          1143:     /* the name of the controlling terminal... */
        !          1144: 
        !          1145:         } else if ((x0 = isatty(0)) || (x1 = isatty(1)) || isatty(2)) {
        !          1146: #ifndef MINIX
        !          1147:            if (x0)
        !          1148:              x = ttyname(0);           /* and compare it with the */
        !          1149:            else if (x1)                /* tty device name. */
        !          1150:              x = ttyname(1);
        !          1151:            else x = ttyname(2);
        !          1152:             strncpy(cname,x,DEVNAMLEN); /* (copy from internal static buf) */
        !          1153:            debug(F110," cname",x,0);
        !          1154:             x = ttyname(ttyfd);         /* Gat real name of ttname. */
        !          1155:             xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;        /* Compare. */
        !          1156:            debug(F111," ttyname",x,xlocal);
        !          1157: #else
        !          1158:            xlocal = 1;                 /* Can't do this test in MINIX */
        !          1159: #endif /* MINIX */
        !          1160:         } else {                        /* Else, if stdin redirected... */
        !          1161: #ifdef SVORPOSIX
        !          1162: /* System V provides nice ctermid() function to get name of controlling tty */
        !          1163:             ctermid(cname);             /* Get name of controlling terminal */
        !          1164:             debug(F110," ctermid",cname,0);
        !          1165:             x = ttyname(ttyfd);         /* Compare with name of comm line. */
        !          1166:             xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
        !          1167:             debug(F111," ttyname",x,xlocal);
        !          1168: #else
        !          1169: /* Just assume local */
        !          1170:             xlocal = 1;
        !          1171: #endif /* SVORPOSIX */
        !          1172:             debug(F101," redirected stdin","",xlocal);
        !          1173:         }
        !          1174:     }
        !          1175: 
        !          1176: /* Note, the following code was added so that Unix "idle-line" snoopers */
        !          1177: /* would not think Kermit was idle when it was transferring files, and */
        !          1178: /* maybe log people out. */
        !          1179:     if (xlocal == 0) {                 /* Remote mode */
        !          1180:        if (fdflag == 0) {              /* Standard i/o is not redirected */
        !          1181:            debug(F100,"ttopen setting ttyfd = 0","",0);
        !          1182:            close(ttyfd);               /* Use file descriptor 0 */
        !          1183:            ttyfd = 0;
        !          1184:        } else {                        /* Standard i/o is redirected */
        !          1185:            debug(F101,"ttopen stdio redirected","",ttyfd);
        !          1186:        }
        !          1187:     }
        !          1188: 
        !          1189: /* Now check if line is locked -- if so fail, else lock for ourselves */
        !          1190: /* Note: After having done this, don't forget to delete the lock if you */
        !          1191: /* leave ttopen() with an error condition. */
        !          1192: 
        !          1193:     lkf = 0;                            /* Check lock */
        !          1194:     if (xlocal > 0) {
        !          1195:        int xx; int xpid;
        !          1196:         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
        !          1197:             debug(F111,"ttopen ttlock fails",ttname,xx);
        !          1198:             close(ttyfd);              /* Close the device. */
        !          1199:            ttyfd = -1;                 /* Erase its file descriptor. */
        !          1200:            signal(SIGINT,occt);        /* Put old SIGINT back. */
        !          1201:            if (xx == -2) {             /* If lockfile says tty is in use, */
        !          1202:                char *p = malloc(200);  /* print an ls -l listing */
        !          1203:                if (p) {                /* if we can get space... */
        !          1204:                    sprintf(p,"/bin/ls -l %s",flfnam);
        !          1205:                    zsyscmd(p);         /* Get listing. */
        !          1206:                    free(p);            /* free the space */
        !          1207:                    xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
        !          1208:                    priv_off();         /* Turn privs back off. */
        !          1209:                    if (xpid > -1) printf("pid = %d\n",xpid); /* show pid */
        !          1210:                }
        !          1211:                return(-5);             /* Code for device in use */
        !          1212:            } else return(-3);          /* Access denied */
        !          1213:         } else lkf = 1;
        !          1214:     }
        !          1215: 
        !          1216: /* Got the line, now set the desired value for local. */
        !          1217: 
        !          1218:     if (*lcl != 0) *lcl = xlocal;
        !          1219: 
        !          1220: /* Some special stuff for v7... */
        !          1221: 
        !          1222: #ifdef  V7
        !          1223: #ifndef MINIX
        !          1224:     if (kmem[TTY] < 0) {               /*  If open, then skip this.  */
        !          1225:        qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
        !          1226:        if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
        !          1227:            fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
        !          1228:            perror("/dev/kmem");
        !          1229:            exit(1);
        !          1230:        }
        !          1231:     }
        !          1232: #endif /* !MINIX */
        !          1233: #endif /* V7 */
        !          1234: 
        !          1235: /* No failure returns after this point */
        !          1236: 
        !          1237: #ifdef ultrix
        !          1238: #ifdef TIOCSINUSE
        !          1239:     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
        !          1240:        fprintf(stderr, "Can't set in-use flag on modem.\n");
        !          1241:        perror("TIOCSINUSE");
        !          1242:     }
        !          1243: #endif /* TIOCSINUSE */
        !          1244: #endif /* ultrix */
        !          1245: 
        !          1246: /* Get tty device settings */
        !          1247: 
        !          1248: #ifdef ATTSV                           /* AT&T UNIX */
        !          1249:     ioctl(ttyfd,TCGETA,&ttold);
        !          1250:     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
        !          1251:     ioctl(ttyfd,TCGETA,&ttraw);
        !          1252:     ioctl(ttyfd,TCGETA,&tttvt);
        !          1253: #else
        !          1254: #ifdef POSIX                           /* POSIX */
        !          1255:     tcgetattr(ttyfd,&ttold);
        !          1256:     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
        !          1257:     tcgetattr(ttyfd,&ttraw);
        !          1258:     tcgetattr(ttyfd,&tttvt);
        !          1259: #else                                  /* BSD, V7, and all others */
        !          1260:     gtty(ttyfd,&ttold);
        !          1261:     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
        !          1262: 
        !          1263: #ifdef sony_news                       /* Sony NEWS */
        !          1264:     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
        !          1265:        perror("ttopen error getting Kanji mode");
        !          1266:        debug(F101,"ttopen error getting Kanji mode","",0);
        !          1267:        km_ext = -1;                    /* Make sure this stays undefined. */
        !          1268:     }
        !          1269: #endif /* sony_news */
        !          1270: 
        !          1271: #ifdef TIOCGETC
        !          1272:     tcharf = 0;                                /* In remote mode, also get */
        !          1273:     if (xlocal == 0) {                 /* special characters */
        !          1274:        if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
        !          1275:            debug(F100,"ttopen TIOCGETC failed","",0);
        !          1276:        } else {
        !          1277:            tcharf = 1;                 /* It worked. */
        !          1278:            ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
        !          1279:            debug(F100,"ttopen TIOCGETC ok","",0);
        !          1280:        }
        !          1281:     }  
        !          1282: #else
        !          1283:     debug(F100,"ttopen TIOCGETC not defined","",0);
        !          1284: #endif /* TIOCGETC */
        !          1285: 
        !          1286: #ifdef TIOCGLTC
        !          1287:     ltcharf = 0;                       /* In remote mode, also get */
        !          1288:     if (xlocal == 0) {                 /* local special characters */
        !          1289:        if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
        !          1290:            debug(F100,"ttopen TIOCGLTC failed","",0);
        !          1291:        } else {
        !          1292:            ltcharf = 1;                /* It worked. */
        !          1293:            ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
        !          1294:            debug(F100,"ttopen TIOCGLTC ok","",0);
        !          1295:        }
        !          1296:     }  
        !          1297: #else
        !          1298:     debug(F100,"ttopen TIOCGLTC not defined","",0);
        !          1299: #endif /* TIOCGLTC */
        !          1300: 
        !          1301: #ifdef TIOCLGET
        !          1302:     lmodef = 0;
        !          1303:     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
        !          1304:        debug(F100,"ttopen TIOCLGET failed","",0);
        !          1305:     } else {
        !          1306:        lmodef = 1;
        !          1307:        debug(F100,"ttopen TIOCLGET ok","",0);
        !          1308:     }
        !          1309: #endif /* TIOCLGET */
        !          1310: 
        !          1311:     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
        !          1312:     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
        !          1313: 
        !          1314: #endif /* POSIX */
        !          1315: #endif /* ATTSV */
        !          1316: 
        !          1317: /* Section for changing line discipline.  It's restored in ttres(). */
        !          1318: 
        !          1319: #ifdef BSD41
        !          1320: /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
        !          1321:     { int k;
        !          1322:       ioctl(ttyfd, TIOCGETD, &ttld);   /* Get and save line discipline */
        !          1323:       debug(F101,"4.1bsd line discipline","",ttld);
        !          1324:       k = OTTYDISC;                    /* Switch to "old" discipline */
        !          1325:       k = ioctl(ttyfd, TIOCSETD, &k);
        !          1326:       debug(F101,"4.1bsd tiocsetd","",k);
        !          1327:     }
        !          1328: #endif /* BSD41 */
        !          1329: 
        !          1330: #ifdef aegis
        !          1331:     /* This was previously done before the last two TCGETA or gtty above,
        !          1332:      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
        !          1333:      * one copy if it here instead, give us a shout!
        !          1334:      */
        !          1335:     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
        !          1336:     if (xlocal) {       /* ignore breaks from local line */
        !          1337:         sio_$control((short)ttyfd, sio_$int_enable, false, st);
        !          1338:         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
        !          1339:     }
        !          1340: #endif /* aegis */
        !          1341: 
        !          1342: #ifdef VXVE
        !          1343:     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
        !          1344:     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
        !          1345:     ioctl(ttyfd,TCSETA,&ttraw);
        !          1346: #endif /* vxve */
        !          1347: 
        !          1348: /* If O_NDELAY was used during open(), then remove it now. */
        !          1349: 
        !          1350: #ifdef O_NDELAY
        !          1351:     if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
        !          1352: 
        !          1353: #ifndef aegis
        !          1354:        if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
        !          1355:            perror("Can't unset O_NDELAY");
        !          1356: #endif /* aegis */
        !          1357:        /* Some systems, notably Xenix (don't know how common this is in
        !          1358:         * other systems), need special treatment to get rid of the O_NDELAY
        !          1359:         * behaviour on read() with respect to carrier presence (i.e. read()
        !          1360:         * returning 0 when carrier absent), even though the above fcntl()
        !          1361:         * is enough to make read() wait for input when carrier is present.
        !          1362:         * This magic, in turn, requires CLOCAL for working when the carrier
        !          1363:         * is absent. But if xlocal == 0, presumably you already have CLOCAL
        !          1364:         * or you have a carrier, otherwise you wouldn't be running this.
        !          1365:         */
        !          1366: #ifdef ATTSV
        !          1367:        if (xlocal) {
        !          1368:            ttraw.c_cflag |= CLOCAL;
        !          1369:            ioctl(ttyfd, TCSETA, &ttraw);
        !          1370:        }
        !          1371: #endif /* ATTSV */
        !          1372: #ifndef SCO3R2
        !          1373: /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
        !          1374:        close( priv_opn(ttname, O_RDWR) ); /* Magic to force change. */
        !          1375: #endif /* SCO3R2 */
        !          1376:     }
        !          1377: #endif /* O_NDELAY */
        !          1378: 
        !          1379: /* Instruct the system how to treat the carrier, and set a few other tty
        !          1380:  * parameters.
        !          1381:  *
        !          1382:  * This also undoes the temporary setting of CLOCAL that may have been done
        !          1383:  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
        !          1384:  * prevent the other end of the line from sitting there talking to itself,
        !          1385:  * producing garbage when the user performs a connect.
        !          1386:  *
        !          1387:  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
        !          1388:  * Now it thinks CLOCAL is always on. It seems the only real solution for
        !          1389:  * Xenix is to switch between the lower and upper case device names.
        !          1390:  *
        !          1391:  * This section may at some future time expand into setting a complete
        !          1392:  * collection of tty parameters, or call a function shared with ttpkt()/
        !          1393:  * ttvt() that does so.  On the other hand, the initial parameters are not
        !          1394:  * that important, since ttpkt() or ttvt() should always fix that before
        !          1395:  * any communication is done.  Well, we'll see...
        !          1396:  */
        !          1397:     if (xlocal) {
        !          1398:        curcarr = -2;
        !          1399:        carrctl(&ttraw, ttcarr == CAR_ON);
        !          1400: 
        !          1401: #ifdef SVORPOSIX
        !          1402:        ttraw.c_lflag &= ~ECHO;
        !          1403:        ttold.c_lflag &= ~ECHO;
        !          1404: #ifdef ATTSV
        !          1405:        ioctl(ttyfd, TCSETA, &ttraw);
        !          1406: #else
        !          1407:        tcsetattr(ttyfd, TCSADRAIN, &ttraw);
        !          1408: #endif /* ATTSV */
        !          1409: 
        !          1410: #else /* BSD, etc */
        !          1411:        ttraw.sg_flags &= ~ECHO;
        !          1412:        ttold.sg_flags &= ~ECHO;
        !          1413:        stty(ttyfd,&ttraw);
        !          1414: #endif /* SVORPOSIX */
        !          1415: /*     ttflui();  This fails some reason  */
        !          1416:     }
        !          1417:     
        !          1418:     /* Get current speed */
        !          1419: 
        !          1420:     ttspeed = ttgspd();
        !          1421:     debug(F101,"ttopen ttspeed","",ttspeed);
        !          1422: 
        !          1423:     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
        !          1424: 
        !          1425:     debug(F101,"ttopen, ttyfd","",ttyfd);
        !          1426:     debug(F101," lcl","",*lcl);
        !          1427:     debug(F111," lock file",flfnam,lkf);
        !          1428:     signal(SIGINT,occt);
        !          1429:     return(0);
        !          1430: }
        !          1431: 
        !          1432: 
        !          1433: /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
        !          1434: 
        !          1435: int
        !          1436: do_open(ttname) char *ttname; {
        !          1437: 
        !          1438: #ifndef        O_NDELAY                        /* O_NDELAY not defined */
        !          1439:     return(priv_opn(ttname,2));
        !          1440: #else                                  /* O_NDELAY defined */
        !          1441: 
        !          1442: #ifdef ATT7300
        !          1443: /*
        !          1444:  Open comms line without waiting for carrier so initial call does not hang
        !          1445:  because state of "modem" is likely unknown at the initial call  -jrd.
        !          1446:  If this is needed for the getty stuff to work, and the open would not work
        !          1447:  without O_NDELAY when getty is still on, then this special case is ok.
        !          1448:  Otherwise, get rid of it. -ske
        !          1449: */
        !          1450:     return(priv_opn(ttname, O_RDWR | O_NDELAY));
        !          1451: 
        !          1452: #else  /* !ATT7300 */
        !          1453: 
        !          1454:     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
        !          1455:   
        !          1456:     return(priv_opn(ttname, O_RDWR | ((ttcarr != CAR_ON) ? O_NDELAY : 0) ));
        !          1457: 
        !          1458: #endif /* !ATT7300 */
        !          1459: #endif /* O_NDELAY */
        !          1460: }
        !          1461: 
        !          1462: /*  T T C L O S  --  Close the TTY, releasing any lock.  */
        !          1463: 
        !          1464: int
        !          1465: ttclos(foo) int foo; {                 /* Arg req'd for signal() prototype */
        !          1466:     int x = 0;
        !          1467: 
        !          1468:     debug(F101,"ttclos ttyfd","",ttyfd);
        !          1469:     if (ttyfd < 0) return(0);           /* Wasn't open. */
        !          1470: 
        !          1471:     if (ttfdflg) return(0);            /* If we got ttyfd from another */
        !          1472:                                        /* process, don't close it. */
        !          1473:     tvtflg = 0;
        !          1474: #ifdef NETCONN
        !          1475:     if (netconn) {                     /* Network connection. */
        !          1476:        debug(F100,"ttclos closing net","",0);
        !          1477:        netclos();                      /* Close it. */
        !          1478:        netconn = 0;
        !          1479:        return(0);
        !          1480:     }
        !          1481: #endif /* NETCONN */
        !          1482: #ifdef FT21
        !          1483:     if (xlocal) ioctl(ttyfd,TIOCHPCL, NULL);
        !          1484: #endif /* FT21 */
        !          1485: #ifdef ultrix
        !          1486:     if (xlocal) ioctl(ttyfd, TIOCNCAR, NULL);
        !          1487: #endif /* ultrix */
        !          1488:     if (xlocal) {
        !          1489:        debug(F100,"ttclos about to call ttunlck","",0);
        !          1490:         if (ttunlck())                  /* Release uucp-style lock */
        !          1491:          fprintf(stderr,"Warning, problem releasing lock\r\n");
        !          1492:        debug(F100,"ttclos about to call ttres","",0);
        !          1493:     }
        !          1494:     if (ttyfd > 0) {
        !          1495:        saval = signal(SIGALRM,timerh); /* Enable timer interrupt. */
        !          1496:        alarm(5);                       /* Allow 5 seconds for this. */
        !          1497:        if (setjmp(sjbuf)) {            /* Timer went off? */
        !          1498:            x = -1;
        !          1499:        } else {                        /* What we're really trying to do */
        !          1500:            if (xlocal) {
        !          1501:                tthang();               /* Hang up first, then... */
        !          1502:                ttres();                /* reset device modes. */
        !          1503:            }
        !          1504:            debug(F101,"ttclos about to call close","",ttyfd);
        !          1505:            close(ttyfd);               /* Close the device. */
        !          1506:            x = 1;
        !          1507:        }
        !          1508:        ttimoff();                      /* Turn off timer. */
        !          1509:        if (x < 0) {
        !          1510:            fprintf(stderr,"?Timed out closing device: %s\n",ttnmsv);
        !          1511:            debug(F100,"ttclos timed out","",0);
        !          1512:        }
        !          1513:     }
        !          1514:     ttyfd = -1;                         /* Invalidate the file descriptor. */
        !          1515: #ifdef sony_news
        !          1516:     km_ext = -1;                       /* Invalidate device's Kanji-mode */
        !          1517: #endif /* sony_news */
        !          1518: 
        !          1519: /* For bidirectional lines, restore getty if it was there before. */
        !          1520: 
        !          1521: #ifdef ACUCNTRL                                /* 4.3BSD acucntrl() method. */
        !          1522:     acucntrl("enable",ttnmsv);         /* Enable getty on the device. */
        !          1523: #else
        !          1524: #ifdef ATT7300                         /* ATT UNIX PC (3B1, 7300) method. */
        !          1525:     if (attmodem & DOGETY)              /* Was getty(1m) running before us? */
        !          1526:       ongetty(ttnmsv);                 /* Yes, restart getty on tty line */
        !          1527:     attmodem &= ~DOGETY;                /* No phone in use, getty restored */
        !          1528: #endif /* ATT7300 */
        !          1529: #endif /* System-dependent getty-restoring methods */
        !          1530: 
        !          1531:     debug(F100,"ttclos done","",0);
        !          1532:     return(0);
        !          1533: }
        !          1534: 
        !          1535: /*  T T H A N G  --  Hangup phone line or network connection.  */
        !          1536: /*
        !          1537:   Returns:
        !          1538:   0 if it does nothing.
        !          1539:   1 if it believes that it hung up successfully.
        !          1540:  -1 if it believes that the hangup attempt failed.
        !          1541: */
        !          1542: 
        !          1543: #define HUPTIME 500                    /* Milliseconds for hangup */
        !          1544: 
        !          1545: int
        !          1546: tthang() {
        !          1547:     int x = 0;                         /* Sometimes used as return code. */
        !          1548: #ifndef POSIX
        !          1549:     int z;                             /* worker */
        !          1550: #endif /* POSIX */
        !          1551: 
        !          1552: #ifdef SVORPOSIX                       /* AT&T, POSIX, HPUX declarations. */
        !          1553:     int spdsav;                                /* for saving speed */
        !          1554: #ifdef HPUX
        !          1555:     mflag dtr_down = 00000000000,
        !          1556:     modem_rtn;
        !          1557:     mflag modem_sav;
        !          1558:     char modem_state[64];
        !          1559: #endif /* HPUX */
        !          1560:     int flags;                         /* fcntl flags */
        !          1561:     unsigned short ttc_save;
        !          1562: #endif /* SVORPOSIX */
        !          1563: 
        !          1564:     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
        !          1565:     if (xlocal < 1) return(0);         /* Don't do this if not local */
        !          1566: 
        !          1567: #ifdef NETCONN
        !          1568:     if (netconn) {                     /* Network connection. */
        !          1569:        if (netclos() < 0) return(-1);  /* Close it */
        !          1570:         tvtflg = 0;
        !          1571:        ttyfd = -1;
        !          1572:         x = 1;
        !          1573:        if (netopen(ttnmsv, &x, ttmdm) < 0) /* Open it again */
        !          1574:          return(-1);
        !          1575:        else 
        !          1576:          return(1);
        !          1577:     }
        !          1578: #endif /* NETCONN */
        !          1579: 
        !          1580: /* From here down, we handle real tty devices. */
        !          1581: 
        !          1582: #ifdef POSIX
        !          1583: /* Should add some error checking here... */
        !          1584:     spdsav = cfgetospeed(&ttcur);      /* Get current speed */
        !          1585:     cfsetospeed(&ttcur,B0);            /* Replace by 0 */
        !          1586:     tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set it */
        !          1587:     msleep(HUPTIME);                   /* Sleep */
        !          1588:     cfsetospeed(&ttcur,spdsav);                /* Restore previous speed */
        !          1589:     tcsetattr(ttyfd,TCSADRAIN,&ttcur);
        !          1590:     return(1);
        !          1591: #endif /* POSIX */
        !          1592: 
        !          1593: #ifdef aegis                           /* Apollo Aegis */
        !          1594:     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
        !          1595:     msleep(HUPTIME);                                   /* pause */
        !          1596:     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
        !          1597:     return(1);
        !          1598: #endif /* aegis */
        !          1599: 
        !          1600: #ifdef ANYBSD                          /* Any BSD version. */
        !          1601:     debug(F100,"tthang BSD style","",0);
        !          1602:     if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */
        !          1603:        debug(F101,"tthang TIOCCDTR fails","",errno);
        !          1604:        return(-1);
        !          1605:     }
        !          1606:     msleep(HUPTIME);                   /* For about 1/2 sec */
        !          1607:     errno = 0;
        !          1608:     x = ioctl(ttyfd,TIOCSDTR,0);       /* Restore DTR */
        !          1609:     if (x < 0) {
        !          1610:        /*
        !          1611:          For some reason, this tends to fail with "no such device or address"
        !          1612:          but the operation still works, probably because of the close/open
        !          1613:          later on.  So let's not scare the user unnecessarily here.
        !          1614:        */
        !          1615:        debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
        !          1616:        x = 1;                          /* Pretend we succeeded */
        !          1617:     } else if (x == 0) x = 1;          /* Success */
        !          1618: #ifdef COMMENT
        !          1619: #ifdef FT21
        !          1620:     ioctl(ttyfd, TIOCSAVEMODES, 0);
        !          1621:     ioctl(ttyfd, TIOCHPCL, 0);
        !          1622:     close(ttyfd);                      /* Yes, must do this twice */
        !          1623:     if ((ttyfd = open(ttnmsv,2)) < 0)  /* on Fortune computers... */
        !          1624:       return(-1);                      /* (but why?) */
        !          1625:     else x = 1;
        !          1626: #endif /* FT21 */
        !          1627: #endif /* COMMENT */
        !          1628:     close(do_open(ttnmsv));            /* Clear i/o error condition */
        !          1629:     errno = 0;
        !          1630: #ifdef COMMENT
        !          1631: /* This is definitely dangerous.  Why was it here? */
        !          1632:     z = ttvt(ttspeed,ttflow);          /* Restore modes. */
        !          1633:     debug(F101,"tthang ttvt returns","",z);
        !          1634:     return(z < 0 ? -1 : 1);
        !          1635: #else
        !          1636:     return(x);
        !          1637: #endif /* COMMENT */
        !          1638: #endif /* ANYBSD */
        !          1639: 
        !          1640: #ifdef ATTSV                           
        !          1641: /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
        !          1642: 
        !          1643: #ifdef HPUX 
        !          1644: /* Hewlett Packard allows explicit manipulation of modem signals. */
        !          1645: 
        !          1646: #ifdef COMMENT
        !          1647: /* Old way... */
        !          1648:     debug(F100,"tthang HP-UX style","",0);
        !          1649:     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
        !          1650:       return(-1);                                 /* oops, can't. */
        !          1651:     msleep(HUPTIME);                              /* Pause half a second. */
        !          1652:     x = 1;                                        /* Set return code */
        !          1653:     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
        !          1654:        if ((modem_rtn & MDCD) != 0)               /* Check if CD is low. */
        !          1655:          x = -1;                                  /* CD didn't drop, fail. */
        !          1656:     } else x = -1;
        !          1657: 
        !          1658:     /* Even if above calls fail, RTS & DTR should be turned back on. */
        !          1659:     modem_rtn = MRTS | MDTR;
        !          1660:     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
        !          1661:     return(x);
        !          1662: #else
        !          1663: /* New way, from Hellmuth Michaelis */
        !          1664:     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
        !          1665:     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
        !          1666:        debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
        !          1667:        return(-1);
        !          1668:     }
        !          1669:     sprintf(modem_state,"%#lx",modem_rtn);
        !          1670:     debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);    
        !          1671:     modem_sav = modem_rtn;             /* save line status */
        !          1672:     modem_rtn &= ~MDTR;                        /* DTR bit down */
        !          1673:     sprintf(modem_state,"%#lx",modem_rtn);
        !          1674:     debug(F110,"tthang HP-UX: modem lines lowerd DTR = ",modem_state,0);    
        !          1675:     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
        !          1676:        debug(F100,"tthang HP-UX: can't lower DTR!","",0);
        !          1677:        return(-1);                     /* oops, can't. */
        !          1678:     }
        !          1679:     msleep(HUPTIME);                   /* Pause half a second. */
        !          1680:     x = 1;                             /* Set return code */
        !          1681:     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
        !          1682:        sprintf(modem_state,"%#lx",modem_rtn);
        !          1683:        debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);    
        !          1684:        if ((modem_rtn & MDCD) != 0) {  /* Check if CD is low. */
        !          1685:            debug(F100,"tthang HP-UX: DCD didn't get down!","",0);
        !          1686:            x = -1;                     /* CD didn't drop, fail. */
        !          1687:        } else {
        !          1688:            debug(F100,"tthang HP-UX: DCD down!","",0);
        !          1689:        }
        !          1690:     } else {
        !          1691:        x = -1;
        !          1692:        debug(F100,"tthang HP-UX: can't get DCD status !","",0);
        !          1693:     }
        !          1694: 
        !          1695:     /* Even if above calls fail, RTS & DTR should be turned back on. */
        !          1696: 
        !          1697:     modem_sav |= (MRTS | MDTR);
        !          1698:     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
        !          1699:        x = -1;
        !          1700:        debug(F100,"tthang HP-UX: can't set saved state |=(RTS | DTR)","",0);
        !          1701:     } else {
        !          1702:        sprintf(modem_state,"%#lx",modem_sav);
        !          1703:        debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);    
        !          1704:     }          
        !          1705:     return(x);
        !          1706: #endif /* COMMENT */
        !          1707: 
        !          1708: #else /* AT&T but not HP-UX */
        !          1709: 
        !          1710: /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
        !          1711: /* It is not known how many, if any, systems actually implement them, */
        !          1712: /* so we include them here in ifdef's. */
        !          1713: 
        !          1714: #ifdef TIOCMBIS                                /* Bit Set */
        !          1715: #ifdef TIOCMBIC                                /* Bit Clear */
        !          1716: #ifdef TIOCM_DTR                       /* DTR */
        !          1717: 
        !          1718: /* Clear DTR, sleep 300 msec, turn it back on. */
        !          1719: /* If any of the ioctl's return failure, go on to the next section. */
        !          1720: 
        !          1721:     z = TIOCM_DTR;                     /* Code for DTR. */
        !          1722: #ifdef TIOCM_RTS                       /* Lower RTS too if symbol is known. */
        !          1723: #ifndef _IBMR2                         /* Don't do this on RS/6000... */
        !          1724:     z |= TIOCM_RTS;                    
        !          1725: #endif /* _IBMR2 */                    /* or DTR will never come up again. */
        !          1726: #endif /* TIOCM_RTS */
        !          1727: 
        !          1728:     debug(F101,"tthang TIOCM signal mask","",z);
        !          1729: #ifndef _IBMR2
        !          1730: /* SVID says the argument must be a pointer to an int. */
        !          1731:     if (ioctl(ttyfd,TIOCMBIC,&z) > -1)
        !          1732: #else
        !          1733: /* Reportedly, the RS/6000 requires an int, not a pointer. */
        !          1734:     if (ioctl(ttyfd,TIOCMBIC,z) > -1)
        !          1735: #endif /* _IBMR2 */
        !          1736:       { /* Try to lower DTR. */
        !          1737:        debug(F100,"tthang TIOCMBIC ok","",0);
        !          1738:        msleep(HUPTIME);                   /* Pause half a second. */
        !          1739: #ifndef _IBMR2
        !          1740:        if (ioctl(ttyfd,TIOCMBIS,&z) > -1) /* Try to turn it back on. */
        !          1741: #else
        !          1742:        if (ioctl(ttyfd,TIOCMBIS,z) > -1)
        !          1743: #endif /* _IBMR2 */
        !          1744:          {
        !          1745:            debug(F100,"tthang TIOCMBIS ok","",0);
        !          1746:            return(1);                  /* Success, done. */
        !          1747:        } else {                        /* Couldn't raise, continue. */
        !          1748:            debug(F101,"tthang TIOCMBIS errno","",errno);
        !          1749:        }
        !          1750:     } else {                           /* Couldn't lower, continue. */
        !          1751:        debug(F101,"tthang TIOCMBIC errno","",errno);
        !          1752:     }
        !          1753: #endif /* TIOCM_DTR */
        !          1754: #endif /* TIOCMBIC */
        !          1755: #endif /* TIOCMBIS */
        !          1756: 
        !          1757: /*
        !          1758:   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
        !          1759:   two AT&T-based systems seem to do this the same way.  The object is simply
        !          1760:   to turn off DTR and then turn it back on.  SVID says the universal method
        !          1761:   for turning off DTR is to set the speed to zero, and this does seem to do
        !          1762:   the trick in all cases.  But neither SVID nor any known man pages say how to
        !          1763:   turn DTR back on again.  Some variants, like most Xenix implementations,
        !          1764:   raise DTR again when the speed is restored to a nonzero value.  Others
        !          1765:   require the device to be closed and opened again, but this is risky because
        !          1766:   getty could seize the device during the instant it is closed.
        !          1767: */
        !          1768: 
        !          1769: /* Return code for ioctl failures... */
        !          1770: #ifdef ATT6300
        !          1771:     x = 1;                             /* ATT6300 doesn't want to fail... */
        !          1772: #else
        !          1773:     x = -1;
        !          1774: #endif /* ATT6300 */
        !          1775: 
        !          1776:     debug(F100,"tthang get settings","",0);
        !          1777:     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
        !          1778:       return(x);                       /* Fail if this doesn't work. */
        !          1779:     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
        !          1780:       return(x);
        !          1781:     ttc_save = ttcur.c_cflag;          /* Remember current speed. */
        !          1782:     spdsav = ttc_save & CBAUD;
        !          1783:     debug(F101,"tthang speed","",spdsav);
        !          1784: 
        !          1785: #ifdef O_NDELAY
        !          1786:     debug(F100,"tthang O_NDELAY on","",0);
        !          1787:     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
        !          1788: #endif /* O_NDELAY */
        !          1789: 
        !          1790: #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
        !          1791:     ttcur.c_cflag &= ~CBAUD;           /* Change the speed to zero.  */
        !          1792: #else
        !          1793: #ifdef RTAIX
        !          1794:     ttcur.c_cflag &= ~CBAUD;           /* Change the speed to zero.  */
        !          1795: #else          /* This way really works but may be dangerous */
        !          1796: #ifdef u3b2
        !          1797:     ttcur.c_cflag = ~(CBAUD|CLOCAL);   /* Special for AT&T 3B2s */
        !          1798:                                        /* (CLOCAL must be OFF) */
        !          1799: #else
        !          1800: #ifdef SCO3R2                          /* SCO UNIX 3.2 */
        !          1801: /*
        !          1802:   This is complete nonsense, but an SCO user claimed this change made
        !          1803:   hanging up work.  Comments from other SCO UNIX 3.2 users would be 
        !          1804:   appreciated.
        !          1805: */
        !          1806:     ttcur.c_cflag = CBAUD|B0;
        !          1807: #else                                  /* None of the above. */
        !          1808:     ttcur.c_cflag = CLOCAL|HUPCL;      /* Change all but these to zero */
        !          1809:                                        /* (CLOCAL must be ON) */
        !          1810: #endif /* SCO3R2 */
        !          1811: #endif /* u3b2 */
        !          1812: #endif /* RTAIX */
        !          1813: #endif /* ATT7300 */
        !          1814: 
        !          1815: #ifdef COMMENT
        !          1816:     /* and if none of those work, try one of these... */
        !          1817:     ttcur.c_cflag = 0;
        !          1818:     ttcur.c_cflag = CLOCAL;
        !          1819:     ttcur.c_cflag &= ~(CBAUD|HUPCL);
        !          1820:     ttcur.c_cflag &= ~(CBAUD|CREAD);
        !          1821:     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
        !          1822:     /* or other combinations */
        !          1823: #endif /* COMMENT */
        !          1824: 
        !          1825: #ifdef TCXONC
        !          1826:     debug(F100,"tthang TCXONC","",0);
        !          1827:     ioctl(ttyfd, TCXONC, 1);
        !          1828: #endif /* TCXONC */
        !          1829: 
        !          1830: #ifdef TIOCSTART
        !          1831:     debug(F100,"tthang TIOCSTART","",0);
        !          1832:     ioctl(ttyfd, TIOCSTART, 0);
        !          1833: #endif /* TIOCSTART */
        !          1834: 
        !          1835:     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
        !          1836:        fcntl(ttyfd, F_SETFL, flags);   /* Restore flags */
        !          1837:        return(-1);                     /* before returning. */
        !          1838:     }
        !          1839:     msleep(300);                       /* Give modem time to notice. */
        !          1840: 
        !          1841: /* Now, even though it doesn't say this in SVID or any man page, we have */
        !          1842: /* to close and reopen the device.  This is not necessary for all systems, */
        !          1843: /* but it's impossible to predict which ones need it and which ones don't. */
        !          1844: 
        !          1845: #ifdef ATT7300
        !          1846: /*
        !          1847:   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
        !          1848:   related ioctl's for their internal modems.  attmodem has getty status and 
        !          1849:   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary, 
        !          1850:   but also ruins the file descriptor, and no other phone(7) ioctl call can fix 
        !          1851:   it.  Whateverit does, it seems to escape detection with PIOCGETA and TCGETA.
        !          1852:   The only way to undo the damage is to close the fd and then reopen it.
        !          1853: */
        !          1854:     if (attmodem & ISMODEM) {
        !          1855:        debug(F100,"tthang attmodem close/open","",0);
        !          1856:        ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
        !          1857:        ioctl(ttyfd,PIOCDISC,&dialer);  /* Disconnect phone. */
        !          1858:        close(ttyfd);                   /* Close and reopen the fd. */
        !          1859:        ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
        !          1860:        attmodem &= ~ISMODEM;           /* Phone no longer in use. */
        !          1861:     }
        !          1862: #else /* !ATT7300 */
        !          1863: /* It seems we have to close and open the device for other AT&T systems */
        !          1864: /* too, and this is the place to do it.  The following code does the */
        !          1865: /* famous close(open(...)) magic by default.  If that doesn't work for you, */
        !          1866: /* then try uncommenting the following statement or putting -DCLSOPN in */
        !          1867: /* the makefile CFLAGS. */
        !          1868: 
        !          1869: /* #define CLSOPN */
        !          1870: 
        !          1871: #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
        !          1872: 
        !          1873: #ifdef RTAIX                           /* RT AIX needs this too... */
        !          1874: #define CLSOPN
        !          1875: #endif /* RTAIX */
        !          1876: 
        !          1877: #ifdef O_NDELAY
        !          1878: #define OPENFLGS O_RDWR | O_NDELAY
        !          1879: #else
        !          1880: #define OPENFLGS O_RDWR
        !          1881: #endif
        !          1882: 
        !          1883: #ifndef CLSOPN
        !          1884: /* This method is used by default. */
        !          1885: /* It is thought to be safer because there is no window where getty */
        !          1886: /* can seize control of the device.  The drawback is that it might not work. */
        !          1887: 
        !          1888:     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
        !          1889:     close(priv_opn(ttnmsv, OPENFLGS));
        !          1890: 
        !          1891: #else
        !          1892: /* This method is used if you #define CLSOPN.  It is more likely to work */
        !          1893: /* than the previous method, but it's also more dangerous. */
        !          1894: 
        !          1895:     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
        !          1896:     close(ttyfd);
        !          1897:     msleep(10);
        !          1898: #ifdef COMMENT
        !          1899: /* Why did we return? */
        !          1900:     if (ttyfd = priv_opn(ttnmsv, OPENFLGS)) return(1);
        !          1901: #else
        !          1902: /* We still need to restore the flags, etc. */
        !          1903:     ttyfd = priv_opn(ttnmsv, OPENFLGS);
        !          1904: #endif /* COMMENT */
        !          1905: 
        !          1906: #endif /* CLSOPN */
        !          1907: #undef OPENFLGS
        !          1908: 
        !          1909: #endif /* SCO32 */
        !          1910: #endif /* ATT7300 */
        !          1911: 
        !          1912: /* Now put all flags & modes back the way we found them. */
        !          1913: /* (Does the order of ioctl & fcntl matter ? ) */
        !          1914: 
        !          1915:     debug(F100,"tthang restore settings","",0);
        !          1916:     ttcur.c_cflag = ttc_save;          /* Get old speed back. */
        !          1917:     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
        !          1918:       return(-1); 
        !          1919:     if (fcntl(ttyfd,F_SETFL,flags) < 0)        /* fcntl parameters */
        !          1920:       return(-1);
        !          1921: 
        !          1922:     return(1);
        !          1923: #endif /* not HPUX */
        !          1924: #endif /* ATTSV */
        !          1925: }
        !          1926: 
        !          1927: /*  T T R E S  --  Restore terminal to "normal" mode.  */
        !          1928: 
        !          1929: /* [email protected]: There are two choices for what this function should do.
        !          1930:  * (1) Restore the tty to current "normal" mode, with carrier treatment
        !          1931:  * according to ttcarr, to be used after every kermit command. (2) Restore
        !          1932:  * the tty to the state it was in before kermit opened it. These choices
        !          1933:  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
        !          1934:  * is currently being called as in choice (1), but ttold basically holds
        !          1935:  * the initial parameters, as in (2), and the description at the beginning
        !          1936:  * of this file says (2).
        !          1937:  *
        !          1938:  * I don't think restoring tty parameters after all kermit commands makes
        !          1939:  * much of a difference.  Restoring them upon exit from kermit may be of
        !          1940:  * some use in some cases (when the line is not restored automatically on
        !          1941:  * close, by the operating system).
        !          1942:  *
        !          1943:  * I can't choose which one it should be, so I haven't changed it. It
        !          1944:  * probably works as it is, too. It would probably even work even with
        !          1945:  * ttres() entirely deleted...
        !          1946:  *
        !          1947:  * (from fdc: Actually, this function operates in remote mode too, so
        !          1948:  * it restores the console (command) terminal to whatever mode it was
        !          1949:  * in before packet operations began, so that commands work right again.)
        !          1950:  */
        !          1951: int
        !          1952: ttres() {                               /* Restore the tty to normal. */
        !          1953:     int x;
        !          1954: 
        !          1955:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          1956: 
        !          1957:     if (ttfdflg) return(0);            /* Don't mess with terminal modes if */
        !          1958:                                        /* we got ttyfd from another process */
        !          1959: #ifdef NETCONN
        !          1960:     if (netconn) return (0);           /* Network connection, do nothing */
        !          1961: #endif /* NETCONN */
        !          1962: 
        !          1963: /* Real terminal device, so restore its original modes */
        !          1964: 
        !          1965: #ifdef ATTSV                            /* For AT&T versions... */
        !          1966:     x = ioctl(ttyfd,TCSETAW,&ttold);   /* Restore tty modes this way. */
        !          1967: #else
        !          1968: #ifdef POSIX                           /* For POSIX like this */
        !          1969:     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
        !          1970: #else                                  /* For all others... */
        !          1971:     msleep(HUPTIME);                   /* This replaces sleep(1)... */
        !          1972:                                        /* Put back sleep(1) if tty is */
        !          1973:                                        /* messed up after close. */
        !          1974: 
        !          1975: /* Here we restore the modes for BSD */
        !          1976: 
        !          1977: #ifdef LPASS8                          /* Undo "pass8" if it were done */
        !          1978:     if (lmodef) {
        !          1979:        if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
        !          1980:          debug(F100,"ttres TIOCLSET failed","",0);
        !          1981:        else
        !          1982:          debug(F100,"ttres TIOCLSET ok","",0);
        !          1983:     }
        !          1984: #endif /* LPASS8 */
        !          1985: 
        !          1986: #ifdef UTEK                    /* Undo hardware flow if it were done */
        !          1987:     if (lmodef) {
        !          1988:        if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
        !          1989:          debug(F100,"ttres TIOCLSET failed","",0);
        !          1990:        else
        !          1991:          debug(F100,"ttres TIOCLSET ok","",0);
        !          1992:     }
        !          1993: #endif /* UTEK */
        !          1994: 
        !          1995: #ifdef TIOCGETC                                /* Put back special characters */
        !          1996:     if (tcharf && (xlocal == 0)) {
        !          1997:        if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
        !          1998:          debug(F100,"ttres TIOCSETC failed","",0);
        !          1999:        else
        !          2000:          debug(F100,"ttres TIOCSETC ok","",0);
        !          2001:     }
        !          2002: #endif /* TIOCGETC */
        !          2003: 
        !          2004: #ifdef TIOCGLTC                                /* Put back local special characters */
        !          2005:     if (ltcharf && (xlocal == 0)) {
        !          2006:        if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
        !          2007:          debug(F100,"ttres TIOCSLTC failed","",0);
        !          2008:        else
        !          2009:          debug(F100,"ttres TIOCSLTC ok","",0);
        !          2010:     }
        !          2011: #endif /* TIOCGLTC */
        !          2012: 
        !          2013:     x = stty(ttyfd,&ttold);             /* restore tty modes the old way. */
        !          2014: 
        !          2015: #endif /* POSIX */
        !          2016: #endif /* ATTSV */
        !          2017: 
        !          2018:     debug(F101,"ttres tty modes restore","",x);
        !          2019:     if (x < 0) debug(F101,"ttres errno","",errno);
        !          2020: 
        !          2021: #ifdef BSD41
        !          2022:     if (ttld > -1) {                   /* Put back line discipline */
        !          2023:        x = ioctl(ttyfd, TIOCSETD, &ttld);
        !          2024:        debug(F101,"ttres line discipline restore","",x);
        !          2025:        if (x < 0) debug(F101,"...ioctl errno","",errno);
        !          2026:        ttld = -1;
        !          2027:     }
        !          2028: #endif /* BSD41 */
        !          2029: 
        !          2030: #ifdef sony_news
        !          2031:     x = xlocal ? km_ext : km_con;      /* Restore Kanji mode. */
        !          2032:     if (x != -1) {                     /* Make sure we know original modes. */
        !          2033:        if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
        !          2034:            perror("ttres can't set Kanji mode");
        !          2035:            debug(F101,"ttres error setting Kanji mode","",x);
        !          2036:            return(-1);
        !          2037:        }
        !          2038:     }
        !          2039:     debug(F100,"ttres set Kanji mode ok","",0);
        !          2040: #endif /* sony_news */
        !          2041: 
        !          2042:     tvtflg = 0;                                /* Invalidate terminal mode settings */
        !          2043:     return(x);
        !          2044: }
        !          2045: 
        !          2046: /*  T T R P I D  --  Read pid from lockfile "name" (used by ttlock) */
        !          2047: 
        !          2048: int
        !          2049: ttrpid(name) char *name; {
        !          2050:     int x, fd, pid;
        !          2051: 
        !          2052:     fd = open(name,O_RDONLY);          /* Try to open lockfile. */
        !          2053:     if (fd > 0) {
        !          2054: 
        !          2055: #ifdef PIDSTRING
        !          2056:        char buf[12];
        !          2057:        x = read(fd, buf, 11);          /* For HDP UUCP, read pid string */
        !          2058:        if (x < 0) return(-1);
        !          2059:        buf[11] = '\0';
        !          2060:        if (x == 11)
        !          2061:          x = sscanf(buf,"%d",&pid);    /* Get the integer pid from it. */
        !          2062: #else
        !          2063:        x = read(fd, (char *)&pid, sizeof(pid)); /* Else read integer pid */
        !          2064: #endif /* PIDSTRING */
        !          2065: 
        !          2066:        if (x < 0) pid = -1;            /* Return any errors. */
        !          2067:        close(fd);                      /* Close the lockfile. */
        !          2068:     } else pid = -1;
        !          2069:     return(pid);
        !          2070: }
        !          2071: 
        !          2072: /*  T T L O C K  */
        !          2073: 
        !          2074: /*
        !          2075:   This function attempts to coordinate use of the communication device with
        !          2076:   other copies of Kermit and any other program that follows the UUCP
        !          2077:   device-locking conventions, which, unfortunately, vary among different UNIX
        !          2078:   implementations.  The idea is to look for a file of a certain name, the
        !          2079:   "lockfile", in a certain directory.  If such a file is found, then the line
        !          2080:   is presumed to be in use, and Kermit should not use it.  If no such file is
        !          2081:   found, Kermit attempts to create one so that other programs will not use the
        !          2082:   same line at the same time.  Because the lockfile and/or the directory it's
        !          2083:   in might lack write permission for the person running Kermit, Kermit could
        !          2084:   find itself running setuid to uucp or other user that does have the
        !          2085:   necessary permissions.  At startup, Kermit has changed its effective uid to
        !          2086:   the user's real uid, and so ttlock() must switch back to the original
        !          2087:   effective uid in order to create the lockfile, and then back again to the
        !          2088:   real uid to prevent unauthorized access to other directories or files owned
        !          2089:   by the user the program is setuid to.
        !          2090: 
        !          2091:   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
        !          2092:   based on suggestions from Warren Tucker.  Call with pointer to name of 
        !          2093:   tty device.  Returns:
        !          2094: 
        !          2095:    0 on success
        !          2096:   -1 on failure
        !          2097: 
        !          2098:   Note: Once privileges are turned on using priv_on(), it is essential that
        !          2099:   they are turned off again before this function returns.
        !          2100: */
        !          2101: #ifdef SVR4                            /* Lockfile uses device numbers. */
        !          2102: #ifndef LFDEVNO                                /* Define this for SVR4 */
        !          2103: #define LFDEVNO                                /* If anybody else needs it, */
        !          2104: #endif /* LFDEVNO */                   /* define it here or on CC */
        !          2105: #endif /* SVR4 */                      /* command line. */
        !          2106: 
        !          2107: #ifdef LFDEVNO
        !          2108: #include <sys/stat.h>                  /* For major() & minor() macros. */
        !          2109:                                        /* Should be in <sys/types.h>. */
        !          2110: #ifndef major                          /* If we didn't find it */
        !          2111: #ifdef SVR4                            /* then for Sys V R4 */
        !          2112: #include <sys/mkdev.h>                 /* look here */
        !          2113: #else                                  /* or for Sunos versions */
        !          2114: #ifdef SUNOS4                          /* ... */
        !          2115: #include <sys/sysmacros.h>             /* look here */
        !          2116: #else                                  /* Otherwise take a chance: */
        !          2117: #define        major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
        !          2118: #define        minor(dev) ( (int) ( (dev) & 0xff))
        !          2119: #endif /* SUNOS4 */
        !          2120: #endif /* SVR4 */
        !          2121: #endif /* major */
        !          2122: #endif /* LFDEVNO */
        !          2123: /*
        !          2124:   Note for RS/6000: routines ttylock(devicename), ttyunlock(devicename),
        !          2125:   and ttylocked(devicename) from the standard library (libc.a) could be 
        !          2126:   used here instead.  It's not clear whether there is any advantage in this.
        !          2127: */
        !          2128: static int
        !          2129: ttlock(ttdev) char *ttdev; {
        !          2130:     int x;
        !          2131: 
        !          2132: #ifdef MINIX
        !          2133:     char *buf;
        !          2134: #endif /* MINIX */
        !          2135: 
        !          2136: #ifdef NOUUCP
        !          2137:     strcpy(flfnam,"NOLOCK");
        !          2138:     haslock = 1;
        !          2139:     return(0);
        !          2140: #else /* !NOUUCP */
        !          2141:     int lockfd;                                /* File descriptor for lock file. */
        !          2142:     PID_T pid;                         /* Process id of this process. */
        !          2143:     int fpid;                          /* pid found in existing lockfile. */
        !          2144:     int tries;                         /* How many times we've tried... */
        !          2145: #ifdef LFDEVNO
        !          2146:     struct stat devbuf;                        /* For device numbers (SVR4). */
        !          2147: #endif /* LFDEVNO */
        !          2148: 
        !          2149: #ifdef PIDSTRING
        !          2150:     char pid_str[12];                  /* My pid in string format. */
        !          2151: #endif /* PIDSTRING */
        !          2152: 
        !          2153:     char *device, *devname;
        !          2154: 
        !          2155: #define LFNAML 50                      /* Max length for lock file name. */
        !          2156:     char lockfil[LFNAML];              /* Lock file name */
        !          2157: #ifdef RTAIX
        !          2158:     char lklockf[LFNAML];              /* Name for link to lock file  */
        !          2159: #endif
        !          2160:     char tmpnam[LFNAML+30];            /* Temporary lockfile name. */
        !          2161:     char *lockdir = LOCK_DIR;          /* Defined near top of this file, */
        !          2162:                                        /* or on cc command line. */
        !          2163: 
        !          2164:     haslock = 0;                        /* Not locked yet. */
        !          2165:     *flfnam = '\0';                    /* Lockfile name is empty. */
        !          2166:     pid = getpid();                    /* Get id of this process. */
        !          2167: 
        !          2168: /*  Construct name of lockfile and temporary file */
        !          2169: 
        !          2170: /*  device  = name of tty device without the path, e.g. "ttyh8" */
        !          2171: /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
        !          2172: 
        !          2173:     device = ((devname=xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
        !          2174: 
        !          2175: #ifdef ISIII                           /* Interactive System III, PC/IX */
        !          2176:     strcpy(lockfil, device);
        !          2177: #else
        !          2178: #ifdef LFDEVNO                         /* Lockfilename has device numbers. */
        !          2179:     if (stat(ttdev,&devbuf) < 0)
        !          2180:       return(-1);
        !          2181:     sprintf(lockfil,"LK.%03d.%03d.%03d",
        !          2182:            major(devbuf.st_dev),       /* inode */
        !          2183:            major(devbuf.st_rdev),      /* major device number */
        !          2184:            minor(devbuf.st_rdev));     /* minor device number */
        !          2185: 
        !          2186: #else                                  /* Others... */
        !          2187: #ifdef PTX                             /* Dynix PTX */
        !          2188:     if (device != &ttdev[5] && strncmp(ttdev,"/dev/",5)==0) {
        !          2189:        sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
        !          2190:     } else
        !          2191: #endif /* PTX */
        !          2192:     sprintf(lockfil,"LCK..%s", device);
        !          2193: #ifdef M_XENIX                         /* SCO Xenix */
        !          2194:     { int x; char c;
        !          2195:       x = (int)strlen(lockfil) - 1;    /* Get last letter of device name. */
        !          2196:       if (x > 0) {                     /* If it's uppercase, lower it. */
        !          2197:          c = lockfil[x];
        !          2198:          if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
        !          2199:       }
        !          2200:     }
        !          2201: #endif /* M_XENIX */
        !          2202: #ifdef RTAIX
        !          2203:     strcpy(lklockf,device);
        !          2204: #endif /* RTAIX */
        !          2205: #endif /* LFDEVNO */
        !          2206: #endif /* ISIII */
        !          2207: 
        !          2208: /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
        !          2209: /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
        !          2210: 
        !          2211:     sprintf(flfnam,"%s/%s",lockdir,lockfil);
        !          2212: #ifdef RTAIX
        !          2213:     sprintf(lkflfn,"%s/%s",lockdir,lklockf);
        !          2214: #endif
        !          2215:     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid);
        !          2216:     debug(F110,"ttlock flfnam",flfnam,0);
        !          2217:     debug(F110,"ttlock tmpnam",tmpnam,0);
        !          2218: 
        !          2219:     priv_on();                         /* Turn on privileges if possible. */
        !          2220:     lockfd = creat(tmpnam, 0444);      /* Try to create temp lock file. */
        !          2221:     if (lockfd < 0) {                  /* Create failed. */
        !          2222:        debug(F111,"ttlock creat failed",tmpnam,errno);
        !          2223:        if (errno == ENOENT) {
        !          2224:            perror(lockdir);        
        !          2225:            printf("UUCP not installed or Kermit misconfigured\n");
        !          2226:        } else {
        !          2227:            perror(lockdir);
        !          2228:            unlink(tmpnam);             /* Get rid of the temporary file. */
        !          2229:        }
        !          2230:        priv_off();                     /* Turn off privileges!!! */
        !          2231:        return(-1);                     /* Return failure code. */
        !          2232:     }
        !          2233: /* Now write the pid into the temp lockfile in the appropriate format */
        !          2234: 
        !          2235: #ifdef PIDSTRING                       /* For Honey DanBer UUCP, */
        !          2236:     sprintf(pid_str,"%10d\n", (int) pid); /* write pid as decimal string. */
        !          2237:     write(lockfd, pid_str, 11);
        !          2238:     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
        !          2239: #else                                  /* Others use integer pid */
        !          2240:     write(lockfd, (char *)&pid, sizeof(pid) );
        !          2241:     debug(F111,"ttlock pid","",(int) pid);
        !          2242: #endif /* PIDSTRING */
        !          2243: 
        !          2244: /* Now try to rename the temp file to the real lock file name. */
        !          2245: /* This will fail if a lock file of that name already exists.  */
        !          2246: 
        !          2247:     close(lockfd);                     /* Close the temp lockfile. */
        !          2248:     chmod(tmpnam,0444);                        /* Permission for a valid lock. */    
        !          2249:     tries = 0;
        !          2250:     while (!haslock && tries++ < 2) {
        !          2251:        haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
        !          2252:        if (haslock) {                        /* If we got the lockfile */
        !          2253: #ifdef RTAIX
        !          2254:            link(flfnam,lkflfn);
        !          2255: #endif     
        !          2256:            break;                            /* we're done. */
        !          2257:        } else {                              /* Otherwise, */
        !          2258:            if ((fpid = ttrpid(flfnam)) > -1) { /* Read pid from lockfile */
        !          2259:                if (fpid > 0) {
        !          2260:                    debug(F101,"ttlock fpid","",fpid);
        !          2261:                    errno = 0;          /* See if process still exists. */
        !          2262:                    x = kill((PID_T) fpid,0);
        !          2263:                    debug(F101,"ttlock kill","",x);
        !          2264:                    debug(F101,"ttlock kill errno","",errno);
        !          2265:                    if (x < 0 && errno == ESRCH) { /* pid is invalid */
        !          2266:                        debug(F111,"ttlock removing stale lock",flfnam,
        !          2267:                              fpid);
        !          2268:                        if (!backgrd)
        !          2269:                          printf(
        !          2270:                                "Removing stale lock %s (pid %d terminated)\n",
        !          2271:                                 flfnam,fpid);
        !          2272:                        x = unlink(flfnam); /* remove the lockfile. */
        !          2273:                        debug(F111,"ttlock unlink",flfnam,x);
        !          2274:                        continue;       /* and go back and try again. */
        !          2275:                    } else if (x < 0 && errno == EPERM || x == 0) {
        !          2276:                        unlink(tmpnam); /* Delete the tempfile */
        !          2277:                        debug(F101,"ttlock found tty locked","",fpid);
        !          2278:                        priv_off();     /* Turn off privs */
        !          2279:                        return(-2);     /* Code for device is in use. */
        !          2280:                    }
        !          2281:                } else {
        !          2282:                    debug(F101,"ttlock can't get fpid","",fpid);
        !          2283:                    break;
        !          2284:                }
        !          2285:            } else break;
        !          2286:        }
        !          2287:     }
        !          2288:     unlink(tmpnam);                    /* Unlink (remove) the temp file. */
        !          2289:     priv_off();                                /* Turn off privs */
        !          2290:     return(haslock ? 0 : -1);          /* Return link's return code. */
        !          2291: #endif /* !NOUUCP */
        !          2292: }
        !          2293: 
        !          2294: /*  T T U N L O C K  */
        !          2295: 
        !          2296: static int
        !          2297: ttunlck() {                             /* Remove UUCP lockfile. */
        !          2298: #ifndef NOUUCP
        !          2299:     if (haslock && *flfnam) {
        !          2300:        priv_on();                      /* Turn privileges on.  */
        !          2301:        unlink(flfnam);                 /* Remove the lockfile. */
        !          2302: #ifdef RTAIX
        !          2303:        unlink(lkflfn);
        !          2304: #endif
        !          2305:        *flfnam = '\0';                 /* Erase the name. */
        !          2306:        priv_off();                     /* Turn privileges off. */
        !          2307:     }
        !          2308: #endif /* !NOUUCP */
        !          2309:     return(0);
        !          2310: }
        !          2311: 
        !          2312: /* 4.3BSD-style UUCP line direction control (Stan Barber, Rice U) */
        !          2313: 
        !          2314: #ifdef ACUCNTRL
        !          2315: VOID
        !          2316: acucntrl(flag,ttname) char *flag, *ttname; {
        !          2317:     char x[DEVNAMLEN+32], *device, *devname;
        !          2318: 
        !          2319:     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
        !          2320:       return;                          /* just return. */
        !          2321:     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
        !          2322:     if (strncmp(device,"LCK..",4) == 0) device += 5;
        !          2323:     sprintf(x,"/usr/lib/uucp/acucntrl %s %s",flag,device);
        !          2324:     debug(F110,"called ",x,0);
        !          2325:     zsyscmd(x);
        !          2326: }
        !          2327: #endif /* ACUCNTRL */
        !          2328: 
        !          2329: /*  T T P K T  --  Condition the communication line for packets. */
        !          2330: /*              or for modem dialing */
        !          2331: 
        !          2332: #define DIALING 4               /* flags (via flow) for modem handling */
        !          2333: #define CONNECT 5
        !          2334: 
        !          2335: /*  If called with speed > -1, also set the speed.  */
        !          2336: 
        !          2337: /*  Returns 0 on success, -1 on failure.  */
        !          2338: 
        !          2339: int
        !          2340: ttpkt(speed,flow,parity) long speed; int flow, parity; {
        !          2341:     int s2;
        !          2342:     int s = -1;
        !          2343: #ifndef SVORPOSIX
        !          2344:     int x;
        !          2345: #endif /* SVORPOSIX */
        !          2346: 
        !          2347:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          2348: 
        !          2349:     debug(F101,"ttpkt parity","",parity);
        !          2350:     debug(F101,"ttpkt flow","",flow);
        !          2351:     debug(F101,"ttpkt speed","",(int) speed);
        !          2352: 
        !          2353:     ttprty = parity;                    /* Let other tt functions see these. */
        !          2354:     ttpmsk = ttprty ? 0177 : 0377;     /* Parity stripping mask */
        !          2355:     ttspeed = speed;
        !          2356:     ttflow = flow;                     /* Now make this available too. */
        !          2357: 
        !          2358: #ifdef NETCONN                         /* Nothing to do for telnet */
        !          2359:     if (netconn) return (0);
        !          2360: #endif /* NETCONN */
        !          2361: 
        !          2362:     if (ttfdflg && !isatty(ttyfd)) return(0);
        !          2363: 
        !          2364: #ifndef SVORPOSIX                      /* Berkeley, V7, etc. */
        !          2365: #ifdef LPASS8
        !          2366: /*
        !          2367:  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
        !          2368:  after having previously set it to NONE without closing and reopening the
        !          2369:  device.  Unless there's something I overlooked below...
        !          2370: */
        !          2371:     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
        !          2372:        debug(F101,"ttpkt executing horrible flow kludge","",0);
        !          2373:        ttclos(0);                      /* Close it */
        !          2374:        x = 0;
        !          2375:        ttopen(ttnmsv,&x,ttmdm,0);      /* Open it again */
        !          2376:     }
        !          2377: #endif /* LPASS8 */
        !          2378: #endif /* SVORPOSIX */
        !          2379: 
        !          2380:     if (xlocal) {
        !          2381:        s2 = (int) (speed / 10L);       /* Convert bps to cps */
        !          2382:        s = ttsspd(s2);                 /* Check and set the speed */
        !          2383:        debug(F101,"ttpkt carrier","",flow);
        !          2384:        carrctl(&ttraw, flow != DIALING /* Carrier control */
        !          2385:                && (ttcarr == CAR_ON));
        !          2386:        tvtflg = 0;                     /* So ttvt() will work next time */
        !          2387:     }
        !          2388: 
        !          2389: #ifndef SVORPOSIX                              /* BSD section */
        !          2390: #ifdef UTEK
        !          2391:     hardflow(flow);
        !          2392:     if (flow == FLO_NONE || flow == FLO_HARD) /* Something besides Xon/Xoff */
        !          2393: #else
        !          2394:     if (flow == FLO_NONE)              /* No Xon/Xoff flow control */
        !          2395: #endif /* UTEK */
        !          2396:     {
        !          2397:        debug(F100,"ttpkt turning TANDEM off, RAW on","",0);
        !          2398:        ttraw.sg_flags &= ~TANDEM;      /* Don't ask for it. */
        !          2399:        ttraw.sg_flags |= RAW;
        !          2400:     } else if (flow == FLO_XONX) {     /* Xon/Xoff requested. */
        !          2401:        debug(F100,"ttpkt turning on TANDEM","",0);
        !          2402:        ttraw.sg_flags |= TANDEM;       /* So ask for it. */
        !          2403: 
        !          2404: #ifdef LPASS8                          /* Can pass 8-bit data through? */
        !          2405: /* If the LPASS8 local mode is available, then flow control can always  */
        !          2406: /* be used, even if parity is none and we are transferring 8-bit data.  */
        !          2407: /* But we only need to do all this if Xon/Xoff is requested. */
        !          2408: /* BUT... this tends not to work through IP or LAT connections, terminal */
        !          2409: /* servers, telnet, rlogin, etc, so it is not generally used. */
        !          2410:        x = LPASS8;                     /* If LPASS8 defined, then */
        !          2411:        debug(F100,"ttpkt executing LPASS8 code","",0);
        !          2412:        if (lmodef) {                   /* TIOCLBIS must be too. */
        !          2413:            x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
        !          2414:            if (x < 0) {
        !          2415:                debug(F100,"ttpkt TIOCLBIS error","",0);
        !          2416:            } else {
        !          2417:                lmodef++;
        !          2418:                debug(F100,"ttpkt TIOCLBIS ok","",0);
        !          2419:            }
        !          2420:        }
        !          2421: /*
        !          2422:  But if we use LPASS8 mode, we must explicitly turn off
        !          2423:  terminal interrupts of all kinds.
        !          2424: */
        !          2425: #ifdef TIOCGETC                                /* Not rawmode, */
        !          2426:        if (tcharf && (xlocal == 0)) {  /* must turn off */
        !          2427:            tchnoi.t_intrc = -1;        /* interrupt character */
        !          2428:            tchnoi.t_quitc = -1;        /* and quit character. */
        !          2429:            tchnoi.t_startc = 17;       /* Make sure xon */
        !          2430:            tchnoi.t_stopc = 19;        /* and xoff not ignored. */
        !          2431:            if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
        !          2432:                debug(F100,"ttpkt TIOCSETC failed","",0);
        !          2433:            } else {
        !          2434:                tcharf = 1;
        !          2435:                debug(F100,"ttpkt TIOCSETC ok","",0);
        !          2436:            }
        !          2437: #ifdef COMMENT
        !          2438: /* only for paranoid debugging */
        !          2439:            if (tcharf) {
        !          2440:                struct tchars foo;
        !          2441:                char tchbuf[100];
        !          2442:                ioctl(0,TIOCGETC,&foo);
        !          2443:                sprintf(tchbuf,
        !          2444:                    "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
        !          2445:                    foo.t_intrc, foo.t_quitc, foo.t_startc,
        !          2446:                    foo.t_stopc, foo.t_eofc,  foo.t_brkc);
        !          2447:                debug(F110,"ttpkt chars",tchbuf,0);
        !          2448:            }
        !          2449: #endif /* COMMENT */
        !          2450:        }
        !          2451:        ttraw.sg_flags |= CBREAK;       /* Needed for unknown reason */
        !          2452: #endif /* TIOCGETC */
        !          2453: 
        !          2454: /* Prevent suspend during packet mode */
        !          2455: #ifdef TIOCGLTC                                /* Not rawmode, */
        !          2456:        if (ltcharf && (xlocal == 0)) { /* must turn off */
        !          2457:            ltchnoi.t_suspc = -1;       /* suspend character */
        !          2458:            ltchnoi.t_dsuspc = -1;      /* and delayed suspend character */
        !          2459:            if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
        !          2460:                debug(F100,"ttpkt TIOCSLTC failed","",0);
        !          2461:            } else {
        !          2462:                ltcharf = 1;
        !          2463:                debug(F100,"ttpkt TIOCSLTC ok","",0);
        !          2464:            }
        !          2465:        }
        !          2466: #endif /* TIOCGLTC */
        !          2467: 
        !          2468: #else /* LPASS8 not defined */
        !          2469: 
        !          2470: /* Previously, BSD-based implementations always */
        !          2471: /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
        !          2472: /* This allows the flow control requested above to actually work, but only */
        !          2473: /* if the user asks for parity (which also means they get 8th-bit quoting). */
        !          2474: 
        !          2475:        if (parity) {                   /* If parity, */
        !          2476:            ttraw.sg_flags &= ~RAW;     /* use cooked mode */
        !          2477: #ifdef COMMENT
        !          2478: /* WHY??? */
        !          2479:            if (xlocal)
        !          2480: #endif /* COMMENT */
        !          2481:              ttraw.sg_flags |= CBREAK;
        !          2482:            debug(F101,"ttpkt cooked, cbreak, parity","",parity);
        !          2483: #ifdef TIOCGETC                                /* Not rawmode, */
        !          2484:            if (tcharf && (xlocal == 0)) { /* must turn off */
        !          2485:                tchnoi.t_intrc = -1;    /* interrupt character */
        !          2486:                tchnoi.t_quitc = -1;    /* and quit character. */
        !          2487:                tchnoi.t_startc = 17;   /* Make sure xon */
        !          2488:                tchnoi.t_stopc = 19;    /* and xoff not ignored. */
        !          2489:                if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
        !          2490:                    debug(F100,"ttpkt TIOCSETC failed","",0);
        !          2491:                } else {
        !          2492:                    tcharf = 1;
        !          2493:                    debug(F100,"ttpkt TIOCSETC ok","",0);
        !          2494:                }
        !          2495:            }
        !          2496: #endif /* TIOCGETC */
        !          2497: #ifdef TIOCGLTC                                /* Not rawmode, */
        !          2498: /* Prevent suspend during packet mode */
        !          2499:            if (ltcharf && (xlocal == 0)) { /* must turn off */
        !          2500:                ltchnoi.t_suspc = -1;   /* suspend character */
        !          2501:                ltchnoi.t_dsuspc = -1;  /* and delayed suspend character */
        !          2502:                if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
        !          2503:                    debug(F100,"ttpkt TIOCSLTC failed","",0);
        !          2504:                } else {
        !          2505:                    ltcharf = 1;
        !          2506:                    debug(F100,"ttpkt TIOCSLTC ok","",0);
        !          2507:                }
        !          2508:            }
        !          2509: #endif /* TIOCGLTC */
        !          2510:        } else {                        /* If no parity, */
        !          2511:            ttraw.sg_flags |= RAW;      /* must use 8-bit raw mode. */
        !          2512:            debug(F101,"ttpkt setting rawmode, parity","",parity);
        !          2513:        }
        !          2514:     } else {                   /* No Xon/Xoff */
        !          2515:        debug(F101,"ttpkt setting rawmode, flow","",flow);
        !          2516:        ttraw.sg_flags |= RAW;  /* Can use 8-bit raw mode. */
        !          2517: #endif /* LPASS8 */
        !          2518:     }
        !          2519: 
        !          2520:     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
        !          2521: #ifdef LCASE
        !          2522:     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
        !          2523: #else
        !          2524:     ttraw.sg_flags &= ~(ECHO|CRMOD);
        !          2525: #endif /* LCASE */
        !          2526: 
        !          2527: #ifdef TOWER1
        !          2528:     ttraw.sg_flags &= ~ANYP;            /* Must tell Tower no parity */
        !          2529: #endif /* TOWER1 */
        !          2530: 
        !          2531:     if (stty(ttyfd,&ttraw) < 0) return(-1); /* Set the new modes. */
        !          2532:     debug(F100,"ttpkt stty ok","",0);
        !          2533: 
        !          2534: #ifdef sony_news
        !          2535:     x = xlocal ? km_ext : km_con;      /* Put line in ASCII mode. */
        !          2536:     if (x != -1) {                     /* Make sure we know original modes. */
        !          2537:        x &= ~KM_TTYPE;
        !          2538:        x |= KM_ASCII;
        !          2539:        if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
        !          2540:            perror("ttpkt can't set ASCII mode");
        !          2541:            debug(F101,"ttpkt error setting ASCII mode","",x);
        !          2542:            return(-1);
        !          2543:        }
        !          2544:     }
        !          2545:     debug(F100,"ttpkt set ASCII mode ok","",0);
        !          2546: #endif /* sony_news */
        !          2547: 
        !          2548:     if (xlocal == 0)                   /* Turn this off so we can read */
        !          2549:       signal(SIGINT,SIG_IGN);          /* Ctrl-C chars typed at console */
        !          2550: 
        !          2551:     tvtflg = 0;                                /* So ttvt() will work next time */
        !          2552:     return(0);
        !          2553: 
        !          2554: #endif /* Not ATTSV or POSIX */
        !          2555: 
        !          2556: /* AT&T UNIX and POSIX */
        !          2557: 
        !          2558: #ifdef SVORPOSIX
        !          2559:     if (flow == FLO_XONX) ttraw.c_iflag |= (IXON|IXOFF);
        !          2560:     if (flow == FLO_NONE) ttraw.c_iflag &= ~(IXON|IXOFF);
        !          2561:     if (flow == FLO_RTSC) {
        !          2562:        /* RTS/CTS Flow control... */
        !          2563: #ifdef RTSXOFF
        !          2564:        /* This is the preferred way, according to SVID R4 */
        !          2565:        if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
        !          2566:            rctsx.x_hflag |= RTSXOFF | CTSXON;
        !          2567:            ioctl(ttyfd,TCSETX,&rctsx); /* Ignore errors for now. */
        !          2568:        }
        !          2569: #else
        !          2570: #ifdef CRTSCTS
        !          2571:        /* Found this one in <termios.h> */
        !          2572:        ttraw.c_iflag |= CRTSCTS;
        !          2573: #endif /* CRTSCRS */
        !          2574: #endif /* RTSXOFF */
        !          2575:     }
        !          2576:     if (flow == FLO_DTRC) {
        !          2577:        /* DTR/CD Flow control... */
        !          2578: #ifdef DTRXOFF
        !          2579:        /* This is straight out of SVID R3 */
        !          2580:        if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
        !          2581:            rctsx.x_hflag |= DTRXOFF | CDXON;
        !          2582:            ioctl(ttyfd,TCSETX,&rctsx); /* Ignore errors. */
        !          2583:        }
        !          2584: #endif /* DTRXOFF */
        !          2585:     }
        !          2586: 
        !          2587:     ttraw.c_lflag &= ~(ICANON|ECHO);
        !          2588:     ttraw.c_lflag &= ~ISIG;            /* Do NOT check for interrupt chars */
        !          2589:     ttraw.c_lflag |= NOFLSH;           /* Don't flush */
        !          2590:     ttraw.c_iflag |= (BRKINT|IGNPAR);
        !          2591: #ifdef ATTSV
        !          2592:     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
        !          2593: #else /* POSIX */
        !          2594:     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
        !          2595: #endif /* ATTSV */
        !          2596:     ttraw.c_oflag &= ~OPOST;
        !          2597:     ttraw.c_cflag &= ~(CSIZE|PARENB);
        !          2598:     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
        !          2599: #ifdef IX370
        !          2600:     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
        !          2601:     ttraw.c_cc[5] = 1;
        !          2602: #else
        !          2603:     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
        !          2604:     ttraw.c_cc[5] = 0;  /* [VTIME] when this many secs/10 expire w/no input */
        !          2605: #endif /* IX370 */
        !          2606: 
        !          2607: #ifdef VINTR                           /* Turn off interrupt character */
        !          2608:     if (xlocal == 0)                   /* so ^C^C can break us out of */
        !          2609:       ttraw.c_cc[VINTR] = 0;           /* packet mode. */
        !          2610: #endif /* VINTR */
        !          2611: 
        !          2612: #ifdef ATTSV
        !          2613:     if (xlocal && (s > 0)) {           /* set speed */
        !          2614:         ttraw.c_cflag &= ~CBAUD;
        !          2615:         ttraw.c_cflag |= s;
        !          2616:     }
        !          2617:     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1);  /* set new modes . */
        !          2618: #else /* POSIX */
        !          2619:     if (xlocal && (s > 0)) {
        !          2620:        cfsetispeed(&ttraw,s);
        !          2621:        cfsetospeed(&ttraw,s);
        !          2622:     }
        !          2623:     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0) return(-1);
        !          2624: #endif /* ATTSV */
        !          2625:     tvtflg = 0;
        !          2626:     return(0);
        !          2627: #endif /* ATTSV */
        !          2628: }
        !          2629: 
        !          2630: /*  T T V T -- Condition communication line for use as virtual terminal  */
        !          2631: 
        !          2632: int
        !          2633: ttvt(speed,flow) long speed; int flow; {
        !          2634:     int s, s2;
        !          2635: 
        !          2636:     debug(F101,"ttvt ttyfd","",ttyfd);
        !          2637:     debug(F101,"ttvt tvtflg","",tvtflg);
        !          2638:     debug(F101,"ttvt speed","",speed);
        !          2639:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          2640: #ifdef NETCONN
        !          2641:     if (netconn) {
        !          2642:        tvtflg = 1;                     /* Network connections */
        !          2643:        return(0);                      /* require no special setup */
        !          2644:     }
        !          2645: #endif /* NETCONN */
        !          2646: 
        !          2647:     if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr)
        !          2648:       return(0);                       /* Already been called. */
        !          2649: 
        !          2650:     if (ttfdflg && !isatty(ttyfd)) return(0);
        !          2651: 
        !          2652:     if (xlocal) {                      /* For external lines... */
        !          2653:        s2 = (int) (speed / 10L);
        !          2654:        s = ttsspd(s2);                 /* Check/set the speed */
        !          2655:        carrctl(&tttvt, flow != DIALING /* Do carrier control */
        !          2656:                && (ttcarr == CAR_ON || ttcarr == CAR_AUT && ttmdm != 0));
        !          2657:     } else s = s2 = -1;
        !          2658: 
        !          2659: #ifndef SVORPOSIX
        !          2660:     /* Berkeley, V7, etc */
        !          2661:     if (flow == FLO_XONX) tttvt.sg_flags |= TANDEM; /* XON/XOFF if selected */
        !          2662: #ifdef UTEK
        !          2663:     hardflow(flow);
        !          2664:     if (flow == FLO_NONE || flow == FLO_HARD) tttvt.sg_flags &= ~TANDEM;
        !          2665: #else
        !          2666:     if (flow == FLO_NONE) tttvt.sg_flags &= ~TANDEM;
        !          2667: #endif /* UTEK */
        !          2668:     tttvt.sg_flags |= RAW;              /* Raw mode */
        !          2669: #ifdef TOWER1
        !          2670:     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
        !          2671: #else
        !          2672:     tttvt.sg_flags &= ~ECHO;            /* No echo */
        !          2673: #endif /* TOWER1 */
        !          2674: 
        !          2675:     if (stty(ttyfd,&tttvt) < 0) return(-1);
        !          2676: 
        !          2677: #else /* It is ATTSV or POSIX */
        !          2678: 
        !          2679:     if (flow == FLO_XONX) tttvt.c_iflag |= (IXON|IXOFF);
        !          2680:     if (flow == FLO_NONE) tttvt.c_iflag &= ~(IXON|IXOFF);
        !          2681: 
        !          2682:     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
        !          2683:     tttvt.c_iflag |= (IGNBRK|IGNPAR);
        !          2684: #ifdef ATTSV
        !          2685:     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY);
        !          2686: #else /* POSIX */
        !          2687:     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|BRKINT|INPCK|ISTRIP);
        !          2688: #endif /* ATTSV */
        !          2689:     tttvt.c_oflag &= ~OPOST;
        !          2690:     tttvt.c_cflag &= ~(CSIZE|PARENB);
        !          2691:     tttvt.c_cflag |= (CS8|CREAD|HUPCL);
        !          2692:     tttvt.c_cc[4] = 1;
        !          2693:     tttvt.c_cc[5] = 0;
        !          2694: 
        !          2695: #ifdef ATTSV
        !          2696:     if (s > 0) {                       /* Set speed */
        !          2697:         tttvt.c_cflag &= ~CBAUD;
        !          2698:         tttvt.c_cflag |= s;
        !          2699:     }
        !          2700:     if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1);  /* set new modes . */
        !          2701: #else /* POSIX */
        !          2702:     if (xlocal && (s > 0)) {
        !          2703:        cfsetispeed(&tttvt,s);
        !          2704:        cfsetospeed(&tttvt,s);
        !          2705:     }
        !          2706:     if (tcsetattr(ttyfd,TCSADRAIN,&tttvt) < 0) return(-1);
        !          2707: #endif /* ATTSV */
        !          2708: #endif /* SVORPOSIX */
        !          2709: 
        !          2710:     ttspeed = speed;                   /* Done, remember how we were */
        !          2711:     ttflow = flow;                     /* called, so we can decide how to */
        !          2712:     tvtflg = 1;                                /* respond next time. */
        !          2713: 
        !          2714:     debug(F101,"ttvt done","",tvtflg);
        !          2715:     return(0);
        !          2716: }
        !          2717: 
        !          2718: /*  T T S S P D  --  Checks and sets transmission rate.  */
        !          2719: 
        !          2720: /*  Call with speed in characters (not bits!) per second. */
        !          2721: /*  Returns internal speed code if successful, -1 otherwise. */
        !          2722: 
        !          2723: int
        !          2724: ttsspd(cps) int cps; {
        !          2725:     int s, s2;
        !          2726: 
        !          2727:     debug(F101,"ttsspd","",cps);
        !          2728: 
        !          2729: #ifdef NETCONN
        !          2730:     if (netconn) return (0);
        !          2731: #endif /* NETCONN */
        !          2732: 
        !          2733:     if (cps < 0) return(-1);
        !          2734:     s = s2 = -1;
        !          2735: 
        !          2736:     /* First check that the given speed is valid. */
        !          2737: 
        !          2738:     switch (cps) {
        !          2739: #ifndef MINIX
        !          2740:       case 0:   s = B0;    break;
        !          2741:       case 5:   s = B50;   break;
        !          2742:       case 7:   s = B75;   break;
        !          2743: #endif
        !          2744:       case 11:  s = B110;  break;
        !          2745: #ifndef MINIX
        !          2746:       case 15:  s = B150;  break;
        !          2747:       case 20:  s = B200;  break;
        !          2748: #endif
        !          2749:       case 30:  s = B300;  break;
        !          2750: #ifndef MINIX
        !          2751:       case 60:  s = B600;  break;
        !          2752: #endif
        !          2753:       case 120: s = B1200; break;
        !          2754: #ifndef MINIX
        !          2755:       case 180: s = B1800; break;
        !          2756: #endif
        !          2757:       case 240: s = B2400; break;
        !          2758:       case 480: s = B4800; break;
        !          2759: #ifndef MINIX
        !          2760:       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
        !          2761: #endif
        !          2762:       case 960: s = B9600; break;
        !          2763: #ifdef B19200
        !          2764:       case 1920: s = B19200; break;
        !          2765: #else
        !          2766: #ifdef EXTA
        !          2767:       case 1920: s = EXTA; break;
        !          2768: #endif
        !          2769: #endif
        !          2770: #ifdef B38400
        !          2771:       case 3840: s = B38400; break;
        !          2772: #else
        !          2773: #ifdef EXTB
        !          2774:       case 3840:   s = EXTB; break;
        !          2775: #endif
        !          2776: #endif
        !          2777:       default:
        !          2778:        return(-1);
        !          2779:     }
        !          2780:     /* Actually set the speed */
        !          2781: 
        !          2782:     if (ttyfd > -1 && s > -1 && xlocal != 0) {
        !          2783:        if (s2 == -1) s2 = s;
        !          2784: 
        !          2785: #ifdef ATTSV
        !          2786:        if (cps == 888) return(-1);     /* No split speeds, sorry. */
        !          2787:        if (ioctl(ttyfd,TCGETA,&ttcur) < 0) return(-1);
        !          2788:        ttcur.c_cflag &= ~CBAUD;
        !          2789:        ttcur.c_cflag |= s;
        !          2790:        tttvt.c_cflag &= ~CBAUD;
        !          2791:        tttvt.c_cflag |= s;
        !          2792:        ttraw.c_cflag &= ~CBAUD;
        !          2793:        ttraw.c_cflag |= s;
        !          2794:        ttold.c_cflag &= ~CBAUD;
        !          2795:        ttold.c_cflag |= s;
        !          2796:        if (ioctl(ttyfd,TCSETAW,&ttcur) < 0) return(-1);
        !          2797: #else 
        !          2798: #ifdef POSIX
        !          2799:        if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
        !          2800:        cfsetospeed(&ttcur,s);
        !          2801:        cfsetispeed(&ttcur,s2);
        !          2802:        cfsetospeed(&ttraw,s);
        !          2803:        cfsetispeed(&ttraw,s2);
        !          2804:        cfsetospeed(&tttvt,s);
        !          2805:        cfsetispeed(&tttvt,s2);
        !          2806:        cfsetospeed(&ttold,s);
        !          2807:        cfsetispeed(&ttold,s2);
        !          2808:        if (tcsetattr(ttyfd,TCSADRAIN,&ttcur) < 0) return(-1);
        !          2809: #else
        !          2810:        if (gtty(ttyfd,&ttcur) < 0) return(-1);
        !          2811:        ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
        !          2812:        tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
        !          2813:        ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
        !          2814:        ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
        !          2815:        if (stty(ttyfd,&ttcur) < 0) return(-1);
        !          2816: #endif /* POSIX */
        !          2817: #endif /* ATTSV */
        !          2818:     }
        !          2819:     return(s);
        !          2820: }
        !          2821: 
        !          2822: /* T T G S P D  -  Get speed of currently selected tty line  */
        !          2823: 
        !          2824: /*
        !          2825:   Unreliable.  After SET LINE, it returns an actual speed, but not the real
        !          2826:   speed.  Apparently it always returns the line's nominal speed, from
        !          2827:   /etc/ttytab.  Even if you SET SPEED to something else, this function might
        !          2828:   not notice.
        !          2829: */
        !          2830: long
        !          2831: ttgspd() {                             /* Get current tty speed */
        !          2832:     int s; long ss;
        !          2833:     char temp[12];
        !          2834: 
        !          2835: #ifdef NETCONN
        !          2836:     if (netconn) return(-1);           /* -1 if network connection */
        !          2837: #endif /* NETCONN */
        !          2838: 
        !          2839:     if (ttyfd < 0) {
        !          2840: #ifdef ATTSV
        !          2841:        s = ccold.c_cflag & CBAUD;
        !          2842: #else
        !          2843: #ifdef POSIX   
        !          2844:        s = cfgetospeed(&ccold);
        !          2845: #else
        !          2846:        s = ccold.sg_ospeed;            /* (obtained by congm()) */
        !          2847: #endif /* POSIX */
        !          2848: #endif /* ATTSV */
        !          2849:     } else {
        !          2850: #ifdef ATTSV
        !          2851:        if (ioctl(ttyfd,TCGETA,&ttcur) < 0) return(-1);
        !          2852:        s = ttcur.c_cflag & CBAUD;
        !          2853: #else
        !          2854: #ifdef POSIX
        !          2855:        if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
        !          2856:        s = cfgetospeed(&ttcur);
        !          2857: #else
        !          2858:        if (gtty(ttyfd,&ttcur) < 0) return(-1);
        !          2859:        s = ttcur.sg_ospeed;
        !          2860: #endif /* POSIX */
        !          2861: #endif /* ATTSV */
        !          2862:     }
        !          2863:     debug(F101,"ttgspd ttyfd","",ttyfd);
        !          2864:     debug(F101,"ttgspd code","",s);
        !          2865:     switch (s) {
        !          2866: #ifdef B0
        !          2867:       case B0:    ss = 0L; break;
        !          2868: #endif
        !          2869: 
        !          2870: #ifndef MINIX
        !          2871: /*
        !          2872:  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
        !          2873:  etc, making for many "duplicate case in switch" errors, which are fatal.
        !          2874: */
        !          2875: #ifdef B50
        !          2876:       case B50:   ss = 50L; break;
        !          2877: #endif
        !          2878: #ifdef B75
        !          2879:       case B75:   ss = 75L; break;
        !          2880: #endif
        !          2881: #endif /* MINIX */
        !          2882: 
        !          2883: #ifdef B110
        !          2884:       case B110:  ss = 110L; break;
        !          2885: #endif
        !          2886: 
        !          2887: #ifndef MINIX
        !          2888: #ifdef B134
        !          2889:       case B134:  ss = 134L; break;
        !          2890: #endif
        !          2891: #ifdef B150
        !          2892:       case B150:  ss = 150L; break;
        !          2893: #endif
        !          2894: #endif /* MINIX */
        !          2895: 
        !          2896: #ifdef B200
        !          2897:       case B200:  ss = 200L; break;
        !          2898: #endif
        !          2899: 
        !          2900: #ifdef B300
        !          2901:       case B300:  ss = 300L; break;
        !          2902: #endif
        !          2903: #ifdef B600
        !          2904:       case B600:  ss = 600L; break;
        !          2905: #endif
        !          2906: #ifdef B1200
        !          2907:       case B1200: ss = 1200L; break;
        !          2908: #endif
        !          2909: #ifdef B1800
        !          2910:       case B1800: ss = 1800L; break;
        !          2911: #endif
        !          2912: #ifdef B2400
        !          2913:       case B2400: ss = 2400L; break;
        !          2914: #endif
        !          2915: #ifdef B4800
        !          2916:       case B4800: ss = 4800L; break;
        !          2917: #endif
        !          2918: #ifdef B9600
        !          2919:       case B9600: ss = 9600L; break;
        !          2920: #endif
        !          2921: #ifdef B19200
        !          2922:       case B19200: ss = 19200L; break;
        !          2923: #else
        !          2924: #ifdef EXTA
        !          2925:       case EXTA: ss = 19200L; break;
        !          2926: #endif
        !          2927: #endif
        !          2928: 
        !          2929: #ifndef MINIX
        !          2930: #ifdef B38400
        !          2931:       case B38400: ss = 38400L; break;
        !          2932: #else
        !          2933: #ifdef EXTB
        !          2934:       case EXTB: ss = 38400L; break;
        !          2935: #endif
        !          2936: #endif
        !          2937: #endif /* MINIX */
        !          2938: 
        !          2939:       default:
        !          2940:        ss = -1; break;
        !          2941:     }
        !          2942:     sprintf(temp,"%l",ss);
        !          2943:     debug(F110,"speed",temp,0);
        !          2944:     return(ss);
        !          2945: }
        !          2946: 
        !          2947: /* ckumyr.c by Kristoffer Eriksson, [email protected], 15 Mar 1990. */
        !          2948: 
        !          2949: #ifdef COHERENT
        !          2950: #ifdef FIONREAD
        !          2951: #undef FIONREAD
        !          2952: #endif
        !          2953: #define FIONREAD TIOCQUERY
        !          2954: #define PEEKTYPE int
        !          2955: #else
        !          2956: #define PEEKTYPE long
        !          2957: #endif /* COHERENT */
        !          2958: 
        !          2959: #ifdef MYREAD
        !          2960: 
        !          2961: /* Private buffer for myread() and its companions.  Not for use by anything
        !          2962:  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
        !          2963:  * allowed to read my_count.
        !          2964:  *
        !          2965:  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
        !          2966:  *
        !          2967:  * A global parity mask variable could be useful too.  We could use it to
        !          2968:  * let myread() strip the parity on its own, instead of stripping sign
        !          2969:  * bits as it does now.
        !          2970:  */
        !          2971: 
        !          2972: #define MYBUFLEN 256
        !          2973: static CHAR mybuf[MYBUFLEN];           /* Buffer, including push back */
        !          2974: static int my_count = 0;               /* Number of chars still in mybuf */
        !          2975: static int my_item = -1;               /* Last index read from mybuf[] */
        !          2976: 
        !          2977: /* myread() -- Efficient read of one character from communications line.
        !          2978:  *
        !          2979:  * Uses a private buffer to minimize the number of expensive read() system
        !          2980:  * calls.  Essentially performs the equivalent of read() of 1 character, which
        !          2981:  * is then returned.  By reading all available input from the system buffers
        !          2982:  * to the private buffer in one chunk, and then working from this buffer, the
        !          2983:  * number of system calls is reduced in any case where more than one character
        !          2984:  * arrives during the processing of the previous chunk, for instance high
        !          2985:  * baud rates or network type connections where input arrives in packets.
        !          2986:  * If the time needed for a read() system call approaches the time for more
        !          2987:  * than one character to arrive, then this mechanism automatically compensates
        !          2988:  * for that by performing bigger read()s less frequently.  If the system load
        !          2989:  * is high, the same mechanism compensates for that too.
        !          2990:  *
        !          2991:  * myread() is a macro that returns the next character from the buffer.  If the
        !          2992:  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
        !          2993:  * returns.
        !          2994:  *
        !          2995:  * This should be efficient enough for any one-character-at-a-time loops.
        !          2996:  * For even better efficiency you might use memcpy()/bcopy() or such between
        !          2997:  * buffers (since they are often better optimized for copying), but it may not
        !          2998:  * be worth it if you have to take an extra pass over the buffer to strip
        !          2999:  * parity and check for CTRL-C anyway.
        !          3000:  *
        !          3001:  * Note that if you have been using myread() from another program module, you
        !          3002:  * may have some trouble accessing this macro version and the private variables
        !          3003:  * it uses.  In that case, just add a function in this module, that invokes the
        !          3004:  * macro.
        !          3005:  */
        !          3006: #define myread()  (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
        !          3007: 
        !          3008: /* Specification: Push back up to one character onto myread()'s queue.
        !          3009:  *
        !          3010:  * This implementation: Push back characters into mybuf. At least one character
        !          3011:  * must have been read through myread() before myunrd() may be used.  After
        !          3012:  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
        !          3013:  * one character can be pushed back, but only one character is guaranteed.
        !          3014:  * Since a previous myread() must have read its character out of mybuf[],
        !          3015:  * that guarantees that there is space for at least one character.  If push
        !          3016:  * back was really needed after EOF, a small addition could provide that.
        !          3017:  *
        !          3018:  * myunrd() is currently not called from anywhere inside kermit...
        !          3019:  */
        !          3020: #ifdef NOTUSED
        !          3021: myunrd(ch) CHAR ch; {
        !          3022:     if (my_item >= 0) {
        !          3023:        mybuf[my_item--] = ch;
        !          3024:        ++my_count;
        !          3025:     }
        !          3026: }
        !          3027: #endif
        !          3028: 
        !          3029: /* mygetbuf() -- Fill buffer for myread() and return first character.
        !          3030:  *
        !          3031:  * This function is what myread() uses when it can't get the next character
        !          3032:  * directly from its buffer.  First, it calls a system dependent myfillbuf()
        !          3033:  * to read at least one new character into the buffer, and then it returns
        !          3034:  * the first character just as myread() would have done.  This function also
        !          3035:  * is responsible for all error conditions that myread() can indicate.
        !          3036:  *
        !          3037:  * Returns: When OK    => a positive character, 0 or greater.
        !          3038:  *         When EOF    => -2.
        !          3039:  *         When error  => -3, error code in errno.
        !          3040:  *
        !          3041:  * Older myread()s additionally returned -1 to indicate that there was nothing
        !          3042:  * to read, upon which the caller would call myread() again until it got
        !          3043:  * something.  The new myread()/mygetbuf() always gets something.  If it 
        !          3044:  * doesn't, then make it do so!  Any program that actually depends on the old
        !          3045:  * behaviour will break.
        !          3046:  *
        !          3047:  * The older version also used to return -2 both for EOF and other errors,
        !          3048:  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
        !          3049:  * other errors now return different results, although Kermit currently never
        !          3050:  * checks to see which it was.  It just disconnects in both cases.
        !          3051:  *
        !          3052:  * Kermit lets the user use the quit key to perform some special commands
        !          3053:  * during file transfer.  This causes read(), and thus also mygetbuf(), to
        !          3054:  * finish without reading anything and return the EINTR error.  This should
        !          3055:  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
        !          3056:  * but if there is nothing to read, this could delay Kermit's reaction to
        !          3057:  * the command, and make Kermit appear unresponsive.
        !          3058:  *
        !          3059:  * The debug() call should be removed for optimum performance.
        !          3060:  */
        !          3061: int
        !          3062: mygetbuf() {
        !          3063:     my_count = myfillbuf();
        !          3064:     /* debug(F101, "myfillbuf read", "", my_count); */
        !          3065:     if (my_count <= 0)
        !          3066:       return(my_count < 0 ? -3 : -2);
        !          3067:     --my_count;
        !          3068:     return(255 & (int)mybuf[my_item = 0]);
        !          3069: }
        !          3070: 
        !          3071: /* myfillbuf():
        !          3072:  * System-dependent read() into mybuf[], as many characters as possible.
        !          3073:  *
        !          3074:  * Returns: OK => number of characters read, always more than zero.
        !          3075:  *          EOF => 0
        !          3076:  *          Error => -1, error code in errno.
        !          3077:  *
        !          3078:  * If there is input available in the system's buffers, all of it should be
        !          3079:  * read into mybuf[] and the function return immediately.  If no input is
        !          3080:  * available, it should wait for a character to arrive, and return with that
        !          3081:  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
        !          3082:  * character, but be aware that any such delay lengthens the packet turnaround
        !          3083:  * time during kermit file transfers.  Should never return with zero characters
        !          3084:  * unless EOF or irrecoverable read error.
        !          3085:  *
        !          3086:  * Correct functioning depends on the correct tty parameters being used.
        !          3087:  * Better control of current parameters is required than may have been the
        !          3088:  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can 
        !          3089:  * no longer be sometimes off and sometimes on like it used to, unless a 
        !          3090:  * special myfillbuf() is written to handle that.  Otherwise the ordinary 
        !          3091:  * myfillbuf()s may think they have come to EOF.
        !          3092:  *
        !          3093:  * If your system has a facility to directly perform the functioning of
        !          3094:  * myfillbuf(), then use it.  If the system can tell you how many characters
        !          3095:  * are available in its buffers, then read that amount (but not less than 1).
        !          3096:  * If the system can return a special indication when you try to read without
        !          3097:  * anything to read, while allowing you to read all there is when there is
        !          3098:  * something, you may loop until there is something to read, but probably that
        !          3099:  * is not good for the system load.
        !          3100:  */
        !          3101: 
        !          3102: #ifdef SVORPOSIX
        !          3103:        /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
        !          3104:         * and CLOCAL set any way you like.  This way, read() will do exactly
        !          3105:         * what is required by myfillbuf(): If there is data in the buffers
        !          3106:         * of the O.S., all available data is read into mybuf, up to the size
        !          3107:         * of mybuf.  If there is none, the first character to arrive is
        !          3108:         * awaited and returned.
        !          3109:         */
        !          3110: int
        !          3111: myfillbuf() {
        !          3112: #ifdef sxaE50
        !          3113:     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
        !          3114:     /* necessary for the sxa E50, but it is. */
        !          3115:     return read(ttyfd, mybuf, 255);
        !          3116: #else
        !          3117:     /* sizeof(mybuf) should be MYBUFL == 256 */
        !          3118:     return read(ttyfd, mybuf, sizeof(mybuf));
        !          3119: #endif /* sxaE50 */
        !          3120: }
        !          3121: 
        !          3122: #else /* not AT&T or POSIX */
        !          3123: 
        !          3124: #ifdef aegis
        !          3125:        /* This is quoted from the old myread().  The semantics seem to be
        !          3126:         * alright, but maybe errno would not need to be set even when
        !          3127:         * there is no error?  I don't know aegis.
        !          3128:         */
        !          3129: int
        !          3130: myfillbuf() {
        !          3131:     int count;
        !          3132: 
        !          3133:     count = ios_$get((short)ttyfd, ios_$cond_opt, mybuf, 256L, st);
        !          3134:     errno = EIO;
        !          3135:     if (st.all == ios_$get_conditional_failed) /* get at least one */
        !          3136:       inbufc = ios_$get((short)ttyfd, 0, mybuf, 1L, st);
        !          3137:     if (st.all == ios_$end_of_file)
        !          3138:       return(0);
        !          3139:     else if (st.all != status_$ok) {
        !          3140:        errno = EIO;
        !          3141:        return(-1);
        !          3142:     }
        !          3143:     return(count);
        !          3144: }
        !          3145: #else /* !aegis */
        !          3146: 
        !          3147: #ifdef FIONREAD
        !          3148:        /* This is for systems with FIONREAD.  FIONREAD returns the number
        !          3149:         * of characters available for reading. If none are available, wait
        !          3150:         * until something arrives, otherwise return all there is.
        !          3151:         */
        !          3152: int
        !          3153: myfillbuf() {
        !          3154:     PEEKTYPE avail;
        !          3155: 
        !          3156:     if ((ioctl(ttyfd, FIONREAD, &avail) < 0) || (avail == 0))
        !          3157:       avail = 1;
        !          3158: 
        !          3159:     if (avail > MYBUFLEN)
        !          3160:       avail = MYBUFLEN;
        !          3161: 
        !          3162:     return(read(ttyfd, mybuf, (int) avail));
        !          3163: }
        !          3164: 
        !          3165: #else /* !FIONREAD */
        !          3166: /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
        !          3167: /* When there is no other possibility, read 1 character at a time. */
        !          3168: int
        !          3169: myfillbuf() {
        !          3170:     return read(ttyfd, mybuf, 1);
        !          3171: }
        !          3172: 
        !          3173: #endif /* !FIONREAD */
        !          3174: #endif /* !aegis */
        !          3175: #endif /* !ATTSV */
        !          3176: 
        !          3177: #endif /* MYREAD */
        !          3178: 
        !          3179: /*  T T F L U I  --  Flush tty input buffer */
        !          3180: 
        !          3181: int
        !          3182: ttflui() {
        !          3183:     int ffd;
        !          3184: 
        !          3185: #ifndef SVORPOSIX
        !          3186:     int n;
        !          3187: #endif /* SVORPOSIX */
        !          3188: #ifdef NETCONN
        !          3189:     if (netconn) return(netflui());
        !          3190: #endif /* NETCONN */
        !          3191: 
        !          3192:     ffd = xlocal ? ttyfd : 0;          /* If not local, use stdin */
        !          3193:     debug(F101,"ttflui xlocal","",xlocal);
        !          3194:     debug(F101,"ttflui ttyfd","",ttyfd);
        !          3195:     debug(F101,"ttflui ffd","",ffd);
        !          3196:     if (ffd < 0) return(-1);
        !          3197: 
        !          3198: #ifdef MYREAD
        !          3199:     my_count = 0;                      /* Initialize myread() stuff */
        !          3200:     my_item = -1;
        !          3201: #endif /* MYREAD */
        !          3202: 
        !          3203: #ifdef aegis
        !          3204:     sio_$control((short)ffd, sio_$flush_in, true, st);
        !          3205:     if (st.all != status_$ok) {
        !          3206:        fprintf(stderr, "flush failed: "); error_$print(st);
        !          3207:     } else {      /* sometimes the flush doesn't work */
        !          3208:         for (;;) {
        !          3209:            char buf[256];
        !          3210:             /* eat all the characters that shouldn't be available */
        !          3211:             ios_$get((short)ffd, ios_$cond_opt, buf, 256L, st); /* (void) */
        !          3212:             if (st.all == ios_$get_conditional_failed) break;
        !          3213:             fprintf(stderr, "flush failed(2): "); error_$print(st);
        !          3214:         }
        !          3215:     }
        !          3216: #else
        !          3217: #ifdef ATTSV
        !          3218: #ifndef VXVE
        !          3219:     ioctl(ffd,TCFLSH,0);
        !          3220: #endif /* VXVE */
        !          3221: #else                                  /* POSIX */
        !          3222: #ifdef POSIX
        !          3223:     tcflush(ttyfd,TCIFLUSH);
        !          3224: #else                                  /* Berkeley and others */
        !          3225: #ifdef TIOCFLUSH
        !          3226: #ifdef ANYBSD
        !          3227:     n = FREAD;                          /* Specify read queue */
        !          3228:     debug(F101,"ttflui anybsd flush","",ffd);
        !          3229:     ioctl(ffd,TIOCFLUSH,&n);
        !          3230: #else
        !          3231:     ioctl(ffd,TIOCFLUSH,0);
        !          3232: #endif /* ANYBSD */
        !          3233: #endif /* TIOCFLUSH */
        !          3234: #endif /* POSIX */
        !          3235: #endif /* aegis */
        !          3236: #endif
        !          3237:     return(0);
        !          3238: }
        !          3239: 
        !          3240: int
        !          3241: ttfluo() {                             /* Flush output buffer */
        !          3242: #ifdef POSIX
        !          3243:     return(tcflush(ttyfd,TCOFLUSH));
        !          3244: #else
        !          3245:     return(0);                         /* (dummy for now) */
        !          3246: #endif /* POSIX */
        !          3247: 
        !          3248: }
        !          3249: 
        !          3250: /* Interrupt Functions */
        !          3251: 
        !          3252: /* Set up terminal interrupts on console terminal */
        !          3253: 
        !          3254: #ifdef SVORPOSIX
        !          3255: SIGTYP
        !          3256: esctrp(foo) int foo; {                 /* trap console escapes (^\) */
        !          3257:     conesc = 1;
        !          3258:     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
        !          3259: }
        !          3260: #endif /* SVORPOSIX */
        !          3261: 
        !          3262: #ifdef V7
        !          3263: SIGTYP
        !          3264: esctrp(foo) int foo; {                 /* trap console escapes (^\) */
        !          3265:     conesc = 1;
        !          3266:     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
        !          3267: }
        !          3268: #endif
        !          3269: 
        !          3270: #ifdef C70
        !          3271: SIGTYP
        !          3272: esctrp(foo) int foo; {                 /* trap console escapes (^\) */
        !          3273:     conesc = 1;
        !          3274:     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
        !          3275: }
        !          3276: #endif
        !          3277: 
        !          3278: /*  C O N B G T  --  Background Test  */
        !          3279: 
        !          3280: static int jc;                         /* 0 = no job control */
        !          3281: 
        !          3282: VOID
        !          3283: conbgt() {
        !          3284:     int x = -1,                                /* process group or SIGINT test */
        !          3285:         y = 0;                         /* isatty() test */
        !          3286: 
        !          3287: /*
        !          3288:   Check for background operation, even if not running on real tty, so that
        !          3289:   background flag can be set correctly.  If background status is detected,
        !          3290:   then Kermit will not issue its interactive prompt or most messages.
        !          3291:   If your prompt goes away, you can blame (and fix?) this function.
        !          3292: */
        !          3293: 
        !          3294: /* Use process-group test if possible. */
        !          3295: 
        !          3296: #ifdef POSIX                           /* We can do it in POSIX */
        !          3297: #define PGROUP_T
        !          3298: #else
        !          3299: #ifdef BSD4                            /* and in BSD 4.x. */
        !          3300: #define PGROUP_T
        !          3301: #else
        !          3302: #ifdef HPUXJOBCTL                      /* and in most HP-UX's */
        !          3303: #define PGROUP_T
        !          3304: #else
        !          3305: #ifdef TIOCGPGRP                       /* and anyplace that has this ioctl. */
        !          3306: #define PGROUP_T
        !          3307: #endif /* TIOCGPGRP */
        !          3308: #endif /* HPUXJOBCTL */
        !          3309: #endif /* BSD4 */
        !          3310: #endif /* POSIX */
        !          3311: 
        !          3312: #ifdef MIPS                            /* Except if it doesn't work... */
        !          3313: #undef PGROUP_T
        !          3314: #endif /* MIPS */
        !          3315: 
        !          3316: #ifdef PGROUP_T
        !          3317: /*
        !          3318:   Semi-reliable process-group test.  Check whether this process's group is
        !          3319:   the same as the controlling terminal's process group.  This works if the
        !          3320:   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
        !          3321: */
        !          3322:     PID_T mypgrp;                      /* Kermit's process group */
        !          3323:     PID_T ctpgrp;                      /* The terminal's process group */
        !          3324: #ifndef _POSIX_SOURCE
        !          3325: /*
        !          3326:   The getpgrp() prototype is obtained from system header files for POSIX 
        !          3327:   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
        !          3328:   a duplicate declaration here, others don't, so it's safer to leave it in
        !          3329:   if we don't know for certain.
        !          3330: */
        !          3331: #ifndef SVR4
        !          3332: #ifndef PS2AIX10
        !          3333:     extern PID_T getpgrp();
        !          3334: #endif /* PS2AIX10 */
        !          3335: #endif /* SVR4 */
        !          3336: #endif /* _POSIX_SOURCE */
        !          3337: 
        !          3338: /* Get my process group. */
        !          3339: 
        !          3340: #ifdef SVR3 /* Maybe this should be ATTSV? */
        !          3341: /* This function is not described in SVID R2 */
        !          3342:     mypgrp = getpgrp();
        !          3343:     debug(F101,"ATTSV conbgt process group","",(int) mypgrp);
        !          3344: #else
        !          3345: #ifdef POSIX
        !          3346:     mypgrp = getpgrp();
        !          3347:     debug(F101,"POSIX conbgt process group","",(int) mypgrp);
        !          3348: #else /* BSD, V7, etc */
        !          3349:     mypgrp = getpgrp(0);
        !          3350:     debug(F101,"BSD conbgt process group","",(int) mypgrp);
        !          3351: #endif /* POSIX */
        !          3352: #endif /* SVR3 */
        !          3353: 
        !          3354: /* Now get controlling tty's process group */
        !          3355: #ifdef POSIX
        !          3356:     ctpgrp = tcgetpgrp(1);             /* The POSIX way */
        !          3357:     debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp);
        !          3358: #else
        !          3359:     ioctl(1, TIOCGPGRP, &ctpgrp);      /* Or the BSD way */
        !          3360:     debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp);
        !          3361: #endif /* POSIX */
        !          3362: 
        !          3363:     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
        !          3364:       x = (mypgrp == ctpgrp) ? 0 : 1;  /* If they differ, then background. */
        !          3365:     else x = -1;                       /* If error, remember. */
        !          3366:     debug(F101,"conbgt process group test","",x);
        !          3367: #endif /* PGROUP_T */
        !          3368: 
        !          3369: /* Try to see if job control is available */
        !          3370: 
        !          3371: #ifdef NOJC                            /* User override */
        !          3372:     jc = 0;                            /* No job control allowed */
        !          3373:     debug(F111,"NOJC","jc",jc);
        !          3374: #else
        !          3375: #ifdef SVR4ORPOSIX                     /* POSIX actually tells us */
        !          3376:     debug(F100,"SVR4ORPOSIX jc test...","",0);
        !          3377: #ifdef _SC_JOB_CONTROL
        !          3378:     jc = sysconf(_SC_JOB_CONTROL);     /* Whatever system says */
        !          3379:     debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
        !          3380: #else
        !          3381: #ifdef _POSIX_JOB_CONTROL
        !          3382:     jc = 1;                            /* By definition */
        !          3383:     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
        !          3384: #else
        !          3385:     jc = 0;                            /* Assume job control allowed */
        !          3386:     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
        !          3387: #endif /* _POSIX_JOB_CONTROL */
        !          3388: #endif /* _SC_JOB_CONTROL */
        !          3389: #else
        !          3390: #ifdef BSD4
        !          3391:     jc = 1;                            /* Job control allowed */
        !          3392:     debug(F111,"BSD job control","jc",jc);
        !          3393: #else
        !          3394:     jc = 0;
        !          3395:     debug(F111,"job control catch-all","jc",jc);
        !          3396: #endif /* BSD4 */
        !          3397: #endif /* SVR4ORPOSIX */
        !          3398: #endif /* NOJC */
        !          3399:     debug(F101,"conbgt jc","",jc);
        !          3400: 
        !          3401: /*
        !          3402:   Another background test.
        !          3403:   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
        !          3404:   which is done by the shell (sh) if the program is started with '&'.
        !          3405:   Unfortunately, this is NOT done by csh or ksh so watch out!
        !          3406:   Note, it's safe to set SIGINT to SIG_IGN here, because further down
        !          3407:   we always set it to something else.
        !          3408: */
        !          3409:     if (x < 0) {                       /* Didn't get good results above... */
        !          3410: 
        !          3411:        SIGTYP (*osigint)();
        !          3412: 
        !          3413:        osigint = signal(SIGINT,SIG_IGN);       /* What is SIGINT set to? */
        !          3414:        x = (osigint == SIG_IGN) ? 1 : 0;       /* SIG_IGN? */
        !          3415:        debug(F101,"conbgt osigint","",(int) osigint);
        !          3416:        debug(F101,"conbgt signal test","",x);
        !          3417:     }
        !          3418: 
        !          3419: /* Also check to see if we're running with redirected stdio. */
        !          3420: /* This is not really background operation, but we want to act as though */
        !          3421: /* it were. */
        !          3422: 
        !          3423:     y = (isatty(0) && isatty(1)) ? 1 : 0;
        !          3424:     debug(F101,"conbgt isatty test","",y);
        !          3425: 
        !          3426: #ifdef BSD29
        !          3427: /* The process group and/or signal test doesn't work under these... */
        !          3428:     backgrd = !y;
        !          3429: #else
        !          3430: #ifdef sxaE50
        !          3431:     backgrd = !y;
        !          3432: #else
        !          3433: #ifdef MINIX
        !          3434:     backgrd = !y;
        !          3435: #else
        !          3436:     backgrd = (x || !y) ? 1 : 0;
        !          3437: #endif /* BSD29 */
        !          3438: #endif /* sxaE50 */
        !          3439: #endif /* MINIX */
        !          3440:     debug(F101,"conbgt backgrd","",backgrd);
        !          3441: }
        !          3442: 
        !          3443: /*  C O N I N T  --  Console Interrupt setter  */
        !          3444: 
        !          3445: /*
        !          3446:   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
        !          3447:   Second arg is pointer to function to handle SIGTSTP (suspend).
        !          3448: */
        !          3449: 
        !          3450: VOID                                   /* Set terminal interrupt traps. */
        !          3451: #ifdef CK_ANSIC
        !          3452: #ifdef apollo
        !          3453: conint(f,s) SIGTYP (*f)(), (*s)();
        !          3454: #else
        !          3455: conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
        !          3456: #endif /* apollo */
        !          3457: #else
        !          3458: conint(f,s) SIGTYP (*f)(), (*s)();
        !          3459: #endif /* CK_ANSIC */
        !          3460: /* conint */ {
        !          3461: 
        !          3462:     conbgt();                          /* Do background test. */
        !          3463: 
        !          3464: /* Set the desired handlers for hangup and software termination. */
        !          3465: 
        !          3466:     signal(SIGHUP,f);                   /* Hangup */
        !          3467:     signal(SIGTERM,f);                  /* Software termination */
        !          3468: 
        !          3469: /* Now handle keyboard stop, quit, and interrupt signals. */
        !          3470: /* Check if invoked in background -- if so signals set to be ignored. */
        !          3471: /* However, if running under a job control shell, don't ignore them. */
        !          3472: /* We won't be getting any, as we aren't in the terminal's process group. */
        !          3473: 
        !          3474:     debug(F101,"conint backgrd","",backgrd);
        !          3475:     debug(F101,"conint jc","",jc);
        !          3476: 
        !          3477:     if (backgrd && !jc) {              /* In background, ignore signals */
        !          3478:        debug(F101,"conint background ignoring signals, jc","",jc);
        !          3479: #ifdef SIGTSTP
        !          3480:         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
        !          3481: #endif /* SIGTSTP */
        !          3482:         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
        !          3483:         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
        !          3484:     } else {                           /* Else in foreground or suspended */
        !          3485:        debug(F101,"conint foreground catching signals, jc","",jc);
        !          3486:         signal(SIGINT,f);               /* Catch terminal interrupt */
        !          3487: 
        !          3488: #ifdef SIGTSTP                         /* Keyboard stop (suspend) */
        !          3489:        debug(F101,"conint SIGSTSTP","",(int) s);
        !          3490:        if (s == NULL) s = SIG_DFL;
        !          3491: #ifdef NOJC                            /* No job control allowed. */
        !          3492:        signal(SIGTSTP,SIG_IGN);
        !          3493: #else                                  /* Job control allowed */
        !          3494:        if (jc)                         /* if available. */
        !          3495:          signal(SIGTSTP,s);
        !          3496:        else
        !          3497:          signal(SIGTSTP,SIG_IGN);
        !          3498: #endif /* NOJC */
        !          3499: #endif /* SIGTSTP */
        !          3500: 
        !          3501: #ifdef SVORPOSIX
        !          3502:         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
        !          3503:         if (conesc) conesc = 0;         /* Clear out pending escapes */
        !          3504: #else
        !          3505: #ifdef V7
        !          3506:         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
        !          3507:         if (conesc) conesc = 0;
        !          3508: #else
        !          3509: #ifdef aegis
        !          3510:         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
        !          3511: #else
        !          3512:         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
        !          3513: #endif /* aegis */
        !          3514: #endif /* V7 */
        !          3515: #endif /* SVORPOSIX */
        !          3516:     }
        !          3517: }
        !          3518: 
        !          3519: 
        !          3520: /*  C O N N O I  --  Reset console terminal interrupts */
        !          3521: 
        !          3522: SIGTYP                                 /* Dummy function to ignore signals */
        !          3523: #ifdef CK_ANSIC
        !          3524: sig_ign(int foo)
        !          3525: #else
        !          3526: sig_ign(foo) int foo;
        !          3527: #endif /* CK_ANSIC */
        !          3528: /* sig_IGN */ {                                /* Just like the real one, but has  */
        !          3529: }                                      /* different address. */
        !          3530: 
        !          3531: VOID
        !          3532: connoi() {                              /* Console-no-interrupts */
        !          3533: 
        !          3534:     debug(F100,"connoi","",0);
        !          3535: #ifdef SIGTSTP
        !          3536:     signal(SIGTSTP,SIG_DFL);
        !          3537: #endif /* SIGTSTP */
        !          3538:     /* Note the locally defined replacement for SIG_IGN that is used here */
        !          3539:     /* for the SIGINT setting.  This is done so that the Sys V background */
        !          3540:     /* test -- (signal(SIGINT,SIG_IGN) == SIG_IGN) -- can work.  If we use */
        !          3541:     /* the real SIG_IGN here, then conint will always decide that this */ 
        !          3542:     /* program is running in the background! */
        !          3543: 
        !          3544:     signal(SIGINT,sig_ign);            /* <--- note! */
        !          3545: 
        !          3546:     signal(SIGHUP,SIG_DFL);
        !          3547:     signal(SIGQUIT,SIG_IGN);
        !          3548:     signal(SIGTERM,SIG_IGN);
        !          3549: }
        !          3550: 
        !          3551: /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
        !          3552: 
        !          3553: #ifdef  V7
        !          3554: /*
        !          3555:  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
        !          3556:  eliminates blocking on a read, because we can read /dev/kmem to get the
        !          3557:  number of characters available for raw input.  If your system can't
        !          3558:  or you won't let the world read /dev/kmem then you must figure out a
        !          3559:  different way to do the counting of characters available, or else replace
        !          3560:  this by a dummy function that always returns 0.
        !          3561: */
        !          3562: /*
        !          3563:  * Call this routine as: initrawq(tty)
        !          3564:  * where tty is the file descriptor of a terminal.  It will return
        !          3565:  * (as a char *) the kernel-mode memory address of the rawq character
        !          3566:  * count, which may then be read.  It has the side-effect of flushing
        !          3567:  * input on the terminal.
        !          3568:  */
        !          3569: /*
        !          3570:  * John Mackin, Physiology Dept., University of Sydney (Australia)
        !          3571:  * ...!decvax!mulga!physiol.su.oz!john
        !          3572:  *
        !          3573:  * Permission is hereby granted to do anything with this code, as
        !          3574:  * long as this comment is retained unmodified and no commercial
        !          3575:  * advantage is gained.
        !          3576:  */
        !          3577: #ifndef MINIX
        !          3578: #ifndef COHERENT
        !          3579: #include <a.out.h>
        !          3580: #include <sys/proc.h>
        !          3581: #endif /* COHERENT */
        !          3582: #endif /* MINIX */
        !          3583: 
        !          3584: #ifdef COHERENT
        !          3585: #include <l.out.h>
        !          3586: #include <sys/proc.h>
        !          3587: #endif /* COHERENT */
        !          3588: 
        !          3589: char *
        !          3590: initrawq(tty) int tty; {
        !          3591: #ifdef MINIX
        !          3592:     return(0);
        !          3593: #else
        !          3594: #ifdef UTS24
        !          3595:     return(0);
        !          3596: #else
        !          3597: #ifdef BSD29
        !          3598:     return(0);
        !          3599: #else
        !          3600:     long lseek();
        !          3601:     static struct nlist nl[] = {
        !          3602:         {PROCNAME},
        !          3603:         {NPROCNAME},
        !          3604:         {""}
        !          3605:     };
        !          3606:     static struct proc *pp;
        !          3607:     char *qaddr, *p, c;
        !          3608:     int m;
        !          3609:     PID_T pid, me;
        !          3610:     NPTYPE xproc;                       /* Its type is defined in makefile. */
        !          3611:     int catch();
        !          3612: 
        !          3613:     me = getpid();
        !          3614:     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
        !          3615:     nlist(BOOTNAME, nl);
        !          3616:     if (nl[0].n_type == 0) err("proc array");
        !          3617: 
        !          3618:     if (nl[1].n_type == 0) err("nproc");
        !          3619: 
        !          3620:     lseek(m, (long)(nl[1].n_value), 0);
        !          3621:     read (m, &xproc, sizeof(xproc));
        !          3622:     saval = signal(SIGALRM, catch);
        !          3623:     if ((pid = fork()) == 0) {
        !          3624:         while(1)
        !          3625:             read(tty, &c, 1);
        !          3626:     }
        !          3627:     alarm(2);
        !          3628: 
        !          3629:     if(setjmp(jjbuf) == 0) {
        !          3630:         while(1)
        !          3631:             read(tty, &c, 1);
        !          3632:     }
        !          3633:     signal(SIGALRM, SIG_DFL);
        !          3634: 
        !          3635: #ifdef DIRECT
        !          3636:     pp = (struct proc *) nl[0].n_value;
        !          3637: #else
        !          3638:     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
        !          3639:     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
        !          3640: #endif
        !          3641:     lseek(m, (long)(nl[1].n_value), 0);
        !          3642:     read(m, &xproc, sizeof(xproc));
        !          3643: 
        !          3644:     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
        !          3645:     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
        !          3646:     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
        !          3647:         err("read proc table");
        !          3648:     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
        !          3649:         if (pp -> p_pid == (short) pid) goto iout;
        !          3650:     }
        !          3651:     err("no such proc");
        !          3652: 
        !          3653: iout:
        !          3654:     close(m);
        !          3655:     qaddr = (char *)(pp -> p_wchan);
        !          3656:     free (p);
        !          3657:     kill(pid, SIGKILL);
        !          3658:     wait((WAIT_T)0);             /* Destroy the ZOMBIEs! */
        !          3659:     return (qaddr);
        !          3660: #endif
        !          3661: #endif
        !          3662: #endif
        !          3663: }
        !          3664: 
        !          3665: /*  More V7-support functions...  */
        !          3666: 
        !          3667: static VOID
        !          3668: err(s) char *s; {
        !          3669:     char buf[200];
        !          3670: 
        !          3671:     sprintf(buf, "fatal error in initrawq: %s", s);
        !          3672:     perror(buf);
        !          3673:     doexit(1,-1);
        !          3674: }
        !          3675: 
        !          3676: static VOID
        !          3677: catch(foo) int foo; {
        !          3678:     longjmp(jjbuf, -1);
        !          3679: }
        !          3680: 
        !          3681: 
        !          3682: /*  G E N B R K  --  Simulate a modem break.  */
        !          3683: 
        !          3684: #ifdef MINIX
        !          3685: #define BSPEED B110
        !          3686: #else
        !          3687: #define BSPEED B150
        !          3688: #endif /* MINIX */
        !          3689: 
        !          3690: VOID
        !          3691: genbrk(fn,msec) int fn, msec; {
        !          3692:     struct sgttyb ttbuf;
        !          3693:     int ret, sospeed, x, y;
        !          3694: 
        !          3695:     ret = ioctl(fn, TIOCGETP, &ttbuf);
        !          3696:     sospeed = ttbuf.sg_ospeed;
        !          3697:     ttbuf.sg_ospeed = BSPEED;
        !          3698:     ret = ioctl(fn, TIOCSETP, &ttbuf);
        !          3699:     y = (int)strlen(brnuls);
        !          3700:     x = ( BSPEED * 100 ) / msec;
        !          3701:     if (x > y) x = y;
        !          3702:     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
        !          3703:     ttbuf.sg_ospeed = sospeed;
        !          3704:     ret = ioctl(fn, TIOCSETP, &ttbuf);
        !          3705:     ret = write(fn, "@", 1);
        !          3706:     return;
        !          3707: }
        !          3708: #endif /* V7 */
        !          3709: 
        !          3710: /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
        !          3711: 
        !          3712: /*  Some callers of this want to know whether there is something to read
        !          3713:  *  either in the system buffers or in our private buffers (and mostly don't
        !          3714:  *  care how many characters, just whether it's more than zero or not), while
        !          3715:  *  some others would be better off with the number of characters in our
        !          3716:  *  private buffers only.
        !          3717:  *
        !          3718:  *  Some systems can say how many characters there are in the system buffers.
        !          3719:  *  Others can not. For those that can't, the number in the private buffers
        !          3720:  *  will have to do (or should we put the tty into O_NDELAY-mode and try to
        !          3721:  *  read one character?). If the system can tell whether there is zero or
        !          3722:  *  more than zero characters, we can return 1 in the latter case even if the
        !          3723:  *  private buffer is empty. (That is good for sliding windows.)
        !          3724:  */
        !          3725: int
        !          3726: ttchk() {
        !          3727:     int x;
        !          3728:     PEEKTYPE n = 0;
        !          3729: 
        !          3730: #ifdef NETCONN
        !          3731:     if (netconn) return(nettchk());
        !          3732: #endif /* NETCONN */
        !          3733: 
        !          3734: #ifdef FIONREAD
        !          3735:     x = ioctl(ttyfd, FIONREAD, &n);     /* Berkeley and maybe some others */
        !          3736:     debug(F101,"ttchk","",n);
        !          3737:     if (x < 0) n = 0;
        !          3738: #else
        !          3739: #ifdef  V7
        !          3740: #ifdef MINIX
        !          3741:     return(0);
        !          3742: #else
        !          3743:     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
        !          3744:     x = read(kmem[TTY], &n, sizeof(int));
        !          3745:     if (x != sizeof(int)) n = 0;
        !          3746: #endif /* MINIX */
        !          3747: #else
        !          3748: #ifdef PROVX1
        !          3749:     x = ioctl(ttyfd, TIOCQCNT, &ttbuf); /* Pro/3xx Venix V.1 */
        !          3750:     n = ttbuf.sg_ispeed & 0377;
        !          3751:     if (x < 0) n = 0;
        !          3752: #else
        !          3753: #ifdef RDCHK
        !          3754:     /* Last resort for systems without FIONREAD or equivalent, but with
        !          3755:      * something like rdchk(), like XENIX.
        !          3756:      */
        !          3757:     if (my_count == 0 && rdchk(ttyfd) > 0) n = 1;
        !          3758: #endif /* RDCHK */
        !          3759: #endif /* PROVX1 */
        !          3760: #endif /* V7 */
        !          3761: #endif /* FIONREAD */
        !          3762: 
        !          3763: #ifdef MYREAD
        !          3764:     /* For myread() users, add the contents of myread()'s private buffer.
        !          3765:      * Sometimes, this is all there is to construct a result of ttchk() on.
        !          3766:      */
        !          3767:     if (my_count > 0)              /* Sys III, Sys V, Apollo Aegis, etc */
        !          3768:        n += my_count;
        !          3769: #endif /* MYREAD */
        !          3770: 
        !          3771:     debug(F101,"ttchk","",n);
        !          3772:     return(n);
        !          3773: }
        !          3774: 
        !          3775: /*  T T X I N  --  Get n characters from tty input buffer  */
        !          3776: 
        !          3777: /*  Returns number of characters actually gotten, or -1 on failure  */
        !          3778: 
        !          3779: /*  Intended for use only when it is known that n characters are actually */
        !          3780: /*  Available in the input buffer.  */
        !          3781: 
        !          3782: int
        !          3783: ttxin(n,buf) int n; CHAR *buf; {
        !          3784:     register int x, c;
        !          3785:   
        !          3786:     ttpmsk = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
        !          3787:     debug(F101,"ttxin n","",n);
        !          3788: #ifdef SUNX25
        !          3789:     if (netconn && (ttnet == NET_SX25))        /* X.25 connection */
        !          3790:       return(x25xin(n,buf));
        !          3791: #endif /* SUNX25 */
        !          3792: 
        !          3793: #ifdef MYREAD
        !          3794:     for( x = 0; (x > -1) && (x < n) && (c = myread()) >= 0; )
        !          3795:       buf[x++] = c & ttpmsk;
        !          3796: #else
        !          3797:     x = read(ttyfd,buf,n);
        !          3798:     for (c = 0; c < n; c++) buf[c] &= ttpmsk;
        !          3799:     debug(F101," x","",x);
        !          3800: #endif /* MYREAD */
        !          3801:     if (x > 0) buf[x] = '\0';
        !          3802:     if (x < 0) x = -1;
        !          3803:     return(x);
        !          3804: }
        !          3805: 
        !          3806: /*  T T O L  --  Write string s, length n, to communication device.  */
        !          3807: /*
        !          3808:   Returns:
        !          3809:    >= 0 on success, number of characters actually written.
        !          3810:    -1 on failure.
        !          3811: */
        !          3812: #define TTOLMAXT 5
        !          3813: int
        !          3814: ttol(s,n) int n; CHAR *s; {
        !          3815:     int x, len, tries;
        !          3816: 
        !          3817:     if (ttyfd < 0) return(-1);          /* Not open? */
        !          3818:     debug(F101,"ttol n","",n);
        !          3819:     tries = TTOLMAXT;                  /* Allow up to this many tries */
        !          3820:     len = n;                           /* Remember original length */
        !          3821: 
        !          3822:     while (n > 0 && tries-- > 0) {     /* Be persistent */
        !          3823:        debug(F101,"ttol try","",TTOLMAXT - tries);
        !          3824:        x = write(ttyfd,s,n);           /* Write string to device */
        !          3825:        if (x == n) {                   /* Worked? */
        !          3826:            debug(F101,"ttol ok","",x); /* OK */
        !          3827:            return(len);                /* Done */
        !          3828:        } else if (x < 0) {             /* No, got error? */
        !          3829:            debug(F101,"ttol failed","",errno);
        !          3830:            return(-1);
        !          3831:        } else {                        /* No error, so partial success */
        !          3832:            debug(F101,"ttol partial","",x);
        !          3833:            s += x;                     /* Point to part not written yet */
        !          3834:            n -= x;                     /* Adjust length */
        !          3835:            if (x > 0) msleep(100);     /* Wait 100 msec */
        !          3836:        }                               /* Go back and try again */
        !          3837:     }  
        !          3838:     return(n < 1 ? len : -1);          /* Too many tries */
        !          3839: }
        !          3840: 
        !          3841: 
        !          3842: 
        !          3843: /*  T T O C  --  Output a character to the communication line  */
        !          3844: 
        !          3845: /*
        !          3846:  This function should only be used for interactive, character-mode operations,
        !          3847:  like terminal connection, script execution, dialer i/o, where the overhead
        !          3848:  of the signals and alarms does not create a bottleneck.
        !          3849: */
        !          3850: int
        !          3851: #ifdef CK_ANSIC
        !          3852: ttoc(char c)
        !          3853: #else
        !          3854: ttoc(c) char c;
        !          3855: #endif /* CK_ANSIC */
        !          3856: /* ttoc */ {
        !          3857:     c &= 0xff;
        !          3858:     /* debug(F101,"ttoc","",(CHAR) c); */
        !          3859:     if (ttyfd < 0) return(-1);          /* Check for not open. */
        !          3860:     saval = signal(SIGALRM,timerh);    /* Enable timer interrupt */
        !          3861:     alarm(2);                          /* for 2 seconds. */
        !          3862:     if (setjmp(sjbuf)) {               /* Timer went off? */
        !          3863:        ttimoff();                      /* Yes, turn off the alarm. */
        !          3864:        conoc('\07');                   /* Ring the bell. */
        !          3865:         debug(F100,"ttoc timed out","",0); /* Log a message. */
        !          3866:        if (ttflow == FLO_XONX) {
        !          3867:            debug(F100,"ttoc flow","",ttflow);  /* Maybe we're xoff'd */
        !          3868: #ifdef POSIX
        !          3869:            debug(F100,"ttoc tcflow","",0); /* POSIX way to unstick. */
        !          3870:            tcflow(ttyfd,TCOON);
        !          3871: #else
        !          3872: #ifdef BSD4                            /* Berkeley way to do it. */
        !          3873: #ifdef TIOCSTART
        !          3874:            debug(F100,"ttoc TIOCSTART","",0);
        !          3875:            ioctl(ttyfd, TIOCSTART, 0);
        !          3876: #endif /* TIOCSTART */
        !          3877: #endif /* BSD4 */
        !          3878: #endif /* POSIX */
        !          3879:        }
        !          3880:        return(-1);                     /* Return failure code. */
        !          3881:     } else {
        !          3882:        if (write(ttyfd,&c,1) < 1) {    /* Try to write the character. */
        !          3883:            ttimoff();                  /* If error, turn off timer, */
        !          3884:            conoc('\07');               /* ring the bell, */
        !          3885:            debug(F101,"ttoc error","",errno); /* log the error, */
        !          3886:            return(-1);                 /* and return the error code. */
        !          3887:        }
        !          3888:     }
        !          3889:     ttimoff();                         /* Success, turn off timer. */
        !          3890:     return(0);
        !          3891: }
        !          3892: 
        !          3893: /*  T T I N L  --  Read a record (up to break character) from comm line.  */
        !          3894: /*
        !          3895:   Reads up to "max" characters from the communication line, terminating on:
        !          3896: 
        !          3897:     (a) the packet length field if the "turn" argument is zero, or
        !          3898:     (b) on the packet-end character (eol) if the "turn" argument is nonzero
        !          3899: 
        !          3900:   and returns the number of characters read upon success, or if "max" was
        !          3901:   exceeded or the timeout interval expired before (a) or (b), returns -1.
        !          3902: 
        !          3903:   The characters that were input are copied into "dest" with their parity bits
        !          3904:   stripped if parity was selected.  Returns the number of characters read.
        !          3905:   Characters after the eol are available upon the next call to this function.
        !          3906: 
        !          3907:   The idea is to minimize the number of system calls per packet, and also to
        !          3908:   minimize timeouts.  This function is the inner loop of the program and must
        !          3909:   be as efficient as possible.  The current strategy is to use myread().
        !          3910: 
        !          3911:   WARNING: this function calls parchk(), which is defined in another module.
        !          3912:   Normally, ckutio.c does not depend on code from any other module, but there
        !          3913:   is an exception in this case because all the other ck?tio.c modules also
        !          3914:   need to call parchk(), so it's better to have it defined in a common place.
        !          3915: */
        !          3916: #ifdef CTRLC
        !          3917: #undef CTRLC
        !          3918: #endif /* CTRLC */
        !          3919: #define CTRLC '\03'
        !          3920: /*
        !          3921:   We have four different declarations here because:
        !          3922:   (a) to allow Kermit to be built without the automatic parity sensing feature
        !          3923:   (b) one of each type for ANSI C, one for non-ANSI.
        !          3924: */
        !          3925: int
        !          3926: #ifdef PARSENSE
        !          3927: #ifdef CK_ANSIC
        !          3928: ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
        !          3929: #else
        !          3930: ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
        !          3931: #endif /* CK_ANSIC */
        !          3932: #else /* not PARSENSE */
        !          3933: #ifdef CK_ANSIC
        !          3934: ttinl(CHAR *dest, int max,int timo, CHAR eol)
        !          3935: #else
        !          3936: ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
        !          3937: #endif /* __SDTC__ */
        !          3938: #endif /* PARSENSE */
        !          3939: /* ttinl */ {
        !          3940: 
        !          3941: #ifndef MYREAD
        !          3942:     CHAR ch;
        !          3943: #endif /* MYREAD */
        !          3944: #ifdef PARSENSE
        !          3945:     int pktlen = -1;
        !          3946:     int lplen = 0;
        !          3947:     int havelen = 0;
        !          3948: #endif /* PARSENSE */
        !          3949: 
        !          3950:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          3951: 
        !          3952:     debug(F101,"ttinl max","",max);
        !          3953:     debug(F101,"ttinl timo","",timo);
        !          3954: 
        !          3955:     *dest = '\0';                       /* Clear destination buffer */
        !          3956:     if (timo < 0) timo = 0;            /* Safety */
        !          3957:     if (timo) {                                /* Don't time out if timo == 0 */
        !          3958:        saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
        !          3959:        alarm(timo);                    /* Set it. */
        !          3960:     }
        !          3961:     if (setjmp(sjbuf)) {                /* Timer went off? */
        !          3962:        debug(F100,"ttinl timout","",0); /* Get here on timeout. */
        !          3963:        debug(F110," with",(char *) dest,0);
        !          3964:        ttimoff();                      /* Turn off timer */
        !          3965:        return(-1);                     /* and return error code. */
        !          3966:     } else {
        !          3967:        register int i, m, n;           /* local variables */
        !          3968:        int ccn = 0;
        !          3969: #ifdef PARSENSE
        !          3970:        int flag = 0;
        !          3971: 
        !          3972:        debug(F000,"ttinl start","",start);
        !          3973:        flag = 0;                       /* Start of packet flag */
        !          3974: #endif /* PARSENSE */
        !          3975: 
        !          3976:        ttpmsk = m = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */
        !          3977: 
        !          3978: #ifdef SUNX25
        !          3979:         if (netconn && (ttnet == NET_SX25))
        !          3980: #ifdef PARSENSE
        !          3981:          return(x25inl(dest,max,timo,eol,start));
        !          3982: #else
        !          3983:          return(x25inl(dest,max,timo,eol));
        !          3984: #endif /* PARSENSE */
        !          3985: #endif /* SUNX25 */
        !          3986: 
        !          3987: /* Now read into destination, stripping parity and looking for the */
        !          3988: /* the packet terminator, and also for two Ctrl-C's typed in a row. */
        !          3989: 
        !          3990:        i = 0;                          /* Destination index */
        !          3991:        debug(F101,"ttinl eol","",eol);
        !          3992: 
        !          3993: #ifdef MYREAD
        !          3994:        while (i < max-1) {
        !          3995:            /* debug(F101,"ttinl i","",i); */
        !          3996:            if ((n = myread()) < 0) {
        !          3997:                debug(F101,"ttinl myread failure, n","",n);
        !          3998:                debug(F101,"ttinl myread errno,","",errno);
        !          3999:                /* Don't let EINTR break packets. */
        !          4000:                if (n == -3 && errno == EINTR && i > 0) {
        !          4001:                    debug(F101,"ttinl myread i","",i);
        !          4002:                    continue;
        !          4003:                }
        !          4004:                break;
        !          4005:            }
        !          4006: #else
        !          4007:        while ((i < max-1)  &&  (n = read(ttyfd, &ch, 1)) > 0) {
        !          4008:            n = ch;
        !          4009: #endif /* MYREAD */
        !          4010: 
        !          4011:            /* debug(F101,"ttinl char","", (n & ttpmsk)); */
        !          4012: 
        !          4013: #ifdef PARSENSE
        !          4014: /*
        !          4015:   Figure out what the length is supposed to be in case the packet
        !          4016:   has no terminator (as with Honeywell GCOS-8 Kermit).
        !          4017: */
        !          4018: #ifndef xunchar
        !          4019: #define xunchar(ch) (((ch) - 32 ) & 0xFF )     /* Character to number */
        !          4020: #endif /* xunchar */
        !          4021:            if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
        !          4022:            if (flag) dest[i++] = n & ttpmsk;
        !          4023: /*
        !          4024:   If we have not been instructed to wait for a turnaround character, we
        !          4025:   can go by the packet length field.  If turn != 0, we must wait for the
        !          4026:   end of line (eol) character before returning.
        !          4027: */
        !          4028:            if (i == 2) {
        !          4029:                pktlen = xunchar(dest[1]);
        !          4030:                havelen = (pktlen > 1);
        !          4031:                debug(F101,"ttinl length","",pktlen);
        !          4032:            } else if (i == 5 && pktlen == 0) {
        !          4033:                lplen = xunchar(dest[4]);
        !          4034:            } else if (i == 6 && pktlen == 0) {
        !          4035:                pktlen = lplen * 95 + xunchar(dest[5]) + 5;
        !          4036:                havelen = 1;
        !          4037:                debug(F101,"ttinl length","",pktlen);
        !          4038:            }
        !          4039: #else
        !          4040:            dest[i++] = n & ttpmsk;
        !          4041: #endif /* PARSENSE */
        !          4042:            if ((n & 0x7f) == CTRLC) {  /* Check for ^C^C */
        !          4043:                if (++ccn > 1) {        /* If we got 2 in a row, bail out. */
        !          4044:                    if (timo) {         /* Clear timer. */
        !          4045:                        ttimoff();
        !          4046:                    }
        !          4047:                    fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
        !          4048:                    return(-2);
        !          4049:                }
        !          4050:            } else ccn = 0;             /* Not ^C, so reset ^C counter, */
        !          4051: 
        !          4052: #ifdef PARSENSE
        !          4053:            if (flag == 0) {
        !          4054:                debug(F101,"ttinl skipping","",n);
        !          4055:                continue;
        !          4056:            }
        !          4057: #endif /* PARSENSE */
        !          4058: 
        !          4059:     /* Check for end of packet */
        !          4060: 
        !          4061:            if (((n & 0x7f) == eol)
        !          4062: #ifdef PARSENSE
        !          4063:                || (!turn && havelen && (i > pktlen+1))
        !          4064: #endif /* PARSENSE */
        !          4065:                ) {
        !          4066: #ifndef PARSENSE
        !          4067:                debug(F101,"ttinl got eol","",eol);
        !          4068:                dest[i] = '\0'; /* Yes, terminate the string, */
        !          4069:                /* debug(F101,"ttinl i","",i); */
        !          4070: #else
        !          4071:                if ((n & 0x7f) != eol) {
        !          4072:                    debug(F101,"ttinl EOP length","",pktlen);
        !          4073:                    debug(F101,"ttinl i","",i);
        !          4074:                } else debug(F101,"ttinl got eol","",eol);
        !          4075:                dest[i] = '\0';         /* Terminate the string, */
        !          4076: 
        !          4077: /* Here's where we actually check and adjust the parity. */
        !          4078: /* The major flaw here is if parity is NONE (ttprty = 0) and the packets */
        !          4079: /* really do have no parity, then parchk() is called for every packet. */
        !          4080: /* In practice, this doesn't really harm efficiency noticably, but it would */
        !          4081: /* be better if ttinl() had a way of knowing to stop doing this once a */
        !          4082: /* particular file transfer had been started and checked. */
        !          4083:                if (ttprty == 0) {
        !          4084:                    if ((ttprty = parchk(dest,start,i)) > 0) {
        !          4085:                        int j;
        !          4086:                        debug(F101,"ttinl senses parity","",ttprty);
        !          4087:                        debug(F110,"ttinl packet before",dest,0);
        !          4088:                        ttpmsk = 0x7f;
        !          4089:                        for (j = 0; j < i; j++)
        !          4090:                          dest[j] &= 0x7f;      /* Strip parity from packet */
        !          4091:                        debug(F110,"ttinl packet after ",dest,0);
        !          4092:                    } else debug(F101,"parchk","",ttprty);
        !          4093:                }
        !          4094: #endif /* PARSENSE */
        !          4095:                if (timo) {                     /* Turn off timer. */
        !          4096:                    ttimoff();
        !          4097:                }
        !          4098:                debug(F111,"ttinl got", dest,i);
        !          4099:                return(i);
        !          4100:            }
        !          4101:        }                               /* end of while() */
        !          4102:        ttimoff();
        !          4103:        return(-1);
        !          4104:     }
        !          4105: }
        !          4106: 
        !          4107: /*  T T I N C --  Read a character from the communication line  */
        !          4108: /*
        !          4109:  On success, returns the character that was read, >= 0.
        !          4110:  On failure, returns -1 or other negative myread error code.
        !          4111: */
        !          4112: int
        !          4113: ttinc(timo) int timo; {
        !          4114: 
        !          4115:     int n = 0;
        !          4116: #ifndef MYREAD
        !          4117:     CHAR ch = 0;
        !          4118: #endif /* MYREAD */
        !          4119: 
        !          4120:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          4121:     if (timo <= 0) {                    /* Untimed. */
        !          4122: #ifdef MYREAD
        !          4123:         /* comm line failure returns -1 thru myread, so no &= 0377 */
        !          4124:        n = myread();                   /* Wait for a character... */
        !          4125:        /* debug(F101,"ttinc n","",n); */
        !          4126:        return(n < 0 ? n : n & ttpmsk);
        !          4127: #else
        !          4128:         while ((n = read(ttyfd,&ch,1)) == 0) /* Wait for a character. */
        !          4129:         /* Shouldn't have to loop in ver 5A. */
        !          4130: #ifdef NETCONN   
        !          4131:          if (netconn) {                /* Special handling for net */
        !          4132:              netclos();
        !          4133:              netconn = 0;
        !          4134:              errno = ENOTCONN;
        !          4135:              return(-2);
        !          4136:          }
        !          4137: #endif /* NETCONN */
        !          4138:          ;
        !          4139: /* debug(F000,"ttinc","",ch); */
        !          4140:         return( (n < 1) ? -3 : (ch & ttpmsk) );
        !          4141: #endif /* MYREAD */
        !          4142:     } else {
        !          4143:        saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
        !          4144:        alarm(timo);
        !          4145:        if (setjmp(sjbuf)) {
        !          4146:            n = -1;
        !          4147:        } else {
        !          4148: #ifdef MYREAD
        !          4149:            n = myread();               /* If managing own buffer... */
        !          4150:            debug(F101,"ttinc myread","",n);
        !          4151: #else
        !          4152:            n = read(ttyfd,&ch,1);      /* Otherwise call the system. */
        !          4153:            debug(F101,"ttinc read","",n);
        !          4154:            if (n > 0)
        !          4155:              n = ch & 255;
        !          4156:            else
        !          4157:              n = (n < 0) ? -3 : -2;    /* Special return codes */
        !          4158: #endif /* MYREAD */
        !          4159:        }
        !          4160:        ttimoff();                      /* Turn off timer */
        !          4161: #ifdef NETCONN
        !          4162:        if (netconn) {
        !          4163:            if (n == -2) {              /* read() returns 0 */
        !          4164:                netclos();              /* on network read failure */
        !          4165:                netconn = 0;
        !          4166:                errno = ENOTCONN;
        !          4167:            }
        !          4168:        }
        !          4169: #endif /* NETCONN */
        !          4170:        return( (n < 0) ? n : (n & ttpmsk) ); /* Return masked char or neg. */
        !          4171:     }
        !          4172: }
        !          4173: 
        !          4174: /*  S N D B R K  --  Send a BREAK signal of the given duration  */
        !          4175: 
        !          4176: static int
        !          4177: #ifdef CK_ANSIC
        !          4178: sndbrk(int msec) {                     /* Argument is milliseconds */
        !          4179: #else
        !          4180: sndbrk(msec) int msec; {
        !          4181: #endif /* CK_ANSIC */
        !          4182: #ifndef POSIX
        !          4183:     int x, n;
        !          4184: #endif /* POSIX */
        !          4185: 
        !          4186: #ifdef ANYBSD
        !          4187: #define BSDBREAK
        !          4188: #endif /* ANYBSD */
        !          4189: 
        !          4190: #ifdef COHERENT
        !          4191: #define BSDBREAK
        !          4192: #endif /* COHERENT */
        !          4193: 
        !          4194: #ifdef PROVX1
        !          4195:     char spd;
        !          4196: #endif /* PROVX1 */
        !          4197: 
        !          4198:     debug(F101,"ttsndb ttyfd","",ttyfd);
        !          4199:     if (ttyfd < 0) return(-1);          /* Not open. */
        !          4200: 
        !          4201: #ifdef NETCONN
        !          4202:     if (netconn)                       /* Send network BREAK */
        !          4203:       return(netbreak());
        !          4204: #endif /* NETCONN */
        !          4205: 
        !          4206:     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
        !          4207: 
        !          4208: #ifdef POSIX                           /* Easy in POSIX */
        !          4209:     return(tcsendbreak(ttyfd,msec / 375));
        !          4210: #else
        !          4211: #ifdef PROVX1
        !          4212:     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
        !          4213:     spd = ttbuf.sg_ospeed;              /* Save speed */
        !          4214:     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
        !          4215:     stty(ttyfd,&ttbuf);                 /*  ... */
        !          4216:     n = (int)strlen(brnuls);           /* Send the right number of nulls */
        !          4217:     x = msec / 91;
        !          4218:     if (x > n) x = n;
        !          4219:     write(ttyfd,brnuls,n);
        !          4220:     ttbuf.sg_ospeed = spd;              /* Restore speed */
        !          4221:     stty(ttyfd,&ttbuf);                 /*  ... */
        !          4222:     return(0);
        !          4223: #else
        !          4224: #ifdef aegis
        !          4225:     sio_$control((short)ttyfd, sio_$send_break, msec, st);
        !          4226:     return(0);
        !          4227: #else
        !          4228: #ifdef ATTSV
        !          4229: /*
        !          4230:   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
        !          4231:   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
        !          4232:   but there's no way for this code to know for sure.)
        !          4233: */
        !          4234:     x = msec / 275;
        !          4235:     for (n = 0; n < x; n++) {
        !          4236:        if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) {
        !          4237:            perror("Can't send BREAK");
        !          4238:            return(-1);
        !          4239:        }
        !          4240:     }
        !          4241:     return(0);
        !          4242: #else
        !          4243: #ifdef BSDBREAK
        !          4244:     n = FWRITE;                         /* Flush output queue. */
        !          4245: /* Watch out for int vs long problems in &n arg! */
        !          4246:     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
        !          4247:     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
        !          4248:         perror("Can't send BREAK");
        !          4249:         return(-1);
        !          4250:     }
        !          4251:     x = msleep(msec);                    /* Sleep for so many milliseconds */
        !          4252:     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
        !          4253:         perror("BREAK stuck!!!");
        !          4254:         doexit(BAD_EXIT,-1);           /* Get out, closing the line. */
        !          4255:                                         /*   with bad exit status */
        !          4256:     }
        !          4257:     return(x);
        !          4258: #else
        !          4259: #ifdef  V7
        !          4260:     return(genbrk(ttyfd,250));         /* Simulate a BREAK */
        !          4261: #endif /* V7 */
        !          4262: #endif /* BSDBREAK */
        !          4263: #endif /* ATTSV */
        !          4264: #endif /* aegis */
        !          4265: #endif /* PROVX1 */
        !          4266: #endif /* POSIX */
        !          4267: }
        !          4268: 
        !          4269: /*  T T S N D B  --  Send a BREAK signal  */
        !          4270: 
        !          4271: int
        !          4272: ttsndb() {
        !          4273:     return(sndbrk(275));
        !          4274: }
        !          4275: 
        !          4276: /*  T T S N D L B  --  Send a Long BREAK signal  */
        !          4277: 
        !          4278: int
        !          4279: ttsndlb() {
        !          4280:     return(sndbrk(1500));
        !          4281: }
        !          4282: 
        !          4283: /*  M S L E E P  --  Millisecond version of sleep().  */
        !          4284: 
        !          4285: /*
        !          4286:   Call with number of milliseconds (thousandths of seconds) to sleep.
        !          4287:   Intended only for small intervals.  For big ones, just use sleep().
        !          4288:   Highly system-dependent.
        !          4289:   Returns 0 always, even if it didn't work.
        !          4290: */
        !          4291: 
        !          4292: /* Define MSLFTIME for systems that must use an ftime() loop. */
        !          4293: #ifdef ANYBSD                          /* For pre-4.2 BSD versions */
        !          4294: #ifndef BSD42
        !          4295: #define MSLFTIME
        !          4296: #endif /* BSD42 */
        !          4297: #endif /* ANYBSD */
        !          4298: #ifdef TOWER1                          /* NCR Tower OS 1.0 */
        !          4299: #define MSLFTIME
        !          4300: #endif /* TOWER1 */
        !          4301: #ifdef COHERENT                                /* Coherent */
        !          4302: #ifndef _I386                          /* not used in the 386 version (4.0) */
        !          4303: #define MSLFTIME 
        !          4304: #endif /* _I386 */
        !          4305: #endif /* COHERENT */
        !          4306: 
        !          4307: int
        !          4308: msleep(m) int m; {
        !          4309: 
        !          4310: #ifndef USLEEP
        !          4311: #ifdef SUNOS4                          /* Systems that have usleep() */
        !          4312: #define USLEEP
        !          4313: #endif /* SUNOS4 */
        !          4314: #ifdef SUN4S5
        !          4315: #define USLEEP
        !          4316: #endif /* SUN4S5 */
        !          4317: #ifdef NEXT
        !          4318: #define USLEEP
        !          4319: #endif /* NEXT*/
        !          4320: #endif /* USLEEP */
        !          4321: 
        !          4322: #ifdef AIXRS
        !          4323: /* RS/6000 can do select() */
        !          4324: #define BSD4
        !          4325: #endif /* AIXRS */
        !          4326: 
        !          4327: #ifdef USLEEP
        !          4328: /*
        !          4329:   "This routine is implemented using setitimer(2); it requires eight
        !          4330:   system calls...".  In other words, it might take 5 minutes to sleep
        !          4331:   for 100 milliseconds...
        !          4332: */
        !          4333:     if (m >= 1000) {                   /* Catch big arguments. */
        !          4334:        sleep(m/1000);
        !          4335:        m = m % 1000;
        !          4336:        if (m < 10) return(0);
        !          4337:     }
        !          4338:     usleep((unsigned int)(m * 1000));
        !          4339:     return(0);
        !          4340: #else
        !          4341: #ifdef aegis
        !          4342:     time_$clock_t dur;
        !          4343: 
        !          4344:     dur.c2.high16 = 0;
        !          4345:     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
        !          4346:     time_$wait(time_$relative, dur, st);
        !          4347:     return(0);
        !          4348: #else
        !          4349: #ifdef PROVX1
        !          4350:     if (m <= 0) return(0);
        !          4351:     sleep(-((m * 60 + 500) / 1000));
        !          4352:     return(0);
        !          4353: #else
        !          4354: #ifdef NAP
        !          4355:     nap((long)m);
        !          4356:     return(0);
        !          4357: #else
        !          4358: #ifdef BSD42
        !          4359: /* BSD 4.2 & above can do it with select()... */
        !          4360:     int t1;
        !          4361:     if (m <= 0) return(0);
        !          4362:     if (m >= 1000) {                   /* Catch big arguments. */
        !          4363:        sleep(m/1000);
        !          4364:        m = m % 1000;
        !          4365:        if (m < 10) return(0);
        !          4366:     }
        !          4367:     if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */
        !          4368:     t1 = tv.tv_sec;                     /* Seconds */
        !          4369:     tv.tv_sec = 0;                      /* Use select() */
        !          4370:     tv.tv_usec = m * 1000L;
        !          4371:     select( 0, (int *)0, (int *)0, (int *)0, &tv );
        !          4372:     return(0);
        !          4373: #ifdef AIXRS
        !          4374: /* Don't pretend we're BSD any more! */
        !          4375: #undef BSD4
        !          4376: #endif /* AIXRS */
        !          4377: 
        !          4378: #else
        !          4379: #ifdef ATTSV
        !          4380:     extern long times();               /* Or #include <times.h> ? */
        !          4381:     long t1, t2, tarray[4];
        !          4382:     int t3;
        !          4383: 
        !          4384: #ifdef COMMENT
        !          4385: /* This better be picked up in ckcdeb.h... */
        !          4386:     char *getenv();
        !          4387: #endif /* COMMENT */
        !          4388:     char *cp = getenv("HZ");
        !          4389:     int CLOCK_TICK;
        !          4390:     int hertz;
        !          4391: 
        !          4392:     if (cp && (hertz = atoi(cp))) {
        !          4393:         CLOCK_TICK  = 1000 / hertz;
        !          4394:     } else {                           /* probably single user mode */
        !          4395: #ifdef HZ
        !          4396:         CLOCK_TICK  = 1000 / HZ;       
        !          4397: #else
        !          4398:        static warned = 0;
        !          4399:        /* HZ always exists in, for instance, SCO Xenix, so you don't have to
        !          4400:         * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
        !          4401:         * have Xenix, you have should have nap(), so the best is to use -DNAP
        !          4402:         * in the makefile. Most systems have HZ.
        !          4403:         */
        !          4404:        CLOCK_TICK = 17;                /* 1/60 sec */
        !          4405:        if (!warned) {
        !          4406:           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
        !          4407:                 1000 / CLOCK_TICK);
        !          4408:           warned = 1;
        !          4409:        }
        !          4410: #endif /* !HZ */
        !          4411:     }
        !          4412: 
        !          4413:     if (m <= 0) return(0);
        !          4414:     if (m >= 1000) {                   /* Catch big arguments. */
        !          4415:        sleep(m/1000);
        !          4416:        m = m % 1000;
        !          4417:        if (m < 10) return(0);
        !          4418:     }
        !          4419:     if ((t1 = times(tarray)) < 0) return(-1);
        !          4420:     while (1) {
        !          4421:         if ((t2 = times(tarray)) < 0) return(-1);
        !          4422:         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
        !          4423:         if (t3 > m) return(t3);
        !          4424:     }
        !          4425: #else /* Not ATTSV */
        !          4426: #ifdef MSLFTIME                                /* Use ftime() loop... */
        !          4427:     int t1, t3 = 0;
        !          4428:     if (m <= 0) return(0);
        !          4429:     if (m >= 1000) {                   /* Catch big arguments. */
        !          4430:        sleep(m/1000);
        !          4431:        m = m % 1000;
        !          4432:        if (m < 10) return(0);
        !          4433:     }
        !          4434:     if (ftime(&ftp) < 0) return(-1);   /* Get base time. */
        !          4435:     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
        !          4436:     while (1) {
        !          4437:         ftime(&ftp);                   /* Get current time and compare. */
        !          4438:         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
        !          4439:         if (t3 > m) return(0);
        !          4440:     }
        !          4441: #else
        !          4442: /* This includes true POSIX, which has no way to do this. */
        !          4443:     if (m >= 1000) {                   /* Catch big arguments. */
        !          4444:        sleep(m/1000);
        !          4445:        m = m % 1000;
        !          4446:        if (m < 10) return(0);
        !          4447:     }
        !          4448:     if (m > 0) while (m > 0) m--;      /* Just a dumb busy loop */
        !          4449:     return(0);
        !          4450: #endif /* MLSFTIME */
        !          4451: #endif /* ATTSV */
        !          4452: #endif /* BSD42 */
        !          4453: #endif /* NAP */
        !          4454: #endif /* PROVX1 */
        !          4455: #endif /* aegis */
        !          4456: #endif /* USLEEP */
        !          4457: }
        !          4458: 
        !          4459: /*  R T I M E R --  Reset elapsed time counter  */
        !          4460: 
        !          4461: VOID
        !          4462: rtimer() {
        !          4463:     tcount = time( (time_t *) 0 );
        !          4464: }
        !          4465: 
        !          4466: 
        !          4467: /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
        !          4468: 
        !          4469: int
        !          4470: gtimer() {
        !          4471:     int x;
        !          4472:     x = (int) (time( (time_t *) 0 ) - tcount);
        !          4473:     debug(F101,"gtimer","",x);
        !          4474:     return( (x < 0) ? 0 : x );
        !          4475: }
        !          4476: 
        !          4477: 
        !          4478: /*  Z T I M E  --  Return date/time string  */
        !          4479: 
        !          4480: VOID
        !          4481: ztime(s) char **s; {
        !          4482: 
        !          4483: #undef ZTIMEV7                         /* Which systems need to use */
        !          4484: #ifdef COHERENT                                /* old UNIX Version 7 way... */
        !          4485: #define ZTIMEV7
        !          4486: #endif /* COHERENT */
        !          4487: #ifdef TOWER1
        !          4488: #define ZTIMEV7
        !          4489: #endif /* TOWER1 */
        !          4490: #ifdef ANYBSD
        !          4491: #ifndef BSD42
        !          4492: #define ZTIMEV7
        !          4493: #endif /* BSD42 */
        !          4494: #endif /* ANYBSD */
        !          4495: #ifdef V7
        !          4496: #ifndef MINIX
        !          4497: #define ZTIMEV7
        !          4498: #endif /* MINIX */
        !          4499: #endif /* V7 */
        !          4500: #ifdef POSIX
        !          4501: #define ZTIMEV7
        !          4502: #endif /* POSIX */
        !          4503: 
        !          4504: #ifdef ATTSV                           /* AT&T way */
        !          4505: /*  extern long time(); */             /* Theoretically these should */
        !          4506:     char *ctime();                     /* already been dcl'd in <time.h> */
        !          4507:     long clock_storage;
        !          4508:     clock_storage = time( (long *) 0 );
        !          4509:     *s = ctime( &clock_storage );
        !          4510: #else
        !          4511: #ifdef PROVX1                          /* Venix 1.0 way */
        !          4512:     int utime[2];
        !          4513:     time(utime);
        !          4514:     *s = ctime(utime);
        !          4515: #else
        !          4516: #ifdef BSD42                           /* 4.2BSD way */
        !          4517:     char *asctime();
        !          4518:     struct tm *localtime();
        !          4519:     struct tm *tp;
        !          4520:     gettimeofday(&tv, &tz);
        !          4521:     time(&tv.tv_sec);
        !          4522:     tp = localtime(&tv.tv_sec);
        !          4523:     *s = asctime(tp);
        !          4524: #else
        !          4525: #ifdef MINIX                           /* MINIX way */
        !          4526: #ifdef COMMENT
        !          4527:     extern long time();                        /* Already got these from <time.h> */
        !          4528:     extern char *ctime();
        !          4529: #endif /* COMMENT */
        !          4530:     time_t utime[2];
        !          4531:     time(utime);
        !          4532:     *s = ctime(utime);
        !          4533: #else
        !          4534: #ifdef ZTIMEV7                         /* The regular way */
        !          4535:     char *asctime();
        !          4536:     struct tm *localtime();
        !          4537:     struct tm *tp;
        !          4538:     long xclock;
        !          4539:     time(&xclock);
        !          4540:     tp = localtime(&xclock);
        !          4541:     *s = asctime(tp);
        !          4542: #else                                  /* Catch-all for others... */
        !          4543:     *s = "Ddd Mmm 00 00:00:00 0000\n"  /* Return dummy in asctime() format */
        !          4544: #endif /* ZTIMEV7 */
        !          4545: #endif /* MINIX */
        !          4546: #endif /* BSD42 */
        !          4547: #endif /* PROVX1 */
        !          4548: #endif /* SVORPOSIX */
        !          4549: }
        !          4550: 
        !          4551: /*  C O N G M  --  Get console terminal modes.  */
        !          4552: 
        !          4553: /*
        !          4554:   Saves initial console mode, and establishes variables for switching
        !          4555:   between current (presumably normal) mode and other modes.
        !          4556:   Should be called when program starts, but only after establishing
        !          4557:   whether program is in the foreground or background.
        !          4558:   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
        !          4559: */
        !          4560: int
        !          4561: congm() {
        !          4562:     int fd;
        !          4563:     if (backgrd || !isatty(0)) {       /* If in background. */
        !          4564:        cgmf = -1;                      /* Don't bother, modes are garbage. */
        !          4565:        return(-1);
        !          4566:     }
        !          4567:     if (cgmf > 0) return(0);           /* Already did this. */
        !          4568:     debug(F100,"congm getting modes","",0); /* Need to do it. */
        !          4569: #ifdef aegis
        !          4570:     ios_$inq_type_uid(ios_$stdin, conuid, st);
        !          4571:     if (st.all != status_$ok) {
        !          4572:        fprintf(stderr, "problem getting stdin objtype: ");
        !          4573:        error_$print(st);
        !          4574:     }
        !          4575:     concrp = (conuid == mbx_$uid);
        !          4576:     conbufn = 0;
        !          4577: #endif /* aegis */
        !          4578: 
        !          4579:     if ((fd = open(CTTNAM,2)) < 0) {   /* Open controlling terminal */
        !          4580:        fprintf(stderr,"Error opening %s\n", CTTNAM);
        !          4581:        perror("congm");
        !          4582:        return(-1);
        !          4583:     }
        !          4584: #ifdef ATTSV
        !          4585:     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
        !          4586:     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
        !          4587:     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
        !          4588: #ifdef VXVE
        !          4589:     cccbrk.c_line = 0;                 /* STTY line 0 for CDC VX/VE */
        !          4590:     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
        !          4591:     ccraw.c_line = 0;                  /* STTY line 0 for CDC VX/VE */
        !          4592:     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
        !          4593: #endif /* VXVE */
        !          4594: #else
        !          4595: #ifdef POSIX
        !          4596:     if (tcgetattr(fd,&ccold) < 0) return(-1);
        !          4597:     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
        !          4598:     if (tcgetattr(fd,&ccraw) < 0) return(-1);
        !          4599: #else
        !          4600:     if (gtty(fd,&ccold) < 0) return(-1);
        !          4601:     if (gtty(fd,&cccbrk) < 0) return(-1);
        !          4602:     if (gtty(fd,&ccraw) < 0) return(-1);
        !          4603: #endif /* POSIX */
        !          4604: #endif /* ATTSV */
        !          4605: #ifdef sony_news                       /* Sony NEWS */
        !          4606:     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
        !          4607:        perror("congm error getting Kanji mode");
        !          4608:        debug(F101,"congm error getting Kanji mode","",0);
        !          4609:        km_con = -1;                    /* Make sure this stays undefined. */
        !          4610:        return(-1);
        !          4611:     }
        !          4612: #endif /* sony_news */
        !          4613:     close(fd);
        !          4614:     cgmf = 1;                          /* Flag that we got them. */
        !          4615:     return(1);
        !          4616: }
        !          4617: 
        !          4618: 
        !          4619: /*  C O N C B --  Put console in cbreak mode.  */
        !          4620: 
        !          4621: /*  Returns 0 if ok, -1 if not  */
        !          4622: 
        !          4623: int
        !          4624: #ifdef CK_ANSIC
        !          4625: concb(char esc)
        !          4626: #else
        !          4627: concb(esc) char esc;
        !          4628: #endif /* CK_ANSIC */
        !          4629: /* concb */ {
        !          4630:     int x;
        !          4631:     debug(F101,"concb backgrd","",backgrd);
        !          4632:     if (!isatty(0)) return(0);          /* Only for real ttys */
        !          4633:     debug(F100,"concb isatty","",0);
        !          4634:     if (backgrd) return(0);            /* Do nothing if in background. */
        !          4635:     escchr = esc;                       /* Make this available to other fns */
        !          4636:     ckxech = 1;                         /* Program can echo characters */
        !          4637: #ifdef aegis
        !          4638:     conbufn = 0;
        !          4639:     if (concrp) return(write(1, "\035\002", 2));
        !          4640:     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
        !          4641: #endif
        !          4642: #ifndef SVORPOSIX                      /* BSD, V7, etc */
        !          4643:     cccbrk.sg_flags |= CBREAK;          /* Set to character wakeup, */
        !          4644:     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
        !          4645:     x = stty(0,&cccbrk);
        !          4646: #else                                  /* Sys V and POSIX */
        !          4647:     cccbrk.c_lflag &= ~(ICANON|ECHO);
        !          4648:     cccbrk.c_cc[0] = 003;               /* interrupt char is control-c */
        !          4649:     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
        !          4650:     cccbrk.c_cc[4] = 1;
        !          4651: #ifdef ZILOG
        !          4652:     cccbrk.c_cc[5] = 0;
        !          4653: #else
        !          4654:     cccbrk.c_cc[5] = 1;
        !          4655: #endif /* ZILOG */
        !          4656: #ifdef ATTSV                           /* Set new modes */
        !          4657:     x = ioctl(0,TCSETAW,&cccbrk);      /* the Sys V way */
        !          4658: #else /* POSIX */                              /* or the POSIX way */
        !          4659:     x = tcsetattr(0,TCSADRAIN,&cccbrk);
        !          4660: #endif /* ATTSV */
        !          4661: #endif /* SVORPOSIX */
        !          4662: 
        !          4663: #ifndef aegis
        !          4664: #ifndef NOSETBUF
        !          4665:     if (x > -1) setbuf(stdout,NULL);    /* Make console unbuffered. */
        !          4666: #endif /* NOSETBUF */
        !          4667: #endif /* aegis */
        !          4668: 
        !          4669: #ifdef  V7
        !          4670: #ifndef MINIX
        !          4671:     if (kmem[CON] < 0) {
        !          4672:         qaddr[CON] = initrawq(0);
        !          4673:         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
        !          4674:             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
        !          4675:             perror("/dev/kmem");
        !          4676:             exit(1);
        !          4677:         }
        !          4678:     }
        !          4679: #endif /* MINIX */
        !          4680: #endif /* V7 */
        !          4681:     debug(F101,"concb returns","",x);
        !          4682:     return(x);
        !          4683: }
        !          4684: 
        !          4685: /*  C O N B I N  --  Put console in binary mode  */
        !          4686: 
        !          4687: /*  Returns 0 if ok, -1 if not  */
        !          4688: 
        !          4689: int
        !          4690: #ifdef CK_ANSIC
        !          4691: conbin(char esc)
        !          4692: #else
        !          4693: conbin(esc) char esc;
        !          4694: #endif /* CK_ANSIC */
        !          4695: /* conbin */  {
        !          4696:     if (!isatty(0)) return(0);          /* only for real ttys */
        !          4697:     congm();                           /* Get modes if necessary. */
        !          4698:     debug(F100,"conbin","",0);
        !          4699:     escchr = esc;                       /* Make this available to other fns */
        !          4700:     ckxech = 1;                         /* Program can echo characters */
        !          4701: #ifdef aegis
        !          4702:     conbufn = 0;
        !          4703:     if (concrp) return(write(1, "\035\002", 2));
        !          4704:     if (conuid == input_pad_$uid)
        !          4705:       pad_$raw(ios_$stdin, st);
        !          4706:     return(0)
        !          4707: #endif /* aegis */
        !          4708: 
        !          4709: #ifdef SVORPOSIX
        !          4710:     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
        !          4711:     ccraw.c_iflag |= (BRKINT|IGNPAR);
        !          4712: #ifdef ATTSV
        !          4713:     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
        !          4714:                         |INPCK|ISTRIP);
        !          4715: #else /* POSIX */
        !          4716:     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
        !          4717: #endif /* ATTSV */
        !          4718:     ccraw.c_oflag &= ~OPOST;
        !          4719: #ifdef ATT7300
        !          4720:     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
        !          4721: #endif /* ATT7300 */
        !          4722: /*** Kermit used to put the console in 8-bit raw mode, but some users have
        !          4723:  *** pointed out that this should not be done, since some sites actually
        !          4724:  *** use terminals with parity settings on their Unix systems, and if we
        !          4725:  *** override the current settings and stop doing parity, then their terminals
        !          4726:  *** will display blotches for characters whose parity is wrong.  Therefore,
        !          4727:  *** the following two lines are commented out (Larry Afrin, Clemson U):
        !          4728:  ***
        !          4729:  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
        !          4730:  ***   ccraw.c_cflag |= (CS8|CREAD);
        !          4731:  ***
        !          4732:  *** Sys III/V sites that have trouble with this can restore these lines.
        !          4733:  ***/
        !          4734:     ccraw.c_cc[0] = 003;               /* Interrupt char is Ctrl-C */
        !          4735:     ccraw.c_cc[1] = escchr;            /* Escape during packet mode */
        !          4736:     ccraw.c_cc[4] = 1;
        !          4737: 
        !          4738: #ifdef ZILOG
        !          4739:     ccraw.c_cc[5] = 0;
        !          4740: #else
        !          4741:     ccraw.c_cc[5] = 1;
        !          4742: #endif /* ZILOG */
        !          4743: 
        !          4744: #ifdef ATTSV
        !          4745:     return(ioctl(0,TCSETAW,&ccraw));   /* Set new modes. */
        !          4746: #else
        !          4747:     return(tcsetattr(0,TCSADRAIN,&ccraw));
        !          4748: #endif /* ATTSV */
        !          4749: 
        !          4750: #else /* Berkeley, etc. */
        !          4751:     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
        !          4752:     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
        !          4753:     return(stty(0,&ccraw));
        !          4754: #endif /* SVORPOSIX */
        !          4755: }
        !          4756: 
        !          4757: 
        !          4758: /*  C O N R E S  --  Restore the console terminal  */
        !          4759: 
        !          4760: int
        !          4761: conres() {
        !          4762:     debug(F101,"conres cgmf","",cgmf);
        !          4763:     if (cgmf < 1) return(0);           /* Do nothing if modes unchanged */
        !          4764:     if (!isatty(0)) return(0);          /* only for real ttys */
        !          4765:     debug(F100,"conres isatty ok","",0);
        !          4766:     ckxech = 0;                         /* System should echo chars */
        !          4767: 
        !          4768: #ifdef aegis
        !          4769:     conbufn = 0;
        !          4770:     if (concrp) return(write(1, "\035\001", 2));
        !          4771:     if (conuid == input_pad_$uid)
        !          4772:       pad_$cooked(ios_$stdin, st);
        !          4773:     return(0);
        !          4774: #endif /* aegis */
        !          4775: 
        !          4776: #ifdef ATTSV
        !          4777:     debug(F100,"conres restoring ioctl","",0);
        !          4778:     return(ioctl(0,TCSETAW,&ccold));
        !          4779: #else
        !          4780: #ifdef POSIX
        !          4781:     debug(F100,"conres restoring tcsetattr","",0);
        !          4782:     return(tcsetattr(0,TCSADRAIN,&ccold));
        !          4783: #else /* BSD, V7, and friends */
        !          4784:     msleep(300);
        !          4785:     debug(F100,"conres restoring stty","",0);
        !          4786:     return(stty(0,&ccold));
        !          4787: #endif /* POSIX */
        !          4788: #endif /* ATTSV */
        !          4789: #ifdef sony_news                       /* Sony NEWS */
        !          4790:     return(ioctl(0,TIOCKSET,&km_con)); /* Restore console Kanji mode */
        !          4791: #endif /* sony_news */
        !          4792: }
        !          4793: 
        !          4794: /*  C O N O C  --  Output a character to the console terminal  */
        !          4795: 
        !          4796: int
        !          4797: #ifdef CK_ANSIC
        !          4798: conoc(char c)
        !          4799: #else
        !          4800: conoc(c) char c;
        !          4801: #endif /* CK_ANSIC */
        !          4802: /* conoc */ {
        !          4803:     return(write(1,&c,1));
        !          4804: }
        !          4805: 
        !          4806: /*  C O N X O  --  Write x characters to the console terminal  */
        !          4807: 
        !          4808: int
        !          4809: conxo(x,s) int x; char *s; {
        !          4810:     return(write(1,s,x));
        !          4811: }
        !          4812: 
        !          4813: /*  C O N O L  --  Write a line to the console terminal  */
        !          4814: 
        !          4815: int
        !          4816: conol(s) char *s; {
        !          4817:     int len;
        !          4818:     len = (int)strlen(s);
        !          4819:     return(write(1,s,len));
        !          4820: }
        !          4821: 
        !          4822: /*  C O N O L A  --  Write an array of lines to the console terminal */
        !          4823: 
        !          4824: int
        !          4825: conola(s) char *s[]; {
        !          4826:     int i;
        !          4827:     for (i=0 ; *s[i] ; i++) if (conol(s[i]) < 0) return(-1);;
        !          4828:     return(0);
        !          4829: }
        !          4830: 
        !          4831: /*  C O N O L L  --  Output a string followed by CRLF  */
        !          4832: 
        !          4833: int
        !          4834: conoll(s) char *s; {
        !          4835:     conol(s);
        !          4836:     return(write(1,"\r\n",2));
        !          4837: }
        !          4838: 
        !          4839: /*  C O N C H K  --  Return how many characters available at console  */
        !          4840: 
        !          4841: int
        !          4842: conchk() {
        !          4843:     int x; PEEKTYPE n;
        !          4844: 
        !          4845:     if (!isatty(0)) return(0);
        !          4846: #ifdef PROVX1
        !          4847:     x = ioctl(0, TIOCQCNT, &ttbuf);
        !          4848:     n = ttbuf.sg_ispeed & 0377;
        !          4849:     return((x < 0) ? 0 : n);
        !          4850: #else
        !          4851: #ifdef aegis
        !          4852:     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
        !          4853: 
        !          4854:     /* read in more characters */
        !          4855:     conbufn = ios_$get(ios_$stdin,
        !          4856:               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
        !          4857:     if (st.all != status_$ok) conbufn = 0;
        !          4858:     conbufp = conbuf;
        !          4859:     return(conbufn);
        !          4860: #else
        !          4861: #ifdef V7
        !          4862: #ifdef MINIX
        !          4863:     return(0);
        !          4864: #else
        !          4865:     lseek(kmem[CON], (long) qaddr[CON], 0);
        !          4866:     x = read(kmem[CON], &n, sizeof(int));
        !          4867:     return((x == sizeof(int))? n: 0);
        !          4868: #endif /* MINIX */
        !          4869: #else
        !          4870: #ifdef SVORPOSIX
        !          4871:     if (conesc) {                       /* Escape typed */
        !          4872:         conesc = 0;
        !          4873:         signal(SIGQUIT,esctrp);         /* Restore escape */
        !          4874:         return(1);
        !          4875:     }
        !          4876:     return(0);
        !          4877: #else
        !          4878: #ifdef C70
        !          4879:     if (conesc) {                       /* Escape typed */
        !          4880:         conesc = 0;
        !          4881:         signal(SIGQUIT,esctrp);         /* Restore escape */
        !          4882:         return(1);
        !          4883:     }
        !          4884:     return(0);
        !          4885: #else
        !          4886: #ifdef FIONREAD
        !          4887:     x = ioctl(0, FIONREAD, &n);         /* BSD and maybe some others */
        !          4888:     debug(F101,"conchk","",n);
        !          4889:     return((x < 0) ? 0 : n);
        !          4890: #else
        !          4891:     return(0);                          /* Others can't do. */
        !          4892: #endif
        !          4893: #endif
        !          4894: #endif
        !          4895: #endif
        !          4896: #endif
        !          4897: #endif
        !          4898: }
        !          4899: 
        !          4900: /*  C O N I N C  --  Get a character from the console  */
        !          4901: 
        !          4902: int
        !          4903: coninc(timo) int timo; {
        !          4904:     int n = 0; CHAR ch;
        !          4905: #ifdef aegis
        !          4906:     fflush(stdout);
        !          4907:     if (conchk() > 0) {
        !          4908:        --conbufn;
        !          4909:        return(*conbufp++ & 0377);
        !          4910:     }
        !          4911: #endif /* aegis */
        !          4912: 
        !          4913:     if (timo <= 0 ) {                   /* Untimed. */
        !          4914:         n = read(0, &ch, 1);            /* Read a character. */
        !          4915:         ch &= 0377;
        !          4916:         if (n > 0)                     /* Return the character if read ok */
        !          4917:          return(ch);
        !          4918:         else                           /* otherwise... */
        !          4919: #ifdef SVORPOSIX
        !          4920: #ifndef CIE                             /* CIE Regulus has no such symbol */
        !          4921:          if (n < 0 && errno == EINTR)  /* If read was interrupted by QUIT, */
        !          4922:            return(escchr);             /* user entered escape character. */
        !          4923:          else                          /* Can't be ^c, sigint never returns */
        !          4924: #endif /* CIE */
        !          4925: #endif /* SVORPOSIX */
        !          4926:            {
        !          4927:                debug(F101, "coninc(0) errno","",errno);
        !          4928:                return(-1);             /* Return -1 as error indication */
        !          4929:            }
        !          4930:     }
        !          4931:     saval = signal(SIGALRM,timerh);    /* Timed read, so set up timer */
        !          4932:     alarm(timo);
        !          4933:     if (setjmp(sjbuf)) n = -2;
        !          4934:     else {
        !          4935:         n = read(0, &ch, 1);
        !          4936:         ch &= 0377;
        !          4937:     }
        !          4938:     ttimoff();                         /* Turn off timer */
        !          4939:     if (n > 0) return(ch);
        !          4940:     else
        !          4941: #ifdef SVORPOSIX
        !          4942: #ifndef CIE                             /* CIE Regulus has no such symbol */
        !          4943:         if (n == -1 && errno == EINTR)  /* If read interrupted by QUIT, */
        !          4944:             return(escchr);             /* user entered escape character, */
        !          4945:         else                            /* can't be ^c, sigint never returns */
        !          4946: #endif /* CIE */
        !          4947: #endif /* SVORPOSIX */
        !          4948:         return(-1);
        !          4949: }
        !          4950: 
        !          4951: /*  C O N G K S  --  Console Get Keyboard Scancode  */
        !          4952: 
        !          4953: #ifndef congks
        !          4954: /*
        !          4955:   This function needs to be filled in with the various system-dependent
        !          4956:   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
        !          4957:   keyboard scan code.  For now, it's a dummy.
        !          4958: */
        !          4959: int
        !          4960: congks(timo) int timo; {
        !          4961:     return(coninc(timo));
        !          4962: }
        !          4963: #endif /* congks */
        !          4964: 
        !          4965: #ifdef ATT7300
        !          4966: 
        !          4967: /*  A T T D I A L  --  Dial up the remote system using internal modem
        !          4968:  * Purpose: to open and dial a number on the internal modem available on the
        !          4969:  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
        !          4970:  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
        !          4971:  * Uses information in <sys/phone.h> and our status int attmodem.
        !          4972:  */
        !          4973: attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
        !          4974:     char *telnum;
        !          4975:     int ttclos();
        !          4976: 
        !          4977:     attmodem &= ~ISMODEM;                       /* modem not in use yet */
        !          4978:                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
        !          4979:                     /* We turn this flag off once the dial is complete */
        !          4980:     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
        !          4981: 
        !          4982:     /* Condition line, check availability & DATA mode, turn on speaker */
        !          4983:     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
        !          4984:         printf("cannot access phone\n");
        !          4985:         ttclos(0);
        !          4986:         return (-2);
        !          4987:     }
        !          4988:     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
        !          4989: 
        !          4990:     if (dialer.c_lineparam & VOICE) {  /* phone must be in DATA mode */
        !          4991:         printf(" Should not dial with modem in VOICE mode.\n");
        !          4992:         printf(" Exit Kermit, switch to DATA and retry call.\n");
        !          4993:         ttclos(0);
        !          4994:         return (-2);
        !          4995:     }
        !          4996: #ifdef ATTTONED                                /* Old way, tone dialing only. */
        !          4997:     dialer.c_lineparam = DATA | DTMF;  /* Dial with tones, */
        !          4998:     dialer.c_lineparam &= ~PULSE;      /* not with pulses. */
        !          4999: #else
        !          5000:     /* Leave current pulse/tone state alone. */
        !          5001:     /* But what about DATA?  Add it back if you have trouble. */
        !          5002:     /* sys/phone says you get DATA automatically by opening device RDWR */
        !          5003: #endif
        !          5004:     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
        !          5005: #ifdef COMMENT
        !          5006:     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
        !          5007: #else
        !          5008:     /* sys/phone says RINGON used only for incoming voice calls */
        !          5009:     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
        !          5010:     dialer.c_feedback |= SPEAKERON|NORMSPK;
        !          5011: #endif
        !          5012:     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
        !          5013:     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
        !          5014:         printf("Cannot set modem characteristics\n");
        !          5015:         ttclos(0);
        !          5016:         return (-2);
        !          5017:     }
        !          5018:     ioctl(ttyfd,PIOCRECONN,0);         /* Turns on speaker for pulse */
        !          5019: 
        !          5020: #ifdef COMMENT
        !          5021:     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
        !          5022: line_status:%o feedback:%o\n",
        !          5023:     dialer.c_lineparam, dialer.c_waitdialtone,
        !          5024:     dialer.c_linestatus, dialer.c_feedback);
        !          5025: #endif
        !          5026: 
        !          5027:     attmodem |= ISMODEM;                        /* modem is now in-use */
        !          5028:     sleep(1);
        !          5029:     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
        !          5030: #ifdef ATTTONED
        !          5031:       /* Tone dialing only */
        !          5032:       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
        !          5033:          perror("Error in dialing");
        !          5034:          ttclos(0);
        !          5035:          return(-2);
        !          5036:       }
        !          5037: #else /* Allow Pulse or Tone dialing */
        !          5038:     switch (*telnum) {
        !          5039:       case 't': case 'T': case '%':    /* Tone dialing requested */
        !          5040:        dialer.c_lineparam |= DTMF;
        !          5041:        dialer.c_lineparam &= ~PULSE;
        !          5042:        if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
        !          5043:            printf("Cannot set modem to tone dialing\n");
        !          5044:            ttclos(0);
        !          5045:            return(-2);
        !          5046:        }
        !          5047:        break;
        !          5048:       case 'd': case 'D': case 'p': case 'P': case '^':
        !          5049:        dialer.c_lineparam |= PULSE;
        !          5050:        dialer.c_lineparam &= ~DTMF;
        !          5051:        if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
        !          5052:            printf("Cannot set modem to pulse dialing\n");
        !          5053:            ttclos(0);
        !          5054:            return(-2);
        !          5055:        }
        !          5056:        break;
        !          5057:       default:
        !          5058:         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
        !          5059:            perror("Dialing error");
        !          5060:            ttclos(0);
        !          5061:            return(-2);
        !          5062:        }
        !          5063:        break;
        !          5064:     }
        !          5065: #endif
        !          5066: 
        !          5067:     ioctl(ttyfd,PIOCDIAL,"@");         /* terminator for data call */
        !          5068:     do {                               /* wait for modems to Connect */
        !          5069:         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0)        { /* get params */
        !          5070:            perror("Cannot get modems to connect");
        !          5071:            ttclos(0);
        !          5072:            return(-2);
        !          5073:        }
        !          5074:     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
        !          5075:     /* Turn off O_NDELAY flag now. */
        !          5076:     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
        !          5077:     signal(SIGHUP, ttclos);             /* hangup on loss of carrier */
        !          5078:     return(0);                          /* return success */
        !          5079: }
        !          5080: 
        !          5081: /*
        !          5082:   Offgetty, ongetty functions. These function get the 'getty(1m)' off
        !          5083:   and restore it to the indicated line.  Shell's return codes are:
        !          5084:     0: Can't do it.  Probably a user logged on.
        !          5085:     1: No need.  No getty on that line.
        !          5086:     2: Done, you should restore the getty when you're done.
        !          5087:   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
        !          5088:   Thanks to Kevin O'Gorman, Anarm Software Systems.
        !          5089: 
        !          5090:    getoff.sh looks like:   geton.sh looks like:
        !          5091:      setgetty $1 0           setgetty $1 1
        !          5092:      err=$?                  exit $?
        !          5093:      sleep 2
        !          5094:      exit $err
        !          5095: */
        !          5096: 
        !          5097: /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
        !          5098:  * and get status so it can be restarted after the line is hung up.
        !          5099:  */
        !          5100: int
        !          5101: offgetty(ttname) char *ttname; {
        !          5102:     char temp[30];
        !          5103:     while (*ttname != '\0') ttname++;       /* seek terminator of path */
        !          5104:     ttname -= 3;                            /* get last 3 chars of name */
        !          5105:     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
        !          5106:     return(zsyscmd(temp));
        !          5107: }
        !          5108: 
        !          5109: /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
        !          5110: 
        !          5111: int
        !          5112: ongetty(ttname) char *ttname; {
        !          5113:     char temp[30];
        !          5114:     while (*ttname != '\0') ttname++;       /* comms tty path name */
        !          5115:     ttname -= 3;
        !          5116:     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
        !          5117:     return(zsyscmd(temp));
        !          5118: }
        !          5119: #endif /* ATT7300 */
        !          5120: 
        !          5121: /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
        !          5122:  *
        !          5123:  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
        !          5124:  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
        !          5125:  *  2 = Auto: For "modem direct": The same as "Off".
        !          5126:  *            For real modem types: Heed carrier during connect, but ignore
        !          5127:  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
        !          5128:  *
        !          5129:  * As you can see, this setting does not affect dialing, which always ignores
        !          5130:  * carrier (unless there is some special exception for some modem type).  It
        !          5131:  * does affect ttopen() if it is set before ttopen() is used.  This setting
        !          5132:  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
        !          5133:  * (or should be) always called before any communications is tried, which
        !          5134:  * means that, practically speaking, the effect is immediate.
        !          5135:  *
        !          5136:  * Of course, nothing of this applies to remote mode (xlocal = 0).
        !          5137:  *
        !          5138:  * Someone has yet to uncover how to manipulate the carrier in the BSD
        !          5139:  * environment (or any non-termio using environment).  Until that time, this
        !          5140:  * will simply be a no-op for BSD.
        !          5141:  *
        !          5142:  * Note that in previous versions, the carrier was most often left unchanged
        !          5143:  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
        !          5144:  * has changed.  Now it is controlled by ttcarr in conjunction with these
        !          5145:  * modes.
        !          5146:  */
        !          5147: int
        !          5148: ttscarr(carrier) int carrier; {
        !          5149:     ttcarr = carrier;
        !          5150:     debug(F101, "ttscarr","",ttcarr);
        !          5151:     return(ttcarr);
        !          5152: }
        !          5153: 
        !          5154: /* C A R R C T L  --  Set tty modes for carrier treatment.
        !          5155:  *
        !          5156:  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
        !          5157:  * (actually, there are no bits in sgttyb for that), or performs any other
        !          5158:  * operations needed to control this on the current system.  The function does
        !          5159:  * not do the actual TCSETA or stty, since often we want to set other bits too
        !          5160:  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
        !          5161:  *
        !          5162:  * We don't know how to do anything like carrier control on non-ATTSV systems,
        !          5163:  * except, apparently, ultrix.  See above.  It is also known that this doesn't
        !          5164:  * have much effect on a Xenix system.  For Xenix, one should switch back and
        !          5165:  * forth between the upper and lower case device files.  Maybe later. 
        !          5166:  * Presently, Xenix will stick to the mode it was opened with.
        !          5167:  *
        !          5168:  * carrier: 0 = ignore carrier, 1 = require carrier.
        !          5169:  * The current state is saved in curcarr, and checked to save labour.
        !          5170:  */
        !          5171: #ifdef SVORPOSIX
        !          5172: int
        !          5173: #ifdef ATTSV
        !          5174: carrctl(ttpar, carrier)        struct termio *ttpar; int carrier;
        !          5175: #else /* POSIX */
        !          5176: carrctl(ttpar, carrier)        struct termios *ttpar; int carrier;
        !          5177: #endif /* ATTSV */
        !          5178: /* carrctl */ {
        !          5179:     debug(F101, "carrctl","",carrier);
        !          5180:     if (carrier)
        !          5181:       ttpar->c_cflag &= ~CLOCAL;
        !          5182:     else
        !          5183:       ttpar->c_cflag |= CLOCAL;
        !          5184:     return(0);
        !          5185: }
        !          5186: #else /* Berkeley, V7, et al... */
        !          5187: int
        !          5188: carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
        !          5189: #ifdef ultrix
        !          5190:     int temp = 0;
        !          5191: #endif /* ultrix */
        !          5192:     debug(F101, "carrctl","",carrier);
        !          5193:     if (carrier == curcarr)
        !          5194:       return(0);
        !          5195:     curcarr = carrier;
        !          5196: #ifdef ultrix
        !          5197:     if (carrier) {
        !          5198:        ioctl(ttyfd, TIOCMODEM, &temp);
        !          5199:        ioctl(ttyfd, TIOCHPCL, 0);
        !          5200:     } else {
        !          5201:        /* (According to the manuals, TIOCNCAR should be preferred */
        !          5202:        /* over TIOCNMODEM...) */
        !          5203:        ioctl(ttyfd, TIOCNMODEM, &temp);
        !          5204:     }
        !          5205: #endif /* ultrix */
        !          5206:     return(0);
        !          5207: }
        !          5208: #endif /* SVORPOSIX */
        !          5209: 
        !          5210: 
        !          5211: /*  T T G M D M  --  Get modem signals  */
        !          5212: /*
        !          5213:  Looks for RS-232 modem signals, and returns those that are on in as its
        !          5214:  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
        !          5215:  Returns: 
        !          5216:  -3 Not implemented
        !          5217:  -2 if the communication device does not have modem control (e.g. telnet)
        !          5218:  -1 on error.
        !          5219:  >= 0 on success, with a bit mask containing the modem signals that are on.
        !          5220: */
        !          5221: 
        !          5222: /*
        !          5223:   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
        !          5224:   modem control, namely the TIOCMGET ioctl.
        !          5225: */
        !          5226: 
        !          5227: #ifdef BSD43
        !          5228: #define K_MDMCTL
        !          5229: #endif
        !          5230: 
        !          5231: #ifdef SUNOS4
        !          5232: #define K_MDMCTL
        !          5233: #endif
        !          5234: 
        !          5235: #ifdef TIOCMGET
        !          5236: #define K_MDMCTL
        !          5237: #endif
        !          5238: 
        !          5239: int
        !          5240: ttgmdm() {
        !          5241: 
        !          5242: #ifdef HPUX                            /* HPUX has its own way */
        !          5243: 
        !          5244: /*
        !          5245:   NOTE: I don't have an HPUX man page, and so I'm only guessing at the
        !          5246:   right names for these symbols.  Somebody with HPUX please let me know
        !          5247:   what corrections are needed.
        !          5248: */
        !          5249: 
        !          5250:     int x, y, z;
        !          5251: 
        !          5252:     if (netconn) return(-2);           /* No modem signals for network */
        !          5253:     if (xlocal)                                /* Get modem signals */
        !          5254:       x = ioctl(ttyfd,MCGETA,&y);
        !          5255:     else
        !          5256:       x = ioctl(0,MCGETA,&y);
        !          5257:     if (x < 0) return(-1);
        !          5258:     debug(F101,"ttgmdm","",y);
        !          5259: 
        !          5260:     z = 0;                             /* Initialize return value */
        !          5261: 
        !          5262: /* Now set bits for each modem signal that is reported to be on. */
        !          5263: 
        !          5264: #ifdef MCTS
        !          5265:     /* Clear To Send */
        !          5266:     if (y & MCTS) z |= BM_CTS;
        !          5267: #endif
        !          5268: #ifdef MDSR
        !          5269:     /* Data Set Ready */
        !          5270:     if (y & MDSR) z |= BM_DSR;
        !          5271: #endif
        !          5272: #ifdef MDCD
        !          5273:     /* Carrier */
        !          5274:     if (y & MDCD) z |= BM_DCD;
        !          5275: #endif
        !          5276: #ifdef MRNG
        !          5277:     /* Ring Indicate */
        !          5278:     if (y & MRNG) z |= BM_RNG;
        !          5279: #endif
        !          5280: #ifdef MDTR
        !          5281:     /* Data Terminal Ready */
        !          5282:     if (y & MDTR) z |= BM_DTR;
        !          5283: #endif
        !          5284: #ifdef MRTS
        !          5285:     /* Request To Send */
        !          5286:     if (y & MRTS) z |= BM_RTS;
        !          5287: #endif
        !          5288:     return(z);
        !          5289: 
        !          5290: #else /* ! HPUX */
        !          5291: 
        !          5292: #ifdef K_MDMCTL
        !          5293: /*
        !          5294:   Note, <sys/ttycom> might have already been included by by <sys/ioctl.h>.
        !          5295:   Hence the following ifndef on a symbol which is defined there.
        !          5296: */
        !          5297: #ifndef TIOCMGET
        !          5298: #include <sys/ttycom.h>
        !          5299: #endif /* TIOCMGET */
        !          5300: 
        !          5301:     int x, y, z;
        !          5302: 
        !          5303:     if (netconn) return(-2);           /* Network, no modem signals. */
        !          5304:     if (xlocal)
        !          5305:       x = ioctl(ttyfd,TIOCMGET,&y);    /* Get modem signals. */
        !          5306:     else
        !          5307:       x = ioctl(0,TIOCMGET,&y);
        !          5308:     if (x < 0) return(-1);
        !          5309:     debug(F101,"ttgmdm","",y);
        !          5310: 
        !          5311:     z = 0;                             /* Initialize return value. */
        !          5312: #ifdef TIOCM_CTS
        !          5313:     /* Clear To Send */
        !          5314:     if (y & TIOCM_CTS) z |= BM_CTS;
        !          5315: #endif
        !          5316: #ifdef TIOCM_DSR
        !          5317:     /* Data Set Ready */
        !          5318:     if (y & TIOCM_DSR) z |= BM_DSR;
        !          5319: #endif
        !          5320: #ifdef TIOCM_CAR
        !          5321:     /* Carrier */
        !          5322:     if (y & TIOCM_CAR) z |= BM_DCD;
        !          5323: #endif
        !          5324: #ifdef TIOCM_RNG
        !          5325:     /* Ring Indicate */
        !          5326:     if (y & TIOCM_RNG) z |= BM_RNG;
        !          5327: #endif
        !          5328: #ifdef TIOCM_DTR
        !          5329:     /* Data Terminal Ready */
        !          5330:     if (y & TIOCM_DTR) z |= BM_DTR;
        !          5331: #endif
        !          5332: #ifdef TIOCM_RTS
        !          5333:     /* Request To Send */
        !          5334:     if (y & TIOCM_RTS) z |= BM_RTS;
        !          5335: #endif
        !          5336:     return(z);
        !          5337: #else
        !          5338:     if (netconn) return(-2);
        !          5339:     return(-3);
        !          5340: 
        !          5341: #endif /* K_MDMCTL */
        !          5342: #endif /* HPUX */
        !          5343: }
        !          5344: 
        !          5345: /*  P S U S P E N D  --  Put this process in the background.  */
        !          5346: 
        !          5347: /*
        !          5348:   Call with flag nonzero if suspending is allowed, zero if not allowed.
        !          5349:   Returns 0 on apparent success, -1 on failure (flag was zero, or
        !          5350:   kill() returned an error code.
        !          5351: */
        !          5352: int
        !          5353: psuspend(flag) int flag; {
        !          5354: 
        !          5355: #ifdef RTU
        !          5356:     extern int rtu_bug;
        !          5357: #endif /* RTU */
        !          5358: 
        !          5359:     if (flag == 0) return(-1);
        !          5360: 
        !          5361: #ifdef NOJC
        !          5362:     return(-1);
        !          5363: #else
        !          5364: #ifdef SIGTSTP
        !          5365: /*
        !          5366:   The big question here is whether job control is *really* supported.
        !          5367:   There's no way Kermit can know for sure.  The fact that SIGTSTP is
        !          5368:   defined does not guarantee the Unix kernel supports it, and the fact
        !          5369:   that the Unix kernel supports it doesn't guarantee that the user's
        !          5370:   shell (or other process that invoked Kermit) supports it.
        !          5371: */
        !          5372: #ifdef RTU
        !          5373:     rtu_bug = 1;
        !          5374: #endif /* RTU */
        !          5375:     if (kill(0,SIGSTOP) < 0
        !          5376: #ifdef OXOS
        !          5377: /*
        !          5378:   Because "kill(myself,SIGSTOP)" can't be caught, blocked, or ignored..."
        !          5379: */
        !          5380:        && kill(getpid(),SIGSTOP) < 0
        !          5381: #else
        !          5382: #ifdef MIPS
        !          5383: /* Let's try this for MIPS too. */
        !          5384:        && kill(getpid(),SIGSTOP) < 0
        !          5385: #endif /* MIPS */
        !          5386: #endif /* OXOS */
        !          5387:        ) {                             /* If job control, suspend the job */
        !          5388:        perror("suspend");
        !          5389:        debug(F101,"psuspend error","",errno);
        !          5390:        return(-1);
        !          5391:     }
        !          5392:     debug(F100,"psuspend ok","",0);
        !          5393:     return(0);
        !          5394: #else
        !          5395:     return(-1);
        !          5396: #endif /* SIGTSTP */
        !          5397: #endif /* NOJC */
        !          5398: }
        !          5399: 
        !          5400: /*
        !          5401:   setuid package, by Kristoffer Eriksson, with contributions from Dean
        !          5402:   Long and fdc.
        !          5403: */
        !          5404: 
        !          5405: #ifndef _POSIX_SOURCE
        !          5406: #ifndef SUNOS4
        !          5407: #ifndef NEXT
        !          5408: #ifndef PS2AIX10
        !          5409: extern UID_T getuid(), geteuid(), getreuid();
        !          5410: extern GID_T getgid(), getegid(), getregid();
        !          5411: #endif /* PS2AIX10 */
        !          5412: #endif /* NEXT */
        !          5413: #endif /* SUNOS4 */
        !          5414: #endif /* _POSIX_SOURCE */
        !          5415: 
        !          5416: /*
        !          5417: Subject: Set-user-id
        !          5418: To: [email protected] (Frank da Cruz)
        !          5419: Date: Sat, 21 Apr 90 4:48:25 MES
        !          5420: From: Kristoffer Eriksson <[email protected]>
        !          5421: 
        !          5422: This is a set of functions to be used in programs that may be run set-user-id
        !          5423: and/or set-group-id. They handle both the case where the program is not run
        !          5424: with such privileges (nothing special happens then), and the case where one
        !          5425: or both of these set-id modes are used.  The program is made to run with the
        !          5426: user's real user and group ids most of the time, except for when more
        !          5427: privileges are needed.  Don't set-user-id to "root".
        !          5428: 
        !          5429: This works on System V and POSIX.  In BSD, it depends on the
        !          5430: "saved-set-user-id" feature.
        !          5431: */
        !          5432: 
        !          5433: #define UID_ROOT 0                     /* Root user and group ids */
        !          5434: #define GID_ROOT 0
        !          5435: 
        !          5436: /*
        !          5437:   The following construction automatically defines the symbol SETREUID for
        !          5438:   Unix versions based on Berkeley Unix 4.2 or later.  If this symbol is 
        !          5439:   defined, then this program will use getreuid() and getregid() calls in
        !          5440:   preference to getuid() and getgid(), which in Berkeley-based Unixes do
        !          5441:   not allow arbitrary switching back and forth of real & effective uid.
        !          5442:   This construction also allows -DSETREUID to be put on the cc command line
        !          5443:   for any system that has and wants to use setre[ug]id().  It also prevents
        !          5444:   automatic definition of SETREUID if -DNOSETREU is included on the cc 
        !          5445:   command line (or otherwise defined).
        !          5446: */
        !          5447: #ifdef FT18                            /* None of this for Fortune. */
        !          5448: #define NOSETREU
        !          5449: #endif /* FT18 */
        !          5450: 
        !          5451: #ifdef ANYBSD
        !          5452: #ifndef BSD29
        !          5453: #ifndef BSD41
        !          5454: #ifndef SETREUID
        !          5455: #ifndef NOSETREU
        !          5456: #define SETREUID
        !          5457: #endif /* NOSETREU */                   
        !          5458: #endif /* SETREUID */
        !          5459: #endif /* !BSD41 */
        !          5460: #endif /* !BSD29 */
        !          5461: #endif /* ANYBSD */
        !          5462: 
        !          5463: /* Variables for user and group IDs. */
        !          5464: 
        !          5465: static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
        !          5466: static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
        !          5467: 
        !          5468: 
        !          5469: /* P R I V _ I N I  --  Initialize privileges package  */
        !          5470: 
        !          5471: /* Called as early as possible in a set-uid or set-gid program to store the
        !          5472:  * set-to uid and/or gid and step down to the users real uid and gid. The
        !          5473:  * stored id's can be temporarily restored (allowed in System V) during
        !          5474:  * operations that require the privilege.  Most of the time, the program
        !          5475:  * should execute in unpriviliged state, to not impose any security threat.
        !          5476:  *
        !          5477:  * Note: Don't forget that access() always uses the real id:s to determine
        !          5478:  * file access, even with privileges restored.
        !          5479:  *
        !          5480:  * Returns an error mask, with error values or:ed together:
        !          5481:  *   1 if setuid() fails,
        !          5482:  *   2 if setgid() fails, and
        !          5483:  *   4 if the program is set-user-id to "root", which can't be handled.
        !          5484:  *
        !          5485:  * Only the return value 0 indicates real success. In case of failure,
        !          5486:  * those privileges that could be reduced have been, at least, but the
        !          5487:  * program should be aborted none-the-less.
        !          5488:  *
        !          5489:  * Also note that these functions do not expect the uid or gid to change
        !          5490:  * without their knowing. It may work if it is only done temporarily, but
        !          5491:  * you're on your own.
        !          5492:  */
        !          5493: int
        !          5494: priv_ini() {
        !          5495:     int err = 0;
        !          5496: 
        !          5497:     /* Save real ID:s. */
        !          5498:     realuid = getuid();
        !          5499:     realgid = getgid();
        !          5500: 
        !          5501:     /* Save current effective ID:s, those set to at program exec. */
        !          5502:     privuid = geteuid();
        !          5503:     privgid = getegid();
        !          5504: 
        !          5505:     /* If running set-uid, go down to real uid, otherwise remember that
        !          5506:      * no privileged uid is available.
        !          5507:      *
        !          5508:      * Exceptions:
        !          5509:      *
        !          5510:      * 1) If the real uid is already "root" and the set-uid uid (the
        !          5511:      * initial effective uid) is not "root", then we would have trouble
        !          5512:      * if we went "down" to "root" here, and then temporarily back to the
        !          5513:      * set-uid uid (not "root") and then again tried to become "root". I
        !          5514:      * think the "saved set-uid" is lost when changing uid from effective
        !          5515:      * uid "root", which changes all uid, not only the effective uid. But
        !          5516:      * in this situation, we can simply go to "root" and stay there all
        !          5517:      * the time. That should give sufficient privilege (understatement!),
        !          5518:      * and give the right uids for subprocesses.
        !          5519:      *
        !          5520:      * 2) If the set-uid (the initial effective uid) is "root", and we
        !          5521:      * change uid to the real uid, we can't change it back to "root" when
        !          5522:      * we need the privilege, for the same reason as in 1). Thus, we can't
        !          5523:      * handle programs that are set-user-id to "root" at all. The program
        !          5524:      * should be aborted. Use some other uid. "root" is probably to
        !          5525:      * privileged for such things, anyway. (The uid is reverted to the
        !          5526:      * real uid until abortion.)
        !          5527:      *
        !          5528:      * These two exceptions have the effect that the "root" uid will never
        !          5529:      * be one of the two uids that are being switched between, which also
        !          5530:      * means we don't have to check for such cases in the switching
        !          5531:      * functions.
        !          5532:      *
        !          5533:      * Note that exception 1) is handled by these routines (by constantly
        !          5534:      * running with uid "root", while exception 2) is a serious error, and
        !          5535:      * is not provided for at all in the switching functions.
        !          5536:      */
        !          5537:     if (realuid == privuid)
        !          5538:        privuid = (UID_T) -1;           /* Not running set-user-id. */
        !          5539: 
        !          5540:     /* If running set-gid, go down to real gid, otherwise remember that
        !          5541:      * no privileged gid is available.
        !          5542:      *
        !          5543:      * There are no exception like there is for the user id, since there
        !          5544:      * is no group id that is privileged in the manner of uid "root".
        !          5545:      * There could be equivalent problems for group changing if the
        !          5546:      * program sometimes ran with uid "root" and sometimes not, but
        !          5547:      * that is already avoided as explained above.
        !          5548:      *
        !          5549:      * Thus we can expect always to be able to switch to the "saved set-
        !          5550:      * gid" when we want, and back to the real gid again. You may also
        !          5551:      * draw the conclusion that set-gid provides for fewer hassles than
        !          5552:      * set-uid.
        !          5553:      */
        !          5554: 
        !          5555:     if (realgid == privgid)            /* If not running set-user-id, */
        !          5556:       privgid = (GID_T) -1;            /*  remember it this way. */
        !          5557: 
        !          5558:     err = priv_off();                  /* Turn off setuid privilege. */
        !          5559: 
        !          5560:     if (privuid == UID_ROOT)           /* If setuid to root, */
        !          5561:       err |= 4;                                /* return this error. */
        !          5562: 
        !          5563:     if (realuid == UID_ROOT)           /* If real id is root, */
        !          5564:       privuid = (UID_T) -1;            /* stay root at all times. */
        !          5565: 
        !          5566:     return(err);
        !          5567: }
        !          5568: 
        !          5569: 
        !          5570: /* Macros for hiding the differences in UID/GID setting between various Unix
        !          5571:  * systems. These macros should always be called with both the privileged ID
        !          5572:  * and the non-privileged ID. The one in the second argument, will become the
        !          5573:  * effective ID. The one in the first argument will be retained for later
        !          5574:  * retrieval.
        !          5575:  */
        !          5576: #ifdef SETREUID
        !          5577: #ifdef SAVEDUID
        !          5578: /* On BSD systems with the saved-UID feature, we just juggle the effective
        !          5579:  * UID back and forth, and leave the real UID at its true value.  The kernel
        !          5580:  * allows switching to both the current real UID, the effective UID, and the
        !          5581:  * UID which the program is set-UID to.  The saved set-UID always holds the
        !          5582:  * privileged UID for us, and the real UID will always be the non-privileged,
        !          5583:  * and we can freely choose one of them for the effective UID at any time.
        !          5584:  */
        !          5585: #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
        !          5586: #define switchgid(hidden,active) setregid( (GID_T) -1, active)
        !          5587: 
        !          5588: #else   /* SETREUID,!SAVEDUID */
        !          5589: 
        !          5590: /* On systems with setreXid() but without the saved-UID feature, notably
        !          5591:  * BSD 4.2, we swap the real and effective UIDs each time.  It's
        !          5592:  * the effective UID that we are interrested in, but we have to retain the
        !          5593:  * unused UID somewhere to enable us to restore it later, and that we do this
        !          5594:  * in the real UID.  The kernel only allows switching to either the current 
        !          5595:  * real or the effective UID, unless you're "root".
        !          5596:  */
        !          5597: #define switchuid(hidden,active)       setreuid(hidden,active)
        !          5598: #define switchgid(hidden,active)       setregid(hidden,active)
        !          5599: #endif
        !          5600: 
        !          5601: #else /* !SETREUID, !SAVEDUID */
        !          5602: 
        !          5603: /* On System V and POSIX, the only thing we can change is the effective UID
        !          5604:  * (unless the current effective UID is "root", but initsuid() avoids that for
        !          5605:  * us).  The kernel allows switching to the current real UID or to the saved
        !          5606:  * set-UID.  These are always set to the non-privileged UID and the privileged
        !          5607:  * UID, respectively, and we only change the effective UID.  This breaks if
        !          5608:  * the current effective UID is "root", though, because for "root" setuid/gid
        !          5609:  * becomes more powerful, which is why initsuid() treats "root" specially.
        !          5610:  * Note: That special treatment maybe could be ignored for BSD?  Note: For
        !          5611:  * systems that don't fit any of these three cases, we simply can't support
        !          5612:  * set-UID.
        !          5613:  */
        !          5614: #define switchuid(hidden,active)       setuid(active)
        !          5615: #define switchgid(hidden,active)       setgid(active)
        !          5616: #endif /* SETREUID */
        !          5617:   
        !          5618: 
        !          5619: /* P R I V _ O N  --  Turn on the setuid and/or setgid */
        !          5620: 
        !          5621: /* Go to the privileged uid (gid) that the program is set-user-id
        !          5622:  * (set-group-id) to, unless the program is running unprivileged.
        !          5623:  * If setuid() fails, return value will be 1. If getuid() fails it
        !          5624:  * will be 2.  Return immediately after first failure, and the function
        !          5625:  * tries to restore any partial work done.  Returns 0 on success.
        !          5626:  * Group id is changed first, since it is less serious than user id.
        !          5627:  */
        !          5628: int
        !          5629: priv_on() {
        !          5630:     if (privgid != (GID_T) -1)
        !          5631:       if (switchgid(realgid,privgid))
        !          5632:         return(2);
        !          5633: 
        !          5634:     if (privuid != (UID_T) -1)
        !          5635:       if (switchuid(realuid,privuid)) {
        !          5636:          if (privgid != (GID_T) -1)
        !          5637:            switchgid(privgid,realgid);
        !          5638:          return(1);
        !          5639:       }
        !          5640:     return(0);
        !          5641: }
        !          5642: 
        !          5643: /* P R I V _ O F F  --  Turn on the real uid and gid */
        !          5644: 
        !          5645: /* Return to the unprivileged uid (gid) after an temporary visit to
        !          5646:  * privileged status, unless the program is running without set-user-id
        !          5647:  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
        !          5648:  * in setgid() or:ed together. The functions tries to return both uid
        !          5649:  * and gid to unprivileged state, regardless of errors. Returns 0 on
        !          5650:  * success.
        !          5651:  */
        !          5652: int
        !          5653: priv_off() {
        !          5654:     int err = 0;
        !          5655: 
        !          5656:     if (privuid != (UID_T) -1)
        !          5657:        if (switchuid(privuid,realuid))
        !          5658:          err |= 1;
        !          5659: 
        !          5660:     if (privgid != (GID_T) -1)
        !          5661:        if (switchgid(privgid,realgid))
        !          5662:        err |= 2;
        !          5663: 
        !          5664:     return(err);
        !          5665: }
        !          5666: 
        !          5667: /* Turn off privilege permanently.  No going back.  This is necessary before
        !          5668:  * a fork() on BSD43 machines that don't save the setUID or setGID, because
        !          5669:  * we swap the real and effective ids, and we don't want to let the forked
        !          5670:  * process swap them again and get the privilege back. It will work on other
        !          5671:  * machines too, such that you can rely on its effect always being the same,
        !          5672:  * for instance, even when you're in priv_on() state when this is called.
        !          5673:  * (Well, that part about "permanent" is on System V only true if you follow
        !          5674:  * this with a call to exec(), but that's what we want it for anyway.)
        !          5675:  * Added by Dean Long -- [email protected]
        !          5676:  */
        !          5677: int
        !          5678: priv_can() {
        !          5679: 
        !          5680: #ifdef SETREUID
        !          5681:     int err = 0;
        !          5682:     if (privuid != (UID_T) -1)
        !          5683:        if (setreuid(realuid,realuid))
        !          5684:          err |= 1;
        !          5685: 
        !          5686:     if (privgid != (GID_T) -1)
        !          5687:         if (setregid(realgid,realgid))
        !          5688:          err |= 2;
        !          5689: 
        !          5690:     return(err);
        !          5691: 
        !          5692: #else
        !          5693:     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
        !          5694:     return(priv_off());
        !          5695: 
        !          5696: #endif /* SETREUID */
        !          5697: }
        !          5698: 
        !          5699: /* P R I V _ O P N  --  For opening protected files or devices. */
        !          5700: 
        !          5701: int
        !          5702: priv_opn(name, modes) char *name; int modes; {
        !          5703:     int x;
        !          5704:     priv_on();                         /* Turn privileges on */
        !          5705:     x = open(name, modes);             /* Try to open the device */
        !          5706:     priv_off();                                /* Turn privileges off */
        !          5707:     return(x);                         /* Return open's return code */
        !          5708: }
        !          5709: 
        !          5710: /*  P R I V _ C H K  --  Check privileges.  */
        !          5711: 
        !          5712: /*  Try to turn them off.  If turning them off did not succeed, cancel them */
        !          5713: 
        !          5714: int
        !          5715: priv_chk() {
        !          5716:     int x, y = 0;
        !          5717:     x = priv_off();                    /* Turn off privs. */
        !          5718:     if (x != 0 || getuid() == privuid || geteuid() == privuid)
        !          5719:       y = priv_can();
        !          5720:     if (x != 0 || getgid() == privgid || getegid() == privgid)
        !          5721:       y = y | priv_can();
        !          5722:     return(y);
        !          5723: }
        !          5724: 
        !          5725: UID_T
        !          5726: real_uid() {
        !          5727:     return(realuid);
        !          5728: }
        !          5729: 
        !          5730: VOID
        !          5731: ttimoff() {                           /* Turn off any timer interrupts */
        !          5732:     alarm(0);
        !          5733:     if (saval)
        !          5734:       signal(SIGALRM,saval);
        !          5735:     else
        !          5736:       signal(SIGALRM,SIG_DFL);
        !          5737:     saval = NULL;
        !          5738: }
        !          5739: 
        !          5740: #ifdef UTEK
        !          5741: /* Turn on or off hardware flow control under UTek */
        !          5742: VOID
        !          5743: hardflow(flow) int flow; {
        !          5744:     int x;
        !          5745:     x = LDODTR | LDOCTS;
        !          5746:     if (flow == FLO_HARD) {            /* Use hardware flow control */
        !          5747:        if (lmodef) {
        !          5748:            x = ioctl(ttyfd,TIOCLBIS,&x);
        !          5749:            if (x < 0) {
        !          5750:                debug(F100,"hardflow TIOCLBIS error","",0);
        !          5751:            } else {
        !          5752:                lmodef++;
        !          5753:                debug(F100,"hardflow TIOCLBIS ok","",0);
        !          5754:            }
        !          5755:        }
        !          5756:     } else {
        !          5757:        if (lmodef) {
        !          5758:            x = ioctl(ttyfd,TIOCLBIC,&x);
        !          5759:            if (x < 0) {
        !          5760:                debug(F100,"hardflow TIOCLBIC error","",0);
        !          5761:            } else {
        !          5762:                lmodef++;
        !          5763:                debug(F100,"hardflow TIOCLBIC ok","",0);
        !          5764:            }
        !          5765:        }
        !          5766:     }
        !          5767: }
        !          5768: #endif /* UTEK */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.