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