home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / minix1 / mxutio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  48KB  |  1,782 lines

  1. char *ckxv = "Unix tty I/O, 4C(040), 30 Sep 86";
  2.  
  3. /*  C K U T I O  */
  4.  
  5. /* C-Kermit interrupt, terminal control & i/o functions for Unix systems */
  6.  
  7. /*
  8.  Author: Frank da Cruz (SY.FDC@CU20B),
  9.  Columbia University Center for Computing Activities, January 1985.
  10.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  11.  Permission is granted to any individual or institution to use, copy, or
  12.  redistribute this software so long as it is not sold for profit, provided this
  13.  copyright notice is retained. 
  14. */
  15. /* Includes for all Unixes (conditional includes come later) */
  16.  
  17. #include <sys/types.h>            /* Types */
  18.  
  19. #include <sys/dir.h>            /* Directory */
  20. #include <ctype.h>            /* Character types */
  21. #ifdef NULL
  22. #undef NULL
  23. #endif NULL
  24. #include <stdio.h>            /* Unix Standard i/o */
  25. #include <signal.h>            /* Interrupts */
  26. #include <setjmp.h>            /* Longjumps */
  27. #include "ckcdeb.h"            /* Typedefs, formats for debug() */
  28.  
  29. /* Maximum length for the name of a tty device */
  30.  
  31. #ifndef DEVNAMLEN
  32. #define DEVNAMLEN 25
  33. #endif
  34.  
  35. /* 4.1 BSD support added by Charles E. Brooks, EDN-VAX */
  36. /* Fortune 16:32 For:Pro 1.7 support mostly like 4.1, added by J-P Dumas */
  37.  
  38. #ifdef BSD4
  39. #define ANYBSD
  40. #ifdef MAXNAMLEN
  41. #define BSD42
  42. char *ckxsys = " 4.2 BSD";
  43. #else
  44. #ifdef FT17
  45. #define BSD41
  46. char *ckxsys = " For:Pro Fortune 1.7";
  47. #else
  48. #define BSD41
  49. #ifndef C70
  50. char *ckxsys = " 4.1 BSD";
  51. #endif
  52. #endif
  53. #endif
  54. #endif
  55.  
  56. /* 2.9bsd support contributed by Bradley Smith, UCLA */
  57. #ifdef BSD29
  58. #define ANYBSD
  59. char *ckxsys = " 2.9 BSD";
  60. #endif
  61.  
  62. /*
  63.  Version 7 UNIX support contributed by Gregg Wonderly,
  64.  Oklahoma State University:  gregg@okstate.csnet
  65. */
  66. #ifdef    V7
  67. #ifndef MINIX
  68. char *ckxsys = " Version 7 UNIX (tm)";
  69. #else
  70. /* MINIX support by Adrian Godwin, Bedford, England */
  71. char *ckxsys = " MINIX version 1.1";
  72. #endif
  73. #endif
  74.  
  75. /* BBN C70 support from Frank Wancho, WANCHO@SIMTEL20 */
  76. #ifdef C70
  77. char *ckxsys = " BBN C/70";
  78. #endif
  79.  
  80. /* Amdahl UTS 2.4 (v7 derivative) for IBM 370 series compatible mainframes */
  81. /* Contributed by Garard Gaye, Jean-Pierre Dumas, DUMAS@SUMEX-AIM. */
  82. #ifdef UTS24
  83. char *ckxsys = " Amdahl UTS 2.4";
  84. #endif
  85.  
  86. /* Pro/Venix Version 1.x support from Columbia U. */
  87. #ifdef PROVX1
  88. char *ckxsys = " Pro-3xx Venix v1";
  89. #endif
  90.  
  91. /* Tower support contributed by John Bray, Auburn, Alabama */
  92. #ifdef TOWER1
  93. char *ckxsys = " NCR Tower 1632, OS 1.02";
  94. #endif
  95.  
  96. /* The following applies to Apollo Domain/ix, not Aegis... */
  97. #ifdef apollo
  98. #undef TIOCEXCL
  99. #endif apollo
  100.  
  101. /* Sys III/V, Xenix, PC/IX support by Herm Fischer, Encino, CA */
  102. #ifdef UXIII
  103. #ifdef XENIX
  104. char *ckxsys = " Xenix/286";
  105. #else
  106. #ifdef PCIX
  107. char *ckxsys = " PC/IX";
  108. #else
  109. #ifdef ISIII
  110. char *ckxsys = " Interactive Systems Corp System III";
  111. #else
  112. char *ckxsys = " AT&T System III/System V";
  113. #endif
  114. #endif
  115. #endif
  116. #endif
  117.  
  118. /* Features... */
  119.  
  120. /* Do own buffering, using unbuffered read() calls... */
  121. #ifdef UXIII
  122. #define MYREAD
  123. #endif
  124.  
  125. #ifdef BSD42
  126. #define MYREAD
  127. #include <errno.h>
  128. #endif
  129.  
  130. #ifdef MINIX
  131. #define MYREAD
  132. #endif
  133.  
  134. /*
  135.  Note - KERLD is the Berkeley Unix Berknet line driver, modified to pass
  136.  through all 8  bits, and to allow an arbitrary break character to be set.
  137.  Don't define this symbol unless you have made this modification to your
  138.  4.2BSD kernel!
  139. */
  140. #ifdef BSD4
  141. /* #define KERLD */  /* <-- note, commented out */
  142. #endif
  143.  
  144. /*
  145.  Variables available to outside world:
  146.  
  147.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  148.    dfloc  -- 0 if dftty is console, 1 if external line.
  149.    dfprty -- Default parity
  150.    dfflow -- Default flow control
  151.    ckxech -- Flag for who echoes console typein:
  152.      1 - The program (system echo is turned off)
  153.      0 - The system (or front end, or terminal).
  154.    functions that want to do their own echoing should check this flag
  155.    before doing so.
  156.  
  157.    flfnam -- Name of lock file, including its path, e.g.,
  158.         "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
  159.    hasLock -- Flag set if this kermit established a uucp lock.
  160.    inbufc -- number of tty line rawmode unread characters 
  161.         (system III/V unixes)
  162.    backgrd -- Flag indicating program executing in background ( & on 
  163.         end of shell command). Used to ignore INT and QUIT signals.
  164.  
  165.  Functions for assigned communication line (either external or console tty):
  166.  
  167.    sysinit()               -- System dependent program initialization
  168.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  169.    ttclos()                -- Close & reset the tty, releasing any access lock.
  170.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  171.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  172.                 or in DIALING or CONNECTED modem control state.
  173.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  174.    ttinc(timo)             -- Timed read character from tty.
  175.    myread()           -- System 3 raw mode bulk buffer read, gives
  176.                --   subsequent chars one at a time and simulates
  177.                --   FIONREAD!
  178.    myunrd(c)           -- Places c back in buffer to be read (one only)
  179.    ttchk()                 -- See how many characters in tty input buffer.
  180.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  181.    ttol(string,length)     -- Write a string to the tty.
  182.    ttoc(c)                 -- Write a character to the tty.
  183.    ttflui()                -- Flush tty input buffer.
  184.  
  185.    ttlock(ttname)       -- Lock against uucp collisions (Sys III)
  186.    ttunlck()           -- Unlock "       "     "
  187.    look4lk(ttname)       -- Check if a lock file exists
  188. */
  189.  
  190. /*
  191. Functions for console terminal:
  192.  
  193.    congm()   -- Get console terminal modes.
  194.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  195.    conbin(esc) -- Put the console in binary (raw) mode.
  196.    conres()  -- Restore the console to mode obtained by congm().
  197.    conoc(c)  -- Unbuffered output, one character to console.
  198.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  199.    conola(s) -- Unbuffered output, array of strings to the console.
  200.    conxo(n,s) -- Unbuffered output, n characters to the console.
  201.    conchk()  -- Check if characters available at console (bsd 4.2).
  202.         Check if escape char (^\) typed at console (System III/V).
  203.    coninc(timo)  -- Timed get a character from the console.
  204.    conint()  -- Enable terminal interrupts on the console if not background.
  205.    connoi()  -- Disable terminal interrupts on the console if not background.
  206.  
  207. Time functions
  208.  
  209.    msleep(m) -- Millisecond sleep
  210.    ztime(&s) -- Return pointer to date/time string
  211.    rtimer() --  Reset timer
  212.    gtimer()  -- Get elapsed time since last call to rtimer()
  213. */
  214.  
  215. /* Conditional Includes */
  216.  
  217. #ifdef FT17
  218. #include <sys/file.h>              /* File information */
  219. #endif
  220.  
  221. #ifndef MINIX
  222. #ifndef PROVX1
  223. #include <sys/file.h>              /* File information */
  224. #endif
  225. #endif
  226.  
  227. /* where does a V7 version get the tm structure from ? */
  228.  
  229. #ifdef MINIX
  230. #include <time.h>
  231. #endif
  232.  
  233. /* System III, System V */
  234.  
  235. #ifdef UXIII
  236. #include <termio.h>
  237. #include <sys/ioctl.h>
  238. #include <fcntl.h>            /* directory reading for locking */
  239. #include <errno.h>            /* error numbers for system returns */
  240. #endif
  241.  
  242. /* Not Sys III/V */
  243.  
  244. #ifndef UXIII
  245. #include <sgtty.h>            /* Set/Get tty modes */
  246. #ifndef PROVX1
  247. #ifndef V7
  248. #ifndef BSD41
  249. #include <sys/time.h>            /* Clock info (for break generation) */
  250. #endif
  251. #endif
  252. #endif
  253. #endif
  254.  
  255. #ifdef BSD41
  256. #include <sys/timeb.h>            /* BSD 4.1 ... ceb */
  257. #endif
  258.  
  259. #ifdef BSD29
  260. #include <sys/timeb.h>            /* BSD 2.9 (Vic Abell, Purdue) */
  261. #endif
  262.  
  263. #ifdef TOWER1
  264. #include <sys/timeb.h>            /* Clock info for NCR Tower */
  265. #endif
  266.  
  267. /* Declarations */
  268.  
  269. long time();                /* All Unixes should have this... */
  270. extern int errno;            /* System call error return */
  271.  
  272. /* Special stuff for V7 input buffer peeking */
  273.  
  274. #ifdef    V7
  275. int kmem[2] = { -1, -1};
  276. char *initrawq(), *qaddr[2]={0,0};
  277. #define CON 0
  278. #define TTY 1
  279. #endif
  280.  
  281. /* dftty is the device name of the default device for file transfer */
  282. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  283.  
  284. #ifdef PROVX1
  285.     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
  286.     int dfloc = 1;            /* that goes in local mode by default */
  287. #else
  288.     char *dftty = CTTNAM;        /* Remote by default, use normal */
  289.     int dfloc = 0;            /* controlling terminal name. */
  290. #endif
  291.  
  292.     int dfprty = 0;            /* Parity (0 = none) */
  293.     int dfflow = 1;            /* Xon/Xoff flow control */
  294.     int backgrd = 0;            /* Assume in foreground (no '&' ) */
  295.  
  296. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  297.  
  298. /* Declarations of variables global within this module */
  299.  
  300. static long tcount;            /* Elapsed time counter */
  301.  
  302. static char *brnuls = "\0\0\0\0\0\0\0"; /* A string of nulls */
  303.  
  304. static jmp_buf sjbuf, jjbuf;        /* Longjump buffer */
  305. static int lkf = 0,            /* Line lock flag */
  306.     conif = 0,                /* Console interrupts on/off flag */
  307.     cgmf = 0,                /* Flag that console modes saved */
  308.     xlocal = 0,                /* Flag for tty local or remote */
  309.     ttyfd = -1;                /* TTY file descriptor */
  310. static char escchr;            /* Escape or attn character */
  311.  
  312. /* Special line discipline, 4.2bsd only, and only with kernel mods... */
  313. #ifdef KERLD
  314.     static int kerld = 1;        /* Special Kermit line discipline... */
  315.     struct tchars oldc, newc;        /* Special characters */
  316.     int ld = NETLDISC;            /* Really a hack to "Berknet" l.d. */
  317.     int oldld;                /* Old discipline */
  318. #else
  319.     static int kerld = 0;        /* Not selected, no special l.d. */
  320. #endif
  321.  
  322. #ifdef BSD42
  323.     static struct timeval tv;        /* For getting time, from sys/time.h */
  324.     static struct timezone tz;
  325. #endif
  326.  
  327. #ifdef BSD29
  328.     static long clock;            /* For getting time from sys/time.h */
  329.     static struct timeb ftp;        /* And from sys/timeb.h */
  330. #endif
  331.  
  332. #ifdef BSD41
  333.     static long clock;            /* For getting time from sys/time.h */
  334.     static struct timeb ftp;        /* And from sys/timeb.h */
  335. #endif
  336.  
  337. #ifdef TOWER1
  338. static long clock;            /* For getting time from sys/time.h */
  339. static struct timeb ftp;        /* And from sys/timeb.h */
  340. #endif
  341.  
  342. #ifdef V7
  343. static long clock;
  344. #endif
  345.  
  346. #ifdef UXIII
  347.   static struct termio             /* sgtty info... */
  348.     ttold, ttraw, tttvt,        /* for communication line */
  349.     ccold, ccraw, cccbrk;        /* and for console */
  350. #else
  351.   static struct sgttyb             /* sgtty info... */
  352.     ttold, ttraw, tttvt, ttbuf,        /* for communication line */
  353.     ccold, ccraw, cccbrk;        /* and for console */
  354. #endif
  355.  
  356. static char flfnam[80];            /* uucp lock file path name */
  357. static int hasLock = 0;            /* =1 if this kermit locked uucp */
  358. static int inbufc = 0;            /* stuff for efficient SIII raw line */
  359. static int ungotn = -1;            /* pushback to unread character */
  360. static int conesc = 0;            /* set to 1 if esc char (^\) typed */
  361.  
  362. static int ttlock();            /* definition of ttlock subprocedure */
  363. static int ttunlck();            /* and unlock subprocedure */
  364. static char ttnmsv[DEVNAMLEN];        /* copy of open path for tthang */
  365.  
  366. /*  S Y S I N I T  --  System-dependent program initialization.  */
  367.  
  368. sysinit() {
  369.  
  370. /* for now, nothing... */
  371.     return(0);
  372. }
  373.  
  374. /*  T T O P E N  --  Open a tty for exclusive access.  */
  375.  
  376. /*  Returns 0 on success, -1 on failure.  */
  377. /*
  378.   If called with lcl < 0, sets value of lcl as follows:
  379.   0: the terminal named by ttname is the job's controlling terminal.
  380.   1: the terminal named by ttname is not the job's controlling terminal.
  381.   But watch out: if a line is already open, or if requested line can't
  382.   be opened, then lcl remains (and is returned as) -1.
  383. */
  384. ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  385.  
  386. #ifdef UXIII
  387.     char *ctermid();            /* Wish they all had this! */
  388. #endif
  389.     char *x; extern char* ttyname();
  390.     char cname[DEVNAMLEN+4];
  391.  
  392.     if (ttyfd > -1) return(0);        /* If already open, ignore this call */
  393.     xlocal = *lcl;            /* Make this available to other fns */
  394. #ifdef NEWUUCP
  395.     acucntrl("disable",ttname);        /* Open getty on line (4.3BSD) */
  396. #endif
  397. #ifdef UXIII
  398.     /* if modem connection, don't wait for carrier */
  399.     ttyfd = open(ttname,O_RDWR | (modem ? O_NDELAY : 0) );
  400. #else
  401.     ttyfd = open(ttname,2);        /* Try to open for read/write */
  402. #endif
  403.  
  404.     if (ttyfd < 0) {            /* If couldn't open, fail. */
  405.     perror(ttname);
  406.     return(-1);
  407.     }
  408.     strncpy(ttnmsv,ttname,DEVNAMLEN);    /* Open, keep copy of name locally. */
  409.  
  410. /* Caller wants us to figure out if line is controlling tty */
  411.  
  412.     debug(F111,"ttopen ok",ttname,*lcl);
  413.     if (*lcl == -1) {
  414.     if (strcmp(ttname,CTTNAM) == 0) {   /* "/dev/tty" always remote */
  415.         debug(F110," Same as CTTNAM",ttname,0);
  416.         xlocal = 0;
  417.     } else if (isatty(0)) {        /* Else, if stdin not redirected */
  418.         x = ttyname(0);        /* then compare its device name */
  419.         strncpy(cname,x,DEVNAMLEN);    /* (copy from internal static buf) */
  420.         debug(F110," ttyname(0)",x,0);
  421.         x = ttyname(ttyfd);     /* ...with real name of ttname. */
  422.         xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
  423.         debug(F111," ttyname",x,xlocal);
  424.     } else {            /* Else, if stdin redirected... */
  425. #ifdef UXIII
  426. /* Sys III/V provides nice ctermid() function to get name of controlling tty */
  427.             ctermid(cname);        /* Get name of controlling terminal */
  428.         debug(F110," ctermid",cname,0);
  429.         x = ttyname(ttyfd);     /* Compare with name of comm line. */
  430.         xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
  431.         debug(F111," ttyname",x,xlocal);
  432. #else
  433. /* Just assume local, so "set speed" and similar commands will work */
  434. /* If not really local, how could it work anyway?... */
  435.         xlocal = 1;
  436.         debug(F101," redirected stdin","",xlocal);
  437. #endif
  438.         }
  439.     }    
  440.  
  441. /* Now check if line is locked -- if so fail, else lock for ourselves */
  442.  
  443.     lkf = 0;                /* Check lock */
  444.     if (xlocal > 0) {
  445.     if (ttlock(ttname) < 0) {
  446.         fprintf(stderr,"Exclusive access to %s denied\n",ttname);
  447.         close(ttyfd); ttyfd = -1;
  448.         debug(F110," Access denied by lock",ttname,0);
  449.         return(-1);            /* Not if already locked */
  450.         } else lkf = 1;
  451.     }
  452.  
  453. /* Got the line, now set the desired value for local. */
  454.  
  455.     if (*lcl < 0) *lcl = xlocal;
  456.  
  457. /* Some special stuff for v7... */
  458.  
  459. #ifdef    V7
  460. #ifndef MINIX
  461.     if (kmem[TTY] < 0) {    /*  If open, then skip this.  */
  462.         qaddr[TTY] = initrawq(ttyfd);    /* Init the queue. */
  463.         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
  464.             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
  465.             perror("/dev/kmem");
  466.             exit(1);
  467.         }
  468.     }
  469. #endif
  470. #endif    V7
  471.  
  472. /* Request exclusive access on systems that allow it. */
  473.  
  474. #ifndef XENIX
  475. /* Xenix exclusive access prevents open(close(...)) from working... */
  476. #ifdef TIOCEXCL
  477.         if (ioctl(ttyfd,TIOCEXCL, NULL) < 0)
  478.         fprintf(stderr,"Warning, problem getting exclusive access\n");
  479. #endif
  480. #endif
  481.  
  482. /* Get tty device settings */
  483.  
  484. #ifndef UXIII
  485.     gtty(ttyfd,&ttold);            /* Get sgtty info */
  486.     gtty(ttyfd,&ttraw);            /* And a copy of it for packets*/
  487.     gtty(ttyfd,&tttvt);            /* And one for virtual tty service */
  488. #else
  489.     ioctl(ttyfd,TCGETA,&ttold);        /* Same deal for Sys III, Sys V */
  490.     ioctl(ttyfd,TCGETA,&ttraw);
  491.     ioctl(ttyfd,TCGETA,&tttvt);
  492. #endif
  493.     debug(F101,"ttopen, ttyfd","",ttyfd);
  494.     debug(F101," lcl","",*lcl);
  495.     debug(F111," lock file",flfnam,lkf);
  496.     return(0);
  497. }
  498.  
  499. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  500.  
  501. ttclos() {
  502.     if (ttyfd < 0) return(0);        /* Wasn't open. */
  503.     if (xlocal) {
  504.     if (tthang())            /* Hang up phone line */
  505.         fprintf(stderr,"Warning, problem hanging up the phone\n");
  506.         if (ttunlck())            /* Release uucp-style lock */
  507.         fprintf(stderr,"Warning, problem releasing lock\n");
  508.     }
  509.     ttres();                /* Reset modes. */
  510. /* Relinquish exclusive access if we might have had it... */
  511. #ifndef XENIX
  512. #ifdef TIOCEXCL
  513. #ifdef TIOCNXCL
  514.     if (ioctl(ttyfd, TIOCNXCL, NULL) < 0)
  515.         fprintf(stderr,"Warning, problem relinquishing exclusive access\n");
  516. #endif
  517. #endif
  518. #endif
  519.     close(ttyfd);            /* Close it. */
  520. #ifdef NEWUUCP
  521.     acucntrl("enable",flfnam);        /* Close getty on line. */
  522. #endif
  523.     ttyfd = -1;                /* Mark it as closed. */
  524.     return(0);
  525. }
  526.  
  527. /*  T T H A N G -- Hangup phone line */
  528.  
  529. tthang() {
  530. #ifdef UXIII
  531.     unsigned short ttc_save;
  532. #endif
  533.  
  534.     if (ttyfd < 0) return(0);        /* Not open. */
  535. #ifdef ANYBSD
  536.     ioctl(ttyfd,TIOCCDTR,0);        /* Clear DTR */
  537.     msleep(500);            /* Let things settle */
  538.     ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
  539. #endif
  540. #ifdef UXIII
  541.     ttc_save = ttraw.c_cflag;
  542.     ttraw.c_cflag &= ~CBAUD;        /* swa: set baud rate to 0 to hangup */
  543.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* do it */
  544.     msleep(100);            /* let things settle */
  545.     ttraw.c_cflag = ttc_save;
  546. #ifndef XENIX        /* xenix cannot do close/open when carrier drops */
  547.                 /* following corrects a PC/IX defficiency */
  548.     ttc_save = fcntl(ttyfd,F_GETFL,0);
  549.     close(ttyfd);        /* close/reopen file descriptor */
  550.     if ((ttyfd = open(ttnmsv, ttc_save)) < 0) return(-1);
  551. #endif
  552.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* un-do it */
  553. #endif
  554.     return (0);
  555. }
  556.  
  557.  
  558. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  559.  
  560. ttres() {                /* Restore the tty to normal. */
  561.     if (ttyfd < 0) return(-1);        /* Not open. */
  562. #ifndef UXIII                /* except for sIII, */
  563.     sleep(1);                /* Wait for pending i/o to finish. */
  564. #endif                    /*   (sIII does wait in ioctls) */
  565. #ifdef KERLD
  566.     if (kerld) ioctl(ttyfd,TIOCSETD,&oldld); /* Restore old line discipline. */
  567. #endif
  568. #ifdef UXIII
  569.     if (ioctl(ttyfd,TCSETAW,&ttold) < 0) return(-1); /* restore termio stuff */
  570. #else
  571.     if (stty(ttyfd,&ttold) < 0) return(-1); /* Restore sgtty stuff */
  572. #endif
  573. #ifdef KERLD
  574.     if (kerld) ioctl(ttyfd,TIOCSETC,&oldc); /* Restore old special chars. */
  575. #endif
  576.  
  577.     return(0);
  578. }
  579.  
  580. #ifdef MINIX
  581. #ifndef NOLOCKS
  582. #define NOLOCKS
  583. #endif
  584. #endif
  585.  
  586. #ifdef NOLOCKS      
  587.  
  588. /* why bother with all the locking code on little systems that don't care? */
  589.  
  590. ttlock() { return 0; }
  591. ttunlck() { return 0; }
  592.  
  593. #else
  594.  
  595. /* Exclusive uucp file locking control */
  596. /*
  597.  by H. Fischer, creative non-Bell coding !
  598.  copyright rights for lock modules assigned to Columbia University
  599. */
  600. static char *
  601. xxlast(s,c) char *s; char c; {        /* Equivalent to strrchr() */
  602.     int i;
  603.     for (i = strlen(s); i > 0; i--)
  604.         if ( s[i-1] == c ) return( s + (i - 1) );
  605.     return(NULL);        
  606. }
  607. static
  608. look4lk(ttname) char *ttname; {
  609.     extern char *strcat(), *strcpy();
  610.     char *device, *devname;
  611.     char lockfil[50];            /* Max length for lock file name */
  612.  
  613. #ifdef ISIII
  614.     char *lockdir = "/etc/locks";
  615. #else
  616. #ifdef ATT3BX
  617.     char *lockdir = "/usr/spool/locks";
  618. #else
  619. #ifdef NEWUUCP
  620.     char *lockdir = "/usr/spool/uucp/LCK";
  621. #else
  622.     char *lockdir = "/usr/spool/uucp";
  623. #endif
  624. #endif
  625. #endif
  626.  
  627.     device = ( (devname=xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  628.  
  629. #ifdef ISIII
  630.     (void) strcpy( lockfil, device );
  631. #else
  632.     strcat( strcpy( lockfil, "LCK.." ), device );
  633. #endif
  634.  
  635.     if (access( lockdir, 04 ) < 0) {    /* read access denied on lock dir */
  636.     fprintf(stderr,"Warning, read access to lock directory denied\n");
  637.     return( 1 );            /* cannot check or set lock file */
  638.     }
  639.     
  640.     strcat(strcat(strcpy(flfnam,lockdir),"/"), lockfil);
  641.     debug(F110,"look4lk",flfnam,0);
  642.  
  643.     if ( ! access( flfnam, 00 ) ) {    /* print out lock file entry */
  644.     char lckcmd[40] ;
  645.     strcat( strcpy(lckcmd, "ls -l ") , flfnam);
  646.     system(lckcmd);
  647.     if (access(flfnam,02) == 0)
  648.         printf("(You may type \"! rm %s\" to remove this file)\n",flfnam);
  649.     return( -1 );
  650.     }
  651.     if ( access( lockdir, 02 ) < 0 ) {    /* lock file cannot be written */
  652.     fprintf(stderr,"Warning, write access to lock directory denied\n");
  653.     return( 1 );
  654.     }
  655.     return( 0 );            /* okay to go ahead and lock */
  656. }
  657.  
  658. /*  T T L O C K  */
  659.  
  660.  
  661. static
  662. ttlock(ttyfd) char *ttyfd; {        /* lock uucp if possible */
  663. #ifdef ATT3BX
  664.     FILE *lck_fild;
  665. #endif
  666.     int lck_fil, l4l;
  667.     int pid_buf = getpid();        /* pid to save in lock file */
  668.     
  669.     hasLock = 0;            /* not locked yet */
  670.     l4l = look4lk(ttyfd);
  671.     if (l4l < 0) return (-1);        /* already locked */
  672.     if (l4l == 1) return (0);        /* can't read/write lock directory */
  673.     lck_fil = creat(flfnam, 0444);    /* create lock file ... */
  674.     if (lck_fil < 0) return (-1);    /* create of lockfile failed */
  675.         /* creat leaves file handle open for writing -- hf */
  676. #ifdef ATT3BX
  677.     fprintf((lck_fild = fdopen(lck_fil, "w")), "%10d\n", pid_buf);
  678.     fflush(lck_fild);
  679. #else
  680.     write (lck_fil, &pid_buf, sizeof(pid_buf) ); /* uucp expects int in file */
  681. #endif
  682.     close (lck_fil);
  683.     hasLock = 1;            /* now is locked */
  684.     return(0);
  685. }
  686.  
  687. /*  T T U N L O C K  */
  688.  
  689. static
  690. ttunlck() {                /* kill uucp lock if possible */
  691.     if (hasLock) return( unlink( flfnam ) );
  692. }
  693.  
  694. #endif /* NOLOCKS */
  695.  
  696. /* New-style (4.3BSD) UUCP line direction control (Stan Barber, Rice U) */
  697.  
  698. #ifdef NEWUUCP
  699. acucntrl(flag,ttname) char *flag, *ttname; {
  700.     char x[DEVNAMLEN+32], *device, *devname;
  701.  
  702.     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
  703.         return;                /* just return. */
  704.     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  705.     if (strncmp(device,"LCK..",4) == 0) device += 5;
  706.     sprintf(x,"/usr/lib/uucp/acucntrl %s %s",flag,device);
  707.     debug(F000,"called ",x,0);
  708.     system(x);
  709. }
  710. #endif
  711.  
  712. /*  T T P K T  --  Condition the communication line for packets. */
  713. /*        or for modem dialing */
  714.  
  715. #define DIALING    4        /* flags (via flow) for modem handling */
  716. #define CONNECT 5
  717.  
  718. /*  If called with speed > -1, also set the speed.  */
  719.  
  720. /*  Returns 0 on success, -1 on failure.  */
  721.  
  722. ttpkt(speed,flow) int speed, flow; {
  723.     int s;
  724.     if (ttyfd < 0) return(-1);        /* Not open. */
  725.  
  726. #ifdef KERLD
  727. /* Note, KERLD ignores the TANDEM, ECHO, and CRMOD bits */
  728.     if (kerld) {
  729.     ioctl(ttyfd,TIOCGETD,&oldld);    /* Get line discipline */
  730.     ioctl(ttyfd,TIOCGETC,&oldc);    /* Get special chars */
  731.     newc = oldc;            /* Copy special chars */
  732.     newc.t_brkc = '\r';        /* Set CR to be break character */
  733.     if(ioctl(ttyfd,TIOCSETC,&newc) < 0) return(-1);
  734.     }
  735. #endif
  736.  
  737.     s = ttsspd(speed);            /* Check the speed */
  738.  
  739. #ifndef UXIII
  740.     if (flow == 1) ttraw.sg_flags |= TANDEM; /* Use XON/XOFF if selected */
  741.     if (flow == 0) ttraw.sg_flags &= ~TANDEM;
  742.     ttraw.sg_flags |= RAW;        /* Go into raw mode */
  743.     ttraw.sg_flags &= ~(ECHO|CRMOD);    /* Use CR for break character */
  744. #ifdef TOWER1
  745.     ttraw.sg_flags &= ~ANYP;         /* Must tell Tower no parityr */
  746. #endif
  747.     if (s > -1) ttraw.sg_ispeed = ttraw.sg_ospeed = s; /* Do the speed */
  748.     if (stty(ttyfd,&ttraw) < 0) return(-1);    /* Set the new modes. */
  749.  
  750. #ifdef MYREAD
  751. #ifdef BSD4
  752. /* Try to make reads nonblocking */
  753.     if (kerld == 0) {
  754.     if (fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL,0) & FNDELAY) == -1)
  755.             return(-1);
  756.     else return(0);
  757.     }
  758. #endif
  759. #endif
  760. #endif
  761.  
  762. #ifdef UXIII
  763.     if (flow == 1) ttraw.c_iflag |= (IXON|IXOFF);
  764.     if (flow == 0) ttraw.c_iflag &= ~(IXON|IXOFF);
  765.  
  766.     if (flow == DIALING)  ttraw.c_cflag |= CLOCAL|HUPCL;
  767.     if (flow == CONNECT)  ttraw.c_cflag &= ~CLOCAL;
  768.  
  769.     ttraw.c_lflag &= ~(ICANON|ECHO);
  770.     ttraw.c_lflag |= ISIG;        /* do check for interrupt */
  771.     ttraw.c_iflag |= (BRKINT|IGNPAR);
  772.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
  773.     ttraw.c_oflag &= ~OPOST;
  774.     ttraw.c_cflag &= ~(CSIZE|PARENB);
  775.     ttraw.c_cflag |= (CS8|CREAD);
  776.     ttraw.c_cc[4] = 1;
  777.     ttraw.c_cc[5] = 0;
  778.  
  779.     if (s > -1) {            /* set speed */
  780.         ttraw.c_cflag &= ~CBAUD;
  781.     ttraw.c_cflag |= s;
  782.     }
  783.     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1);  /* set new modes . */
  784.     if (flow == DIALING) {
  785.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  786.         return(-1);
  787.     close( open(ttnmsv,2) );    /* magic to force mode change!!! */
  788.     }
  789. #endif
  790.  
  791. #ifdef KERLD
  792.     if (kerld) {
  793.     if (ioctl(ttyfd,TIOCSETD,&ld) < 0)
  794.         return(-1); /* Set line discpline. */
  795.     }
  796. #endif
  797.  
  798.     ttflui();                /* Flush any pending input */
  799.     return(0);
  800. }
  801.  
  802. /*  T T V T -- Condition communication line for use as virtual terminal  */
  803.  
  804. ttvt(speed,flow) int speed, flow; {
  805.     int s;
  806.     if (ttyfd < 0) return(-1);        /* Not open. */
  807.  
  808.     s = ttsspd(speed);            /* Check the speed */
  809.  
  810. #ifndef UXIII
  811.     if (flow == 1) tttvt.sg_flags |= TANDEM; /* XON/XOFF if selected */
  812.     if (flow == 0) tttvt.sg_flags &= ~TANDEM;
  813.     tttvt.sg_flags |= RAW;        /* Raw mode */
  814. #ifdef TOWER1
  815.     tttvt.sg_flags &= ~(ECHO|ANYP);    /* No echo or system III ??? parity */
  816. #else
  817.     tttvt.sg_flags &= ~ECHO;        /* No echo */
  818. #endif    
  819.     if (s > -1) tttvt.sg_ispeed = tttvt.sg_ospeed = s; /* Do the speed */
  820.     if (stty(ttyfd,&tttvt) < 0) return(-1);
  821. #ifdef MYREAD
  822. #ifdef BSD4
  823. /* Make reads nonblocking */
  824.     if (kerld == 0) {
  825.     if (fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL,0) & FNDELAY) == -1)
  826.         return(-1);
  827.     else return(0);
  828.     }
  829. #endif
  830. #endif
  831.  
  832. #else
  833.     if (flow == 1) tttvt.c_iflag |= (IXON|IXOFF);
  834.     if (flow == 0) tttvt.c_iflag &= ~(IXON|IXOFF);
  835.  
  836.     if (flow == DIALING)  tttvt.c_cflag |= CLOCAL|HUPCL;
  837.     if (flow == CONNECT)  tttvt.c_cflag &= ~CLOCAL;
  838.  
  839.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
  840.     tttvt.c_iflag |= (IGNBRK|IGNPAR);
  841.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY);
  842.     tttvt.c_oflag &= ~OPOST;
  843.     tttvt.c_cflag &= ~(CSIZE|PARENB);
  844.     tttvt.c_cflag |= (CS8|CREAD);
  845.     tttvt.c_cc[4] = 1;
  846.     tttvt.c_cc[5] = 0;
  847.  
  848.     if (s > -1) {            /* set speed */
  849.     tttvt.c_cflag &= ~CBAUD;
  850.     tttvt.c_cflag |= s;
  851.     }
  852.     if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1);  /* set new modes . */
  853.     if (flow == DIALING) {
  854.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  855.         return(-1);
  856.     close( open(ttnmsv,2) );    /* magic to force mode change!!! */
  857.     }
  858.     return(0);
  859. #endif
  860. }
  861.  
  862. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  863.  
  864. ttsspd(speed) {
  865.     int s, spdok;
  866.  
  867.     if (speed < 0) return(-1);
  868.     spdok = 1;            /* Assume arg ok */
  869.     switch (speed) {
  870.         case 0:    s = B0;    break;    /* Just the common ones. */
  871.         case 110:  s = B110;  break;    /* The others from ttydev.h */
  872.         case 150:  s = B150;  break;    /* could also be included if */
  873.         case 300:  s = B300;  break;    /* necessary... */
  874.         case 600:  s = B600;  break;
  875.         case 1200: s = B1200; break;
  876.         case 1800: s = B1800; break;
  877.         case 2400: s = B2400; break;
  878.         case 4800: s = B4800; break;
  879.         case 9600: s = B9600; break;
  880. #ifdef PLEXUS
  881.         case 19200: s = EXTA; break;
  882. #endif
  883.         default:
  884.             spdok = 0;
  885.         fprintf(stderr,"Unsupported line speed - %d\n",speed);
  886.         fprintf(stderr,"Current speed not changed\n");
  887.         break;
  888.     }        
  889.     if (spdok) return(s); else return(-1);
  890.  }
  891.  
  892.  
  893.  
  894. /*  T T F L U I  --  Flush tty input buffer */
  895.  
  896. ttflui() {
  897.  
  898. #ifndef UXIII
  899.     long n;
  900. #endif
  901.     if (ttyfd < 0) return(-1);        /* Not open. */
  902.  
  903.     ungotn = -1;            /* Initialize myread() stuff */
  904.     inbufc = 0;
  905.  
  906. #ifdef UXIII
  907.     if (ioctl(ttyfd,TCFLSH,0) < 0) perror("flush failed");
  908. #else
  909. #ifdef TIOCFLUSH
  910. #ifdef ANYBSD
  911.     n = FREAD;                /* Specify read queue */
  912.     if (ioctl(ttyfd,TIOCFLUSH,&n) < 0) perror("flush failed");
  913. #else
  914.     if (ioctl(ttyfd,TIOCFLUSH,0) < 0) perror("flush failed");
  915. #endif
  916. #endif
  917. #endif
  918.     return(0);
  919. }
  920.  
  921. /* Interrupt Functions */
  922.  
  923.  
  924. /* Timeout handler for communication line input functions */
  925.  
  926. timerh() {
  927.     longjmp(sjbuf,1);
  928. }
  929.  
  930.  
  931. /* Set up terminal interrupts on console terminal */
  932.  
  933. #ifdef UXIII
  934. esctrp() {                /* trap console escapes (^\) */
  935.     conesc = 1;
  936.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  937. }
  938. #endif
  939.  
  940. #ifdef V7
  941. esctrp() {                /* trap console escapes (^\) */
  942.     conesc = 1;
  943.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  944. }
  945. #endif
  946.  
  947. #ifdef C70
  948. esctrp() {                /* trap console escapes (^\) */
  949.     conesc = 1;
  950.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  951. }
  952. #endif
  953.  
  954. /*  C O N I N T  --  Console Interrupt setter  */
  955.  
  956. conint(f) int (*f)(); {            /* Set an interrupt trap. */
  957.  
  958.     if (!isatty(0)) return(0);        /* only for real ttys */
  959.     if (backgrd) return;        /* must ignore signals in bkgrd */
  960.  
  961. /*
  962.  Except for special cases below, ignore keyboard quit signal.
  963.  ^\ too easily confused with connect escape, and besides, we don't want
  964.  to leave lock files around.  (Frank Prindle)
  965. */
  966.     signal(SIGQUIT,SIG_IGN);
  967.  
  968. #ifdef UXIII
  969.     signal(SIGQUIT,esctrp);        /* console escape in pkt modes */
  970.     if (conesc) {            /* clear out pending escapes */
  971.     conesc = 0;
  972.     }
  973. #endif
  974.  
  975. #ifdef V7
  976.     signal(SIGQUIT,esctrp);        /* console escape in pkt modes */
  977.     if (conesc) {            /* clear out pending escapes */
  978.     conesc = 0;
  979.     }
  980. #endif
  981.  
  982.     if (conif) return;            /* Nothing to do if already on. */
  983.  
  984. /* check if invoked in background -- if so signals set to be ignored */
  985.  
  986.     if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
  987.     backgrd = 1;            /*   means running in background */
  988. #ifdef UXIII
  989.     signal(SIGQUIT,SIG_IGN);    /*   must leave signals ignored */
  990. #endif
  991. #ifdef V7
  992.     signal(SIGQUIT,SIG_IGN);    /*   must leave signals ignored */
  993. #endif
  994.     return;
  995.     }
  996.     signal(SIGINT,f);            /* Function to trap to on interrupt. */
  997.     signal(SIGHUP,f);            /* Or hangup, so lock file cleared. */
  998.     conif = 1;                /* Flag console interrupts on. */
  999. }
  1000.  
  1001.  
  1002. /*  C O N N O I  --  Reset console terminal interrupts */
  1003.  
  1004. connoi() {                /* Console-no-interrupts */
  1005.  
  1006.     if (!isatty(0)) return(0);        /* only for real ttys */
  1007.     if (backgrd) return;        /* Ignore signals in background */
  1008.  
  1009.     signal(SIGINT,SIG_DFL);
  1010.     signal(SIGHUP,SIG_DFL);
  1011.     signal(SIGQUIT,SIG_DFL);
  1012.     conif = 0;                /* Flag interrupt trapping off */
  1013. }
  1014.  
  1015. /*  myread() -- For use by systems that can do nonblocking read() calls  */
  1016. /*
  1017.  Returns:
  1018.   -1  if no characters available,
  1019.   -2  upon error (such as disconnect),
  1020.   otherwise value of character (0 or greater)
  1021. */
  1022. myread() {
  1023.     static int inbuf_item;
  1024.     static CHAR inbuf[257];
  1025.     CHAR readit;
  1026.     
  1027.     if (ungotn >= 0) {
  1028.     readit = ungotn;
  1029.     } else {
  1030.         if (inbufc > 0) {
  1031.         readit = inbuf[++inbuf_item];
  1032.         } else {
  1033.         if ((inbufc = read(ttyfd,inbuf,256)) == 0) {  /* end of file */
  1034.             /* means carrier dropped on modem connection */
  1035.         errno = 9999;        /* magic number for no carrier */
  1036.         return(-2);        /* end of file has no errno */
  1037.         }
  1038.         if (inbufc < 0) {        /* Real error */
  1039.                 return(-2);
  1040.             }
  1041.         readit = inbuf[inbuf_item = 0];
  1042.     }
  1043.         inbufc--;    
  1044.     }
  1045.     ungotn = -1;
  1046.     return(((int)readit) & 0377);
  1047. }
  1048.  
  1049. myunrd(ch) CHAR ch; {            /* push back up to one character */
  1050.     ungotn = ch;
  1051. }
  1052.  
  1053. /*  I N I T R A W Q  --  Set up to read /DEV/KMEM for character count.  */
  1054.  
  1055. #ifdef    V7
  1056. #ifndef MINIX
  1057. /*
  1058.  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
  1059.  eliminates blocking on a read, because we can read /dev/kmem to get the
  1060.  number of characters available for raw input.  If your system can't
  1061.  or you won't let it read /dev/kmem (the world that is) then you must
  1062.  figure out a different way to do the counting of characters available,
  1063.  or else replace this by a dummy function that always returns 0.
  1064. */
  1065. /*
  1066.  * Call this routine as: initrawq(tty)
  1067.  * where tty is the file descriptor of a terminal.  It will return
  1068.  * (as a char *) the kernel-mode memory address of the rawq character
  1069.  * count, which may then be read.  It has the side-effect of flushing
  1070.  * input on the terminal.
  1071.  */
  1072. /*
  1073.  * John Mackin, Physiology Dept., University of Sydney (Australia)
  1074.  * ...!decvax!mulga!physiol.su.oz!john
  1075.  *
  1076.  * Permission is hereby granted to do anything with this code, as
  1077.  * long as this comment is retained unmodified and no commercial
  1078.  * advantage is gained.
  1079.  */
  1080. #include <a.out.h>
  1081. #include <sys/proc.h>
  1082.  
  1083. char *initrawq(tty) int tty; {
  1084. #ifdef UTS24
  1085.     return(0);
  1086. #else
  1087. #ifdef BSD29
  1088.     return(0);
  1089. #else
  1090.     long lseek();
  1091.     static struct nlist nl[] = {
  1092.     {PROCNAME},
  1093.     {NPROCNAME},
  1094.     {""}
  1095.     };
  1096.     static struct proc *pp;
  1097.     char *malloc(), *qaddr, *p, c;
  1098.     int m, pid, me;
  1099.     NPTYPE xproc;            /* Its type is defined in makefile. */
  1100.     int catch();
  1101.  
  1102.     me = getpid();
  1103.     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
  1104.     nlist(BOOTNAME, nl);
  1105.     if (nl[0].n_type == 0) err("proc array");
  1106.  
  1107.     if (nl[1].n_type == 0) err("nproc");
  1108.  
  1109.     lseek(m, (long)(nl[1].n_value), 0);
  1110.     read (m, &xproc, sizeof(xproc));
  1111.     signal(SIGALRM, catch);
  1112.     if ((pid = fork()) == 0) {
  1113.     while(1)
  1114.         read(tty, &c, 1);
  1115.     }
  1116.     alarm(2);
  1117.  
  1118.     if(setjmp(jjbuf) == 0) {
  1119.     while(1)
  1120.         read(tty, &c, 1);
  1121.     }
  1122.     signal(SIGALRM, SIG_DFL);
  1123.  
  1124. #ifdef DIRECT
  1125.     pp = (struct proc *) nl[0].n_value;
  1126. #else 
  1127.     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
  1128.     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
  1129. #endif
  1130.     lseek(m, (long)(nl[1].n_value), 0);
  1131.     read(m, &xproc, sizeof(xproc));
  1132.  
  1133.     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
  1134.     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
  1135.     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
  1136.         err("read proc table");
  1137.     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
  1138.     if (pp -> p_pid == (short) pid) goto iout;
  1139.     }
  1140.     err("no such proc");
  1141.  
  1142. iout:
  1143.     close(m);
  1144.     qaddr = (char *)(pp -> p_wchan);
  1145.     free (p);
  1146.     kill(pid, SIGKILL);
  1147.     wait((int *)0);        /* Destroy the ZOMBIEs! */
  1148.     return (qaddr);
  1149. #endif
  1150. #endif
  1151. }
  1152.  
  1153. /*  More V7-support functions...  */
  1154.  
  1155. static
  1156. err(s) char *s; {
  1157.     char buf[200];
  1158.  
  1159.     sprintf(buf, "fatal error in initrawq: %s", s);
  1160.     perror(buf);
  1161.     doexit(1);
  1162. }
  1163.  
  1164. static
  1165. catch() {
  1166.     longjmp(jjbuf, -1);
  1167. }
  1168.  
  1169. #endif MINIX
  1170.  
  1171. /*  G E N B R K  --  Simulate a modem break.  */
  1172.  
  1173. #define    BSPEED    B150
  1174.  
  1175. genbrk(fn) int fn; {
  1176.     struct sgttyb ttbuf;
  1177.     int ret, sospeed;
  1178.  
  1179.     ret = ioctl(fn, TIOCGETP, &ttbuf);
  1180.     sospeed = ttbuf.sg_ospeed;
  1181.     ttbuf.sg_ospeed = BSPEED;
  1182.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  1183.     ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", 8);
  1184.     ttbuf.sg_ospeed = sospeed;
  1185.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  1186.     ret = write(fn, "@", 1);
  1187.     return;
  1188. }
  1189. #endif    V7
  1190.  
  1191. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  1192.  
  1193. ttchk() {
  1194.     int x; long n;
  1195. #ifdef MYREAD
  1196.     if ((x = inbufc + (ungotn >= 0)) > 0)
  1197.     return x;
  1198. #endif
  1199. #ifdef FIONREAD
  1200.     x = ioctl(ttyfd, FIONREAD, &n);    /* Berkeley and maybe some others */
  1201.     debug(F101,"ttchk","",n);
  1202.     return((x < 0) ? 0 : n);
  1203. #else
  1204. #ifdef    V7
  1205. #ifndef MINIX
  1206.     lseek(kmem[TTY], (long) qaddr[TTY], 0);
  1207.     x = read(kmem[TTY], &n, sizeof(int));
  1208.     return((x == sizeof(int))? n: 0);
  1209. #endif
  1210. #else    V7
  1211. #ifdef PROVX1
  1212.     x = ioctl(ttyfd, TIOCQCNT, &ttbuf);
  1213.     n = ttbuf.sg_ispeed & 0377;
  1214.     return((x < 0) ? 0 : n);
  1215. #else
  1216.     return(0);
  1217. #endif
  1218. #endif
  1219. #endif
  1220. }
  1221.  
  1222.  
  1223. /*  T T X I N  --  Get n characters from tty input buffer  */
  1224.  
  1225. /*  Returns number of characters actually gotten, or -1 on failure  */
  1226.  
  1227. /*  Intended for use only when it is known that n characters are actually */
  1228. /*  Available in the input buffer.  */
  1229.  
  1230. ttxin(n,buf) int n; char *buf; {
  1231.     int x;
  1232.     CHAR c;
  1233.  
  1234. #ifdef MYREAD
  1235.     for( x = 0; (x > -1) && (x < n); buf[x++] = myread() );
  1236. #else
  1237.     debug(F101,"ttxin: n","",n);
  1238.     x = read(ttyfd,buf,n);
  1239.     debug(F101," x","",x);
  1240. #endif
  1241.     if (x > 0) buf[x] = '\0';
  1242.     if (x < 0) x = -1;
  1243.     return(x);
  1244. }
  1245.  
  1246. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  1247.  
  1248. ttol(s,n) int n; char *s; {
  1249.     int x;
  1250.     if (ttyfd < 0) return(-1);        /* Not open. */
  1251.     x = write(ttyfd,s,n);
  1252.     debug(F111,"ttol",s,n);
  1253.     if (x < 0) debug(F101,"ttol failed","",x);
  1254.     return(x);
  1255. }
  1256.  
  1257.  
  1258. /*  T T O C  --  Output a character to the communication line  */
  1259.  
  1260. ttoc(c) char c; {
  1261.     if (ttyfd < 0) return(-1);        /* Not open. */
  1262.     return(write(ttyfd,&c,1));
  1263. }
  1264.  
  1265. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1266. /*
  1267.   If no break character encountered within "max", return "max" characters,
  1268.   with disposition of any remaining characters undefined.  Otherwise, return
  1269.   the characters that were read, including the break character, in "dest" and
  1270.   the number of characters read as the value of function, or 0 upon end of
  1271.   file, or -1 if an error occurred.  Times out & returns error if not completed
  1272.   within "timo" seconds.
  1273. */
  1274.  
  1275. ttinl(dest,max,timo,eol) int max,timo; char *dest; char eol; {
  1276.     int x, y;
  1277.     CHAR c;
  1278.  
  1279.     if (ttyfd < 0) return(-1);        /* Not open. */
  1280.     if (timo <= 0) {            /* Untimed read... */
  1281.  
  1282. #ifdef MYREAD
  1283.     for (x = c = 0; (x < max) && (c != eol); x++) {
  1284.          while ((y = myread()) == -1) ;
  1285.          if (y == -2) return(-1);
  1286.          dest[x] = c = y & 0377;
  1287.     }
  1288. #else
  1289.     x = read(ttyfd,dest,max);    /* Try to read. */
  1290. #endif
  1291.     return(x);            /* Return the count. */
  1292.     }
  1293.  
  1294. /* Timed read... */
  1295.  
  1296.     signal(SIGALRM,timerh);        /* Set up timeout action. */
  1297.     alarm(timo);            /* Set the timer. */
  1298.     if (setjmp(sjbuf))            /* Do this if timer went off. */
  1299.         x = -1;
  1300.     else if (kerld) {            /* Efficient Kermit line discipline */
  1301.     x = read(ttyfd,dest,max);    /* for 4.2bsd only... */
  1302.     } else {                /* Normal case... */
  1303.     for (x = c = y = 0; (x < max) && (c != eol); x++) {
  1304. #ifdef MYREAD
  1305.             while ((y = myread()) == -1) /* Use own buffering if we can */
  1306.             ;
  1307.         if (y == -2) y++;
  1308.         c = y & 0377;
  1309. #else
  1310.         while ((y = read(ttyfd,&c,1)) == 0) /* Else call system */
  1311.             ;            /* ...for each character. */
  1312. #endif
  1313.         if (y < 0) {
  1314.         alarm(0);        /* Error, turn off timer, */
  1315.         signal(SIGALRM,SIG_DFL); /* and associated interrupt. */
  1316.         return(y);        /* Return the error indication. */
  1317.         }
  1318.             dest[x] = c;
  1319.     }
  1320.     x++;
  1321.     }
  1322.     alarm(0);                /* Success, turn off timer, */
  1323.     signal(SIGALRM,SIG_DFL);        /* and associated interrupt. */
  1324.     return(x);                /* Return the count. */
  1325. }
  1326.  
  1327. /*  T T I N C --  Read a character from the communication line  */
  1328.  
  1329. ttinc(timo) int timo; {
  1330.     int n = 0;
  1331.     CHAR ch = 0;
  1332.  
  1333.     if (ttyfd < 0) return(-1);        /* Not open. */
  1334.     if (timo <= 0) {            /* Untimed. */
  1335. #ifdef MYREAD
  1336.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  1337.         while ((n = myread()) == -1) ;    /* Wait for a character... */
  1338.     if (n == -2) n++;
  1339.     return( n );
  1340. #else
  1341.     while ((n = read(ttyfd,&ch,1)) == 0) ; /* Wait for a character. */
  1342.     return( (n > 0) ? (ch & 0377) : n );
  1343. #endif
  1344.     }
  1345.  
  1346.     signal(SIGALRM,timerh);        /* Timed, set up timer. */
  1347.     alarm(timo);
  1348.     if (setjmp(sjbuf)) {
  1349.     n = -1;
  1350.     } else {
  1351. #ifdef MYREAD
  1352.         while ((n = myread()) == -1) ;    /* If managing own buffer... */
  1353.     if (n == -2) {
  1354.         n++;
  1355.     } else {
  1356.         ch = n;
  1357.         n = 1;    
  1358.     }
  1359. #else
  1360.         n = read(ttyfd,&ch,1);        /* Otherwise call the system. */
  1361. #endif
  1362.     }
  1363.     alarm(0);                /* Turn off timer, */
  1364.     signal(SIGALRM,SIG_DFL);        /* and interrupt. */
  1365.     return( (n > 0) ? (ch & 0377) : n ); /* Return char or -1. */
  1366. }
  1367.  
  1368. /*  T T S N D B  --  Send a BREAK signal  */
  1369.  
  1370. ttsndb() {
  1371.     int x; long n; char spd;
  1372.  
  1373.     if (ttyfd < 0) return(-1);        /* Not open. */
  1374.  
  1375. #ifdef PROVX1
  1376.     gtty(ttyfd,&ttbuf);            /* Get current tty flags */
  1377.     spd = ttbuf.sg_ospeed;        /* Save speed */
  1378.     ttbuf.sg_ospeed = B50;        /* Change to 50 baud */
  1379.     stty(ttyfd,&ttbuf);            /*  ... */
  1380.     write(ttyfd,brnuls,3);        /* Send 3 nulls */
  1381.     ttbuf.sg_ospeed = spd;        /* Restore speed */
  1382.     stty(ttyfd,&ttbuf);            /*  ... */
  1383.     return(0);
  1384. #else
  1385. #ifdef UXIII
  1386.     if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) {    /* Send a BREAK */
  1387.         perror("Can't send BREAK");
  1388.     return(-1);
  1389.     }
  1390.     return(0);
  1391. #else
  1392. #ifdef ANYBSD
  1393.     n = FWRITE;                /* Flush output queue. */
  1394.     ioctl(ttyfd,TIOCFLUSH,&n);         /* Ignore any errors.. */
  1395.     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {    /* Turn on BREAK */
  1396.         perror("Can't send BREAK");
  1397.     return(-1);
  1398.     }
  1399.     x = msleep(275);            /* Sleep for so many milliseconds */
  1400.     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {    /* Turn off BREAK */
  1401.     perror("BREAK stuck!!!");
  1402.     doexit(1);            /* Get out, closing the line. */
  1403.                     /*   with exit status = 1 */
  1404.     }
  1405.     return(x);
  1406. #else
  1407. #ifdef    V7
  1408.     genbrk(ttyfd);            /* Simulate a BREAK */
  1409.     return(x);
  1410. #endif
  1411. #endif
  1412. #endif
  1413. #endif
  1414. }
  1415.  
  1416. /*  M S L E E P  --  Millisecond version of sleep().  */
  1417.  
  1418. /*
  1419.  Intended only for small intervals.  For big ones, just use sleep().
  1420. */
  1421.  
  1422. msleep(m) int m; {
  1423.  
  1424. #ifdef PROVX1
  1425.     if (m <= 0) return(0);
  1426.     sleep(-((m * 60 + 500) / 1000));
  1427.     return(0);
  1428. #endif
  1429.  
  1430. #ifdef ANYBSD
  1431.     int t1, t3, t4;
  1432.     if (m <= 0) return(0);
  1433. #ifndef BSD42
  1434. /* 2.9 and 4.1 BSD do it this way */
  1435.     if (ftime(&ftp) < 0) return(-1);    /* Get current time. */
  1436.     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
  1437.     while (1) {
  1438.     ftime(&ftp);            /* new time */
  1439.     t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
  1440.     if (t3 > m) return (t3);
  1441.     }
  1442. #else
  1443. /* 4.2 & above can do it with select()... */
  1444.     if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */
  1445.     t1 = tv.tv_sec;            /* Seconds */
  1446.  
  1447.     tv.tv_sec = 0;            /* Use select() */
  1448.     tv.tv_usec = m * 1000;
  1449.     return(select( 0, (int *)0, (int *)0, (int *)0, &tv) );
  1450. #endif
  1451. #endif
  1452.  
  1453. #ifdef UXIII
  1454. #ifdef XENIX
  1455. #define CLOCK_TICK 50            /* millisecs per clock tick */
  1456. #else
  1457. #define CLOCK_TICK 17            /* 1/60 sec */
  1458. #endif
  1459.     extern long times();
  1460.     long t1, t2, tarray[4];
  1461.     int t3;
  1462.  
  1463.     if (m <= 0) return(0);
  1464.     if ((t1 = times(tarray)) < 0) return(-1);
  1465.     while (1) {
  1466.     if ((t2 = times(tarray)) < 0) return(-1);
  1467.     t3 = ((int)(t2 - t1)) * CLOCK_TICK;
  1468.     if (t3 > m) return(t3);
  1469.     }
  1470. #endif
  1471.  
  1472. #ifdef TOWER1
  1473.     int t1, t3;
  1474.     if (m <= 0) return(0);
  1475.     if (ftime(&ftp) < 0) return(-1);        /* Get current time. */
  1476.     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
  1477.     while (1) {
  1478.     ftime(&ftp);                /* new time */
  1479.     t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
  1480.     if (t3 > m) return (t3);
  1481.     }
  1482. #endif
  1483. }
  1484.  
  1485. /*  R T I M E R --  Reset elapsed time counter  */
  1486.  
  1487. rtimer() {
  1488.     tcount = time( (long *) 0 );
  1489. }
  1490.  
  1491.  
  1492. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1493.  
  1494. gtimer() {
  1495.     int x;
  1496.     x = (int) (time( (long *) 0 ) - tcount);
  1497.     rtimer();
  1498.     return( (x < 0) ? 0 : x );
  1499. }
  1500.  
  1501.  
  1502. /*  Z T I M E  --  Return date/time string  */
  1503.  
  1504. ztime(s) char **s; {
  1505.  
  1506. #ifdef UXIII
  1507.     extern long time();            /* Sys III/V way to do it */
  1508.     char *ctime();
  1509.     long clock_storage;
  1510.  
  1511.     clock_storage = time( (long *) 0 );
  1512.     *s = ctime( &clock_storage );
  1513. #endif
  1514.  
  1515. #ifdef PROVX1
  1516.     int utime[2];            /* Venix way */
  1517.     time(utime);
  1518.     *s = ctime(utime);
  1519. #endif
  1520.  
  1521. #ifdef ANYBSD
  1522.     char *asctime();            /* Berkeley way */
  1523.     struct tm *localtime();
  1524.     struct tm *tp;
  1525. #ifdef BSD42
  1526.     gettimeofday(&tv, &tz);        /* BSD 4.2 */
  1527.     time(&tv.tv_sec);
  1528.     tp = localtime(&tv.tv_sec);
  1529. #else
  1530.     time(&clock);            /* BSD 4.1, 2.9 ... ceb */
  1531.     tp = localtime(&clock);
  1532. #endif
  1533.     *s = asctime(tp);
  1534. #endif
  1535.  
  1536. #ifdef TOWER1
  1537.     char *asctime();            /* Tower way */
  1538.     struct tm *localtime();
  1539.     struct tm *tp;
  1540.  
  1541.     time(&clock);
  1542.     tp = localtime(&clock);
  1543.     *s = asctime(tp);
  1544. #endif
  1545. #ifdef V7
  1546.     char *asctime();            /* V7 way */
  1547.     struct tm *localtime();
  1548.     struct tm *tp;
  1549.  
  1550.     time(&clock);
  1551.     tp = localtime(&clock);
  1552.     *s = asctime(tp);
  1553. #endif
  1554. }
  1555.  
  1556. /*  C O N G M  --  Get console terminal modes.  */
  1557.  
  1558. /*
  1559.  Saves current console mode, and establishes variables for switching between 
  1560.  current (presumably normal) mode and other modes.
  1561. */
  1562.  
  1563. congm() {
  1564.     if (!isatty(0)) return(0);        /* only for real ttys */
  1565. #ifndef UXIII
  1566.      gtty(0,&ccold);            /* Structure for restoring */
  1567.      gtty(0,&cccbrk);            /* For setting CBREAK mode */
  1568.      gtty(0,&ccraw);            /* For setting RAW mode */
  1569. #else
  1570.      ioctl(0,TCGETA,&ccold);
  1571.      ioctl(0,TCGETA,&cccbrk);
  1572.      ioctl(0,TCGETA,&ccraw);
  1573. #endif
  1574.      cgmf = 1;                /* Flag that we got them. */
  1575. }
  1576.  
  1577.  
  1578. /*  C O N C B --  Put console in cbreak mode.  */
  1579.  
  1580. /*  Returns 0 if ok, -1 if not  */
  1581.  
  1582. concb(esc) char esc; {
  1583.     int x;
  1584.     if (!isatty(0)) return(0);        /* only for real ttys */
  1585.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  1586.     escchr = esc;            /* Make this available to other fns */
  1587.     ckxech = 1;                /* Program can echo characters */
  1588. #ifndef UXIII
  1589.     cccbrk.sg_flags |= CBREAK;        /* Set to character wakeup, */
  1590.     cccbrk.sg_flags &= ~ECHO;        /* no echo. */
  1591.     x = stty(0,&cccbrk);
  1592. #else
  1593.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  1594.     cccbrk.c_cc[0] = 003;        /* interrupt char is control-c */
  1595.     cccbrk.c_cc[1] = escchr;        /* escape during packet modes */
  1596.     cccbrk.c_cc[4] = 1;
  1597.     cccbrk.c_cc[5] = 1;
  1598.     x = ioctl(0,TCSETAW,&cccbrk);      /* set new modes . */
  1599. #endif
  1600.     if (x > -1) setbuf(stdout,NULL);    /* Make console unbuffered. */
  1601. #ifdef    V7
  1602. #ifndef MINIX
  1603.     if (kmem[CON] < 0) {
  1604.     qaddr[CON] = initrawq(0);
  1605.     if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
  1606.         fprintf(stderr, "Can't read /dev/kmem in concb.\n");
  1607.         perror("/dev/kmem");
  1608.         exit(1);
  1609.     }
  1610.     }
  1611. #endif
  1612. #endif    V7
  1613.     return(x);
  1614. }
  1615.  
  1616. /*  C O N B I N  --  Put console in binary mode  */
  1617.  
  1618. /*  Returns 0 if ok, -1 if not  */
  1619.  
  1620. conbin(esc) char esc; {
  1621.     if (!isatty(0)) return(0);        /* only for real ttys */
  1622.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  1623.     escchr = esc;            /* Make this available to other fns */
  1624.     ckxech = 1;                /* Program can echo characters */
  1625. #ifndef UXIII
  1626.     ccraw.sg_flags |= (RAW|TANDEM);       /* Set rawmode, XON/XOFF */
  1627.     ccraw.sg_flags &= ~(ECHO|CRMOD);      /* Set char wakeup, no echo */
  1628.     return(stty(0,&ccraw));
  1629. #else
  1630.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  1631.     ccraw.c_iflag |= (BRKINT|IGNPAR);
  1632.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
  1633.             |INPCK|ISTRIP);
  1634.     ccraw.c_oflag &= ~OPOST;
  1635.  
  1636. /*** Kermit used to put the console in 8-bit raw mode, but some users have
  1637.  *** pointed out that this should not be done, since some sites actually
  1638.  *** use terminals with parity settings on their Unix systems, and if we
  1639.  *** override the current settings and stop doing parity, then their terminals
  1640.  *** will display blotches for characters whose parity is wrong.  Therefore,
  1641.  *** the following two lines are commented out (Larry Afrin, Clemson U):
  1642.  ***
  1643.  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
  1644.  ***   ccraw.c_cflag |= (CS8|CREAD);
  1645.  ***
  1646.  *** Sys III/V sites that have trouble with this can restore these lines.
  1647.  ***/
  1648.     ccraw.c_cc[4] = 1;
  1649.     ccraw.c_cc[5] = 1;
  1650.     return(ioctl(0,TCSETAW,&ccraw) );      /* set new modes . */
  1651. #endif
  1652. }
  1653.  
  1654.  
  1655. /*  C O N R E S  --  Restore the console terminal  */
  1656.  
  1657. conres() {
  1658.     if (cgmf == 0) return(0);        /* Don't do anything if modes */
  1659.     if (!isatty(0)) return(0);        /* only for real ttys */
  1660. #ifndef UXIII                /* except for sIII, */
  1661.     sleep(1);                /*  not known! */
  1662. #endif                    /*   (sIII does wait in ioctls) */
  1663.     ckxech = 0;                /* System should echo chars */
  1664. #ifndef UXIII
  1665.     return(stty(0,&ccold));        /* Restore controlling tty */
  1666. #else
  1667.     return(ioctl(0,TCSETAW,&ccold));
  1668. #endif
  1669. }
  1670.  
  1671. /*  C O N O C  --  Output a character to the console terminal  */
  1672.  
  1673. conoc(c) char c; {
  1674.     write(1,&c,1);
  1675. }
  1676.  
  1677. /*  C O N X O  --  Write x characters to the console terminal  */
  1678.  
  1679. conxo(x,s) char *s; int x; {
  1680.     write(1,s,x);
  1681. }
  1682.  
  1683. /*  C O N O L  --  Write a line to the console terminal  */
  1684.  
  1685. conol(s) char *s; {
  1686.     int len;
  1687.     len = strlen(s);
  1688.     write(1,s,len);
  1689. }
  1690.  
  1691. /*  C O N O L A  --  Write an array of lines to the console terminal */
  1692.  
  1693. conola(s) char *s[]; {
  1694.     int i;
  1695.     for (i=0 ; *s[i] ; i++) conol(s[i]);
  1696. }
  1697.  
  1698. /*  C O N O L L  --  Output a string followed by CRLF  */
  1699.  
  1700. conoll(s) char *s; {
  1701.     conol(s);
  1702.     write(1,"\r\n",2);
  1703. }
  1704.  
  1705. /*  C O N C H K  --  Return how many characters available at console  */
  1706.  
  1707. conchk() {
  1708.     int x; long n;
  1709.  
  1710. #ifdef PROVX1 
  1711.     x = ioctl(0, TIOCQCNT, &ttbuf);
  1712.     n = ttbuf.sg_ispeed & 0377;
  1713.     return((x < 0) ? 0 : n);
  1714. #else
  1715. #ifdef V7
  1716. #ifndef MINIX
  1717.     lseek(kmem[CON], (long) qaddr[CON], 0);
  1718.     x = read(kmem[CON], &n, sizeof(int));
  1719.     return((x == sizeof(int))? n: 0);
  1720. #endif
  1721. #else
  1722. #ifdef UXIII
  1723.     if (conesc) {            /* Escape typed */
  1724.     conesc = 0;
  1725.     signal(SIGQUIT,esctrp);        /* Restore escape */
  1726.     return(1);
  1727.     }
  1728.     return(0);
  1729. #else
  1730. #ifdef C70
  1731.     if (conesc) {            /* Escape typed */
  1732.     conesc = 0;
  1733.     signal(SIGQUIT,esctrp);        /* Restore escape */
  1734.     return(1);
  1735.     }
  1736.     return(0);
  1737. #endif
  1738. #endif
  1739. #endif
  1740. #endif
  1741. #ifdef FIONREAD
  1742.     x = ioctl(0, FIONREAD, &n);        /* BSD and maybe some others */
  1743.     return((x < 0) ? 0 : n);
  1744. #endif
  1745.     return(0);                /* Others can't do. */
  1746. }
  1747.  
  1748. /*  C O N I N C  --  Get a character from the console  */
  1749.  
  1750. coninc(timo) int timo; {
  1751.     int n = 0; char ch;
  1752.     if (timo <= 0 ) {            /* untimed */
  1753.     n = read(0, &ch, 1);        /* Read a character. */
  1754.     ch &= 0377;
  1755.     if (n > 0) return(ch);         /* Return the char if read */
  1756.     else 
  1757. #ifdef UXIII
  1758.         if (n < 0 && errno == EINTR) /* if read was interrupted by QUIT */
  1759.         return(escchr);         /* user entered escape character */
  1760.         else            /* couldnt be ^c, sigint never returns */
  1761. #endif
  1762.         return(-1);          /* Return the char, or -1. */
  1763.     }
  1764.     signal(SIGALRM,timerh);        /* Timed read, so set up timer */
  1765.     alarm(timo);
  1766.     if (setjmp(sjbuf)) n = -2;
  1767.     else {
  1768.     n = read(0, &ch, 1);
  1769.     ch &= 0377;
  1770.     }
  1771.     alarm(0);                /* Stop timing, we got our character */
  1772.     signal(SIGALRM,SIG_DFL);
  1773.     if (n > 0) return(ch);
  1774.     else
  1775. #ifdef UXIII
  1776.         if (n == -1 && errno == EINTR)  /* If read interrupted by QUIT, */
  1777.         return(escchr);        /* user entered escape character, */
  1778.         else                    /* can't be ^c, sigint never returns */
  1779. #endif
  1780.         return(-1);
  1781. }
  1782.