mike@brl-tgr.ARPA (Michael John Muuss <mike>) (10/31/84)
Enclosed are new version of the 4.2 BSD /etc/getty program, plus the sources and manual page for BRL's PACXMON program. Also included is the Melbourn code for autobauding if you don't have a PACX. echo 'sh - gettytab' sed 's/^X//' <<'________This_Is_The_END________' >>gettytab X# @(#)gettytab 4.5 (Berkeley) 83/08/08 X X# X# Most of the table entries here are just copies of the X# old getty table, it is by no means certain, or even likely, X# then any of them are optimal for any purpose whatever. X# Nor is it likely that more than a couple are even correct X# X X# X# The default gettytab entry, used to set defaults for all other X# entries, and in cases where getty is called with no table name X# Xdefault:\ X :ap:cb:ce:ck:\ X :im=\r\n\r\nBRL VAX UNIX [4.2 BSD] (%h)\r\n\r\r\n\r:sp#1200: X XP|PACX:\ X :gp:to#60: X XA|Auto-baud:\ X :ab:sp#2400:f0#040: X X# X# Fixed speed entries X# X# the "std.NNN" names are known to the special case X# portselector code in getty, however they can X# be assigned to any table desired. X# Xa|std.110|110-baud:\ X :nd#1:cd#1:uc:sp#110: Xb|std.134|134.5-baud:\ X :ep:nd#1:cd#2:ff#1:td#1:sp#134:nl: X1|std.150|150-baud:\ X :ep:nd#1:cd#2:td#1:fd#1:sp#150:nl:lm=\E\72\6\6\17login\72 : Xc|std.300|300-baud:\ X :nd#1:cd#1:sp#300: Xd|std.600|600-baud:\ X :nd#1:cd#1:sp#600: Xf|std.1200|1200-baud:\ X :sp#1200: X6|std.2400|2400-baud:\ X :sp#2400: X7|std.4800|4800-baud:\ X :sp#4800: X2|std.9600|9600-baud:\ X :sp#9600: X X# X# Dial in rotary tables, speed selection via 'break' X# X0|d300|Dial-300:\ X :nx=d1200:cd#2:sp#300: Xd1200|Dial-1200:\ X :nx=d150:fd#1:sp#1200: Xd150|Dial-150:\ X :nx=d110:lm@:tc=150-baud: Xd110|Dial-110:\ X :nx=d300:tc=300-baud: X X# X# Odd special case terminals X# X-|tty33|asr33|Pity the poor user of this beast:\ X :tc=110-baud: X X4|Console|Console Decwriter II:\ X :nd@:cd@:rw:tc=300-baud: X Xi|Interdata console:\ X :uc:sp#0: X Xl|lsi chess terminal:\ X :sp#300: X X# X# Fast dialup terminals, 1200/300 rotary (can start either way) X# X3|D1200|Fast-Dial-1200:\ X :nx=D300:tc=1200-baud: X5|D300|Fast-Dial-300:\ X :nx=D1200:tc=300-baud: X X# X# Wierdo special case for fast crt's with hardcopy devices X# X8|T9600|CRT with hardcopy:\ X :nx=T300:tc=9600-baud: X9|T300|CRT with hardcopy (300):\ X :nx=T9600:tc=300-baud: X X# X# Plugboard, and misc other terminals X# Xp|P9600|Plugboard-9600:\ X :nx=P300:tc=9600-baud: Xq|P300|Plugboard-300:\ X :nx=P1200:tc=300-baud: Xr|P1200|Plugboard-1200:\ X :nx=P9600:tc=1200-baud: X X# X# XXXX Port selector X# Xs|Port Selector:\ X :ps:sp#1200: ________This_Is_The_END________ echo 'sh - gettytab.c' sed 's/^X//' <<'________This_Is_The_END________' >>gettytab.c X/* X * G E T T Y T A B . C X * X * $Revision: 1.2 $ X * X * $Log: gettytab.c,v $ X * Revision 1.2 83/12/16 01:55:33 rsm X * Added distinctive RCS header X * X */ X#ifndef lint Xstatic char RCSid[] = "@(#)$Header: gettytab.c,v 1.2 83/12/16 01:55:33 rsm BRL $"; X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)gettytab.c 4.2 (Berkeley) 83/09/25"; X#endif X X#include <ctype.h> X X#define TABBUFSIZ 512 X Xstatic char *tbuf; Xint hopcount; /* detect infinite loops in termcap, init 0 */ Xchar *skip(); Xchar *getstr(); Xchar *decode(); X X/* X * Get an entry for terminal name in buffer bp, X * from the termcap file. Parse is very rudimentary; X * we just notice escaped newlines. X */ Xgetent(bp, name) X char *bp, *name; X{ X register char *cp; X register int c; X register int i = 0, cnt = 0; X char ibuf[TABBUFSIZ]; X char *cp2; X int tf; X X tbuf = bp; X tf = open("/etc/gettytab", 0); X if (tf < 0) X return (-1); X for (;;) { X cp = bp; X for (;;) { X if (i == cnt) { X cnt = read(tf, ibuf, TABBUFSIZ); X if (cnt <= 0) { X close(tf); X return (0); X } X i = 0; X } X c = ibuf[i++]; X if (c == '\n') { X if (cp > bp && cp[-1] == '\\'){ X cp--; X continue; X } X break; X } X if (cp >= bp+TABBUFSIZ) { X write(2,"Gettytab entry too long\n", 24); X break; X } else X *cp++ = c; X } X *cp = 0; X X /* X * The real work for the match. X */ X if (namatch(name)) { X close(tf); X return(nchktc()); X } X } X} X X/* X * tnchktc: check the last entry, see if it's tc=xxx. If so, X * recursively find xxx and append that entry (minus the names) X * to take the place of the tc=xxx entry. This allows termcap X * entries to say "like an HP2621 but doesn't turn on the labels". X * Note that this works because of the left to right scan. X */ X#define MAXHOP 32 Xnchktc() X{ X register char *p, *q; X char tcname[16]; /* name of similar terminal */ X char tcbuf[TABBUFSIZ]; X char *holdtbuf = tbuf; X int l; X X p = tbuf + strlen(tbuf) - 2; /* before the last colon */ X while (*--p != ':') X if (p<tbuf) { X write(2, "Bad gettytab entry\n", 19); X return (0); X } X p++; X /* p now points to beginning of last field */ X if (p[0] != 't' || p[1] != 'c') X return(1); X strcpy(tcname,p+3); X q = tcname; X while (q && *q != ':') X q++; X *q = 0; X if (++hopcount > MAXHOP) { X write(2, "Getty: infinite tc= loop\n", 25); X return (0); X } X if (getent(tcbuf, tcname) != 1) X return(0); X for (q=tcbuf; *q != ':'; q++) X ; X l = p - holdtbuf + strlen(q); X if (l > TABBUFSIZ) { X write(2, "Gettytab entry too long\n", 24); X q[TABBUFSIZ - (p-tbuf)] = 0; X } X strcpy(p, q+1); X tbuf = holdtbuf; X return(1); X} X X/* X * Tnamatch deals with name matching. The first field of the termcap X * entry is a sequence of names separated by |'s, so we compare X * against each such name. The normal : terminator after the last X * name (before the first field) stops us. X */ Xnamatch(np) X char *np; X{ X register char *Np, *Bp; X X Bp = tbuf; X if (*Bp == '#') X return(0); X for (;;) { X for (Np = np; *Np && *Bp == *Np; Bp++, Np++) X continue; X if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) X return (1); X while (*Bp && *Bp != ':' && *Bp != '|') X Bp++; X if (*Bp == 0 || *Bp == ':') X return (0); X Bp++; X } X} X X/* X * Skip to the next field. Notice that this is very dumb, not X * knowing about \: escapes or any such. If necessary, :'s can be put X * into the termcap file in octal. X */ Xstatic char * Xskip(bp) X register char *bp; X{ X X while (*bp && *bp != ':') X bp++; X if (*bp == ':') X bp++; X return (bp); X} X X/* X * Return the (numeric) option id. X * Numeric options look like X * li#80 X * i.e. the option string is separated from the numeric value by X * a # character. If the option is not found we return -1. X * Note that we handle octal numbers beginning with 0. X */ Xlong Xgetnum(id) X char *id; X{ X register long i, base; X register char *bp = tbuf; X X for (;;) { X bp = skip(bp); X if (*bp == 0) X return (-1); X if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) X continue; X if (*bp == '@') X return(-1); X if (*bp != '#') X continue; X bp++; X base = 10; X if (*bp == '0') X base = 8; X i = 0; X while (isdigit(*bp)) X i *= base, i += *bp++ - '0'; X return (i); X } X} X X/* X * Handle a flag option. X * Flag options are given "naked", i.e. followed by a : or the end X * of the buffer. Return 1 if we find the option, or 0 if it is X * not given. X */ Xgetflag(id) X char *id; X{ X register char *bp = tbuf; X X for (;;) { X bp = skip(bp); X if (!*bp) X return (-1); X if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { X if (!*bp || *bp == ':') X return (1); X else if (*bp == '!') X return (0); X else if (*bp == '@') X return(-1); X } X } X} X X/* X * Get a string valued option. X * These are given as X * cl=^Z X * Much decoding is done on the strings, and the strings are X * placed in area, which is a ref parameter which is updated. X * No checking on area overflow. X */ Xchar * Xgetstr(id, area) X char *id, **area; X{ X register char *bp = tbuf; X X for (;;) { X bp = skip(bp); X if (!*bp) X return (0); X if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) X continue; X if (*bp == '@') X return(0); X if (*bp != '=') X continue; X bp++; X return (decode(bp, area)); X } X} X X/* X * Tdecode does the grung work to decode the X * string capability escapes. X */ Xstatic char * Xdecode(str, area) X register char *str; X char **area; X{ X register char *cp; X register int c; X register char *dp; X int i; X X cp = *area; X while ((c = *str++) && c != ':') { X switch (c) { X X case '^': X c = *str++ & 037; X break; X X case '\\': X dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; X c = *str++; Xnextc: X if (*dp++ == c) { X c = *dp++; X break; X } X dp++; X if (*dp) X goto nextc; X if (isdigit(c)) { X c -= '0', i = 2; X do X c <<= 3, c |= *str++ - '0'; X while (--i && isdigit(*str)); X } X break; X } X *cp++ = c; X } X *cp++ = 0; X str = *area; X *area = cp; X return (str); X} ________This_Is_The_END________ echo 'sh - gettytab.h' sed 's/^X//' <<'________This_Is_The_END________' >>gettytab.h X/* X * G E T T Y T A B . H X * X * $Revision: 1.2 $ X * X * $Log: gettytab.h,v $ X * Revision 1.2 83/12/16 01:55:40 rsm X * Added distinctive RCS header X * X */ X X/* gettytab.h 4.3 83/07/09 */ X X/* X * Getty description definitions. X */ Xstruct gettystrs { X char *field; /* name to lookup in gettytab */ X char *defalt; /* value we find by looking in defaults */ X char *value; /* value that we find there */ X}; X Xstruct gettynums { X char *field; /* name to lookup */ X long defalt; /* number we find in defaults */ X long value; /* number we find there */ X int set; /* we actually got this one */ X}; X Xstruct gettyflags { X char *field; /* name to lookup */ X char invrt; /* name existing in gettytab --> false */ X char defalt; /* true/false in defaults */ X char value; /* true/false flag */ X char set; /* we found it */ X}; X X/* X * String values. X */ X#define NX gettystrs[0].value X#define CL gettystrs[1].value X#define IM gettystrs[2].value X#define LM gettystrs[3].value X#define ER gettystrs[4].value X#define KL gettystrs[5].value X#define ET gettystrs[6].value X#define PC gettystrs[7].value X#define TT gettystrs[8].value X#define EV gettystrs[9].value X#define LO gettystrs[10].value X#define HN gettystrs[11].value X#define HE gettystrs[12].value X#define IN gettystrs[13].value X#define QU gettystrs[14].value X#define XN gettystrs[15].value X#define XF gettystrs[16].value X#define BK gettystrs[17].value X#define SU gettystrs[18].value X#define DS gettystrs[19].value X#define RP gettystrs[20].value X#define FL gettystrs[21].value X#define WE gettystrs[22].value X#define LN gettystrs[23].value X X/* X * Numeric definitions. X */ X#define IS gettynums[0].value X#define OS gettynums[1].value X#define SP gettynums[2].value X#define ND gettynums[3].value X#define CD gettynums[4].value X#define TD gettynums[5].value X#define FD gettynums[6].value X#define BD gettynums[7].value X#define TO gettynums[8].value X#define F0 gettynums[9].value X#define F0set gettynums[9].set X#define F1 gettynums[10].value X#define F1set gettynums[10].set X#define F2 gettynums[11].value X#define F2set gettynums[11].set X#define PF gettynums[12].value X X/* X * Boolean values. X */ X#define HT gettyflags[0].value X#define NL gettyflags[1].value X#define EP gettyflags[2].value X#define EPset gettyflags[2].set X#define OP gettyflags[3].value X#define OPset gettyflags[2].set X#define AP gettyflags[4].value X#define APset gettyflags[2].set X#define EC gettyflags[5].value X#define CO gettyflags[6].value X#define CB gettyflags[7].value X#define CK gettyflags[8].value X#define CE gettyflags[9].value X#define PE gettyflags[10].value X#define RW gettyflags[11].value X#define XC gettyflags[12].value X#define LC gettyflags[13].value X#define UC gettyflags[14].value X#define IG gettyflags[15].value X#define PS gettyflags[16].value X#define HC gettyflags[17].value X#define UB gettyflags[18].value X#define AB gettyflags[19].value X#define GP gettyflags[20].value X Xint getent(); Xlong getnum(); Xint getflag(); Xchar *getstr(); X Xextern struct gettyflags gettyflags[]; Xextern struct gettynums gettynums[]; Xextern struct gettystrs gettystrs[]; Xextern int hopcount; ________This_Is_The_END________ echo 'sh - init.c' sed 's/^X//' <<'________This_Is_The_END________' >>init.c X/* X * I N I T . C X * X * $Revision: 1.3 $ X * X * $Log: init.c,v $ X * Revision 1.3 84/02/23 21:44:38 rsm X * Various changes including pacx support and autobauding X * X * Revision 1.2 83/12/16 01:55:46 rsm X * Added distinctive RCS header X * X */ X#ifndef lint Xstatic char RCSid[] = "@(#)$Header: init.c,v 1.3 84/02/23 21:44:38 rsm BRL $"; X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)init.c 4.4 (Berkeley) 83/07/09"; X#endif X X/* X * Getty table initializations. X * X * Melbourne getty. X */ X#include <sgtty.h> X#include "gettytab.h" X Xextern struct sgttyb tmode; Xextern struct tchars tc; Xextern struct ltchars ltc; Xextern char hostname[]; X Xstruct gettystrs gettystrs[] = { X { "nx" }, /* next table */ X { "cl" }, /* screen clear characters */ X { "im" }, /* initial message */ X { "lm", "login: " }, /* login message */ X { "er", &tmode.sg_erase }, /* erase character */ X { "kl", &tmode.sg_kill }, /* kill character */ X { "et", &tc.t_eofc }, /* eof chatacter (eot) */ X { "pc", "" }, /* pad character */ X { "tt" }, /* terminal type */ X { "ev" }, /* enviroment */ X { "lo", "/bin/login" }, /* login program */ X { "hn", hostname }, /* host name */ X { "he" }, /* host name edit */ X { "in", &tc.t_intrc }, /* interrupt char */ X { "qu", &tc.t_quitc }, /* quit char */ X { "xn", &tc.t_startc }, /* XON (start) char */ X { "xf", &tc.t_stopc }, /* XOFF (stop) char */ X { "bk", &tc.t_brkc }, /* brk char (alt \n) */ X { "su", <c.t_suspc }, /* suspend char */ X { "ds", <c.t_dsuspc }, /* delayed suspend */ X { "rp", <c.t_rprntc }, /* reprint char */ X { "fl", <c.t_flushc }, /* flush output */ X { "we", <c.t_werasc }, /* word erase */ X { "ln", <c.t_lnextc }, /* literal next */ X { 0 } X}; X Xstruct gettynums gettynums[] = { X { "is" }, /* input speed */ X { "os" }, /* output speed */ X { "sp" }, /* both speeds */ X { "nd" }, /* newline delay */ X { "cd" }, /* carriage-return delay */ X { "td" }, /* tab delay */ X { "fd" }, /* form-feed delay */ X { "bd" }, /* backspace delay */ X { "to" }, /* timeout */ X { "f0" }, /* output flags */ X { "f1" }, /* input flags */ X { "f2" }, /* user mode flags */ X { "pf" }, /* delay before flush at 1st prompt */ X { 0 } X}; X Xstruct gettyflags gettyflags[] = { X { "ht", 0 }, /* has tabs */ X { "nl", 1 }, /* has newline char */ X { "ep", 0 }, /* even parity */ X { "op", 0 }, /* odd parity */ X { "ap", 0 }, /* any parity */ X { "ec", 1 }, /* no echo */ X { "co", 0 }, /* console special */ X { "cb", 0 }, /* crt backspace */ X { "ck", 0 }, /* crt kill */ X { "ce", 0 }, /* crt erase */ X { "pe", 0 }, /* printer erase */ X { "rw", 1 }, /* don't use raw */ X { "xc", 1 }, /* don't ^X ctl chars */ X { "lc", 0 }, /* terminal las lower case */ X { "uc", 0 }, /* terminal has no lower case */ X { "ig", 0 }, /* ignore garbage */ X { "ps", 0 }, /* do port selector speed select */ X { "hc", 1 }, /* don't set hangup on close */ X { "ub", 0 }, /* unbuffered output */ X { "ab", 0 }, /* auto-baud detect with '\r' */ X { "gp", 0 }, /* connected to Gandalf PACX IV */ X { 0 } X}; ________This_Is_The_END________ echo 'sh - main.c' sed 's/^X//' <<'________This_Is_The_END________' >>main.c X/* X * M A I N . C X * X * $Revision: 1.4 $ X * X * $Log: main.c,v $ X * Revision 1.4 84/08/09 01:48:01 dpk X * Modified getty to pass line number as hostname to login X * X * Revision 1.3 84/02/23 21:44:47 rsm X * Various changes including pacx support and autobauding X * X * Revision 1.2 83/12/16 01:55:53 rsm X * Added distinctive RCS header X * X */ X#ifndef lint Xstatic char RCSid[] = "@(#)$Header: main.c,v 1.4 84/08/09 01:48:01 dpk BRL $"; X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)main.c 4.5 (Berkeley) 83/08/01"; X#endif X X/* X * getty -- adapt to terminal speed on dialup, and call login X * X * Melbourne getty, June 83, kre. X */ X X#include <sgtty.h> X#include <signal.h> X#include <ctype.h> X#include <setjmp.h> X#include "gettytab.h" X Xstruct sgttyb tmode = { X 0, 0, CERASE, CKILL, 0 X}; Xstruct tchars tc = { X CINTR, CQUIT, CSTART, X CSTOP, CEOF, CBRK, X}; Xstruct ltchars ltc = { X CSUSP, CDSUSP, CRPRNT, X CFLUSH, CWERASE, CLNEXT X}; X Xint crmod; Xint upper; Xint lower; Xint digit; X Xchar hostname[32]; Xchar name[16]; Xchar *portselector(); X X#define OBUFSIZ 128 X#define TABBUFSIZ 512 X Xchar defent[TABBUFSIZ]; Xchar defstrs[TABBUFSIZ]; Xchar tabent[TABBUFSIZ]; Xchar tabstrs[TABBUFSIZ]; X Xchar *env[128]; X Xchar partab[] = { X 0001,0201,0201,0001,0201,0001,0001,0201, X 0202,0004,0003,0205,0005,0206,0201,0001, X 0201,0001,0001,0201,0001,0201,0201,0001, X 0001,0201,0201,0001,0201,0001,0001,0201, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0000,0200,0200,0000,0200,0000,0000,0200, X 0000,0200,0200,0000,0200,0000,0000,0200, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0000,0200,0200,0000,0200,0000,0000,0200, X 0000,0200,0200,0000,0200,0000,0000,0200, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0000,0200,0200,0000,0200,0000,0000,0200, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0200,0000,0000,0200,0000,0200,0200,0000, X 0000,0200,0200,0000,0200,0000,0000,0201 X}; X X#define ERASE tmode.sg_erase X#define KILL tmode.sg_kill X#define EOT tc.t_eofc X Xjmp_buf timeout; X Xdingdong() X{ X X alarm(0); X signal(SIGALRM, SIG_DFL); X longjmp(timeout, 1); X} X Xjmp_buf intrupt; X Xinterrupt() X{ X X signal(SIGINT, interrupt); X longjmp(intrupt, 1); X} X Xmain(argc, argv) X char *argv[]; X{ X char *tname; X long allflags; X extern char *pacx_term; X extern char *pacx_line; X X signal(SIGINT, SIG_IGN); X/* X signal(SIGQUIT, SIG_DFL); X*/ X gethostname(hostname, sizeof(hostname)); X if (hostname[0] == '\0') X strcpy(hostname, "Amnesiac"); X gettable("default", defent, defstrs); X gendefaults(); X tname = "default"; X if (argc > 1) X tname = argv[1]; X for (;;) { X int ldisp = OTTYDISC; X X gettable(tname, tabent, tabstrs); X if (OPset || EPset || APset) X APset++, OPset++, EPset++; X setdefaults(); X ioctl(0, TIOCFLUSH, 0); /* clear out the crap */ X if (IS) X tmode.sg_ispeed = speed(IS); X else if (SP) X tmode.sg_ispeed = speed(SP); X if (OS) X tmode.sg_ospeed = speed(OS); X else if (SP) X tmode.sg_ospeed = speed(SP); X tmode.sg_flags = setflags(0); X ioctl(0, TIOCSETP, &tmode); X setchars(); X ioctl(0, TIOCSETC, &tc); X ioctl(0, TIOCSETD, &ldisp); X if (HC) X ioctl(0, TIOCHPCL, 0); X if (GP) { X extern char *pacx(); X X tname = pacx(argv[2]); /* !!! */ X X /* Drop connection if name is null */ X if (tname == 0) { X tmode.sg_ispeed = tmode.sg_ospeed = 0; X ioctl(0, TIOCSETP, &tmode); X exit(1); X } X continue; X } X if (AB) { X extern char *autobaud(); X X tname = autobaud(); X continue; X } X if (PS) { X tname = portselector(); X continue; X } X if (CL && *CL) X putpad(CL); X edithost(HE); X if (IM && *IM) X putf(IM); X if (setjmp(timeout)) { X tmode.sg_ispeed = tmode.sg_ospeed = 0; X ioctl(0, TIOCSETP, &tmode); X exit(1); X } X if (TO) { X signal(SIGALRM, dingdong); X alarm(TO); X } X if (getname()) { X alarm(0); X signal(SIGALRM, SIG_DFL); X if (!(upper || lower || digit)) X continue; X allflags = setflags(2); X tmode.sg_flags = allflags & 0xffff; X allflags >>= 16; X if (crmod || NL) X tmode.sg_flags |= CRMOD; X if (upper || UC) X tmode.sg_flags |= LCASE; X if (lower || LC) X tmode.sg_flags &= ~LCASE; X ioctl(0, TIOCSETP, &tmode); X ioctl(0, TIOCSLTC, <c); X ioctl(0, TIOCLSET, &allflags); X putchr('\n'); X oflush(); X makeenv(env); X signal(SIGINT, SIG_DFL); X if( pacx_term != 0 ) { X execle(LO, "login", "-t", pacx_term, "-h", X pacx_line, name, (char *)0, env); X } else { X execle(LO, "login", name, (char *)0, env); X } X exit(1); X } X alarm(0); X signal(SIGALRM, SIG_DFL); X signal(SIGINT, SIG_IGN); X if (NX && *NX) X tname = NX; X } X} X Xgetname() X{ X register char *np; X register c; X char cs; X X /* X * Interrupt may happen if we use CBREAK mode X */ X if (setjmp(intrupt)) { X signal(SIGINT, SIG_IGN); X return (0); X } X signal(SIGINT, interrupt); X tmode.sg_flags = setflags(0); X ioctl(0, TIOCSETP, &tmode); X tmode.sg_flags = setflags(1); X prompt(); X if (PF > 0) { X oflush(); X sleep(PF); X PF = 0; X } X ioctl(0, TIOCSETP, &tmode); X crmod = 0; X upper = 0; X lower = 0; X digit = 0; X np = name; X for (;;) { X oflush(); X if (read(0, &cs, 1) <= 0) X exit(0); X if ((c = cs&0177) == 0) X return (0); X if (c == EOT) X exit(1); X if (c == '\r' || c == '\n' || np >= &name[16]) X break; X X if (c >= 'a' && c <= 'z') X lower++; X else if (c >= 'A' && c <= 'Z') { X upper++; X } else if (c == ERASE || c == '#' || c == '\b') { X if (np > name) { X np--; X if (tmode.sg_ospeed >= B1200) X puts("\b \b"); X else X putchr(cs); X } X continue; X } else if (c == KILL || c == '@') { X putchr(cs); X putchr('\r'); X if (tmode.sg_ospeed < B1200) X putchr('\n'); X /* this is the way they do it down under ... */ X else if (np > name) X puts(" \r"); X prompt(); X np = name; X continue; X } else if (c == ' ') X c = '_'; X else if (c >= '0' && c <= '9') X digit++; X if (IG && (c < ' ' || c > 0176)) X continue; X *np++ = c; X putchr(cs); X } X signal(SIGINT, SIG_IGN); X *np = 0; X if (c == '\r') X crmod++; X if (upper && !lower && !LC || UC) X for (np = name; *np; np++) X if (isupper(*np)) X *np = tolower(*np); X return (1); X} X Xstatic Xshort tmspc10[] = { X 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15 X}; X Xputpad(s) X register char *s; X{ X register pad = 0; X register mspc10; X X if (isdigit(*s)) { X while (isdigit(*s)) { X pad *= 10; X pad += *s++ - '0'; X } X pad *= 10; X if (*s == '.' && isdigit(s[1])) { X pad += s[1] - '0'; X s += 2; X } X } X X puts(s); X /* X * If no delay needed, or output speed is X * not comprehensible, then don't try to delay. X */ X if (pad == 0) X return; X if (tmode.sg_ospeed <= 0 || X tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) X return; X X /* X * Round up by a half a character frame, X * and then do the delay. X * Too bad there are no user program accessible programmed delays. X * Transmitting pad characters slows many X * terminals down and also loads the system. X */ X mspc10 = tmspc10[tmode.sg_ospeed]; X pad += mspc10 / 2; X for (pad /= mspc10; pad > 0; pad--) X putchr(*PC); X} X Xputs(s) X register char *s; X{ X X while (*s) X putchr(*s++); X} X Xchar outbuf[OBUFSIZ]; Xint obufcnt = 0; X Xputchr(cc) X{ X char c; X X c = cc; X c |= partab[c&0177] & 0200; X if (OP) X c ^= 0200; X if (!UB) { X outbuf[obufcnt++] = c; X if (obufcnt >= OBUFSIZ) X oflush(); X } else X write(1, &c, 1); X} X Xoflush() X{ X if (obufcnt) X write(1, outbuf, obufcnt); X obufcnt = 0; X} X Xprompt() X{ X X putf(LM); X if (CO) X putchr('\n'); X} X Xputf(cp) X register char *cp; X{ X extern char editedhost[]; X X while (*cp) { X if (*cp != '%') { X putchr(*cp++); X continue; X } X switch (*++cp) { X X case 'h': X puts(editedhost); X break; X X case '%': X putchr('%'); X break; X } X cp++; X } X} ________This_Is_The_END________ echo 'sh - pacxmon.8b' sed 's/^X//' <<'________This_Is_The_END________' >>pacxmon.8b X.TH PACXMON 8 "2 Mar 1984" X.UC 4 X.SH NAME Xpacxmon \- manage Gandalf PACX port selector for getty X.SH SYNOPSIS X.B /usr/brl/etc/pacxmon X.SH DESCRIPTION X.I Pacxmon Xlistens to the PACX statistics port Xand maintains a complete picture of the status of all active connections Xthrough the PACX at any time. X.I Pacxmon Xmay be queried at any time (typically by \fIgetty(8)\fR) Xabout the status of a given connection. X.I Getty Xuses this procedure to automatically determine the speed Xof an incoming connection, and to discover the location and Xterminal type (for $TERM) of the terminal making the connection. X.SH "/etc/pacxports1 FORMAT XEach entry in this file describes a connection between a PACX port and a XVAX computer port. The format is: X.DS X.nf X\fIportnum\fR:\fIVAX port\fR X.fi X.DE Xwhere \fIportnum\fR is the number of the PACX port, expressed Xas 4 digits, with leading zeros, and X\fIVAX port\fR is the last component of the Xterminal line name in /dev. Example: X.nf X0320:ttyh0 X0321:ttyh1 X0322:ttyh2 X.fi X.SH "/etc/pacxlines1 FORMAT XEach entry in this file contains information about a terminal \fIline\fR Xconnected to the PACX port selector. XThe first character of each entry indicates the enabled/disabled Xstatus of the PACX \fIline\fR. A SPACE indicates the \fIline\fR is enabled, Xand a DASH (minus) indicates a comment. Format is: X.DS X.nf X\fIline:linenum:TERM:Class:Rate:Initial STTY modes:Location:Voice Phone\fR X.fi X.PP X\fILinenum\fR is the number of the PACX line that the terminal Xis connected to, \fITERM\fR is the terminal type (in \fI/etc/termcap\fR), X\fIClass\fR is the terminal class (General, Modem, Restricted, etc), Xand presently has no effect, X\fIRate\fR is the charge rate (in units of $0.01/hour), and presently Xhas no effect, X\fIInitial STTY modes\fR describe desired deviations from Xthe standard initial terminal modes, X\fILocation\fR is a short string giving information about Xthe physical location of the terminal, and X\fIVoice Phone\fR is a phone number or extension number near the terminal. XFor example: X.nf X line:702:vis200:General:100:scope tabs:BMD (394) 231:x6678 X\-line:703:vis200:General:100:scope tabs:VLD (394) 117:x6640 Not On Yet! X.fi X.SH "/etc/ttys FORMAT XAll ports under control of X.I pacxmon Xmust be listed in /etc/ttys with package ``P'', to trigger the Xappropriate behavior in X.I getty X(via the /etc/gettytab P (PACX) entry of ``:gp:'' to ``get PACX package''). X.SH FILES X.nf X/etc/pacxlines1 description of terminal lines to PACX mapping X/etc/pacxports1 description of PACX ports to VAX port mapping X/etc/ttys enable specific VAX ports for pacxmon control X/dev/pacxstats symbolic link to /dev/tty?? from PACX Statistics port X.fi X.SH AUTHOR XRobert S. Miles X.SH SEE ALSO Xgetty(8), Xgettytab(5) X.SH BUGS XThe format of the communications between \fIpacxmon\fR and \fIgetty\fR Xis obscure, and documented only in the source code. X.PP XThe format of pacxlines1 and pacxports1 is too complex. Either Xall the promised features should be implemented, or the file format Xshould be simplified. X.PP XIf the connection to the PACX Statistics port is not working, or Xthe modem control on that VAX port is wrong, nothing happens. X.PP XThis whole interface to a port selector is very powerful, but Xexcessively complex, and somewhat fragile. X.PP XThere is a compile-time flag (\fIdebug\fR) which will cause X\fIpacxmon\fR to output a log of all the messages the PACX Xsends, plus diagnostic information about TCP connections Xwhich are made. Consult the source code. ________This_Is_The_END________ echo 'sh - pacxmon.c' sed 's/^X//' <<'________This_Is_The_END________' >>pacxmon.c X/* X * P A C X M O N . C X * X * $Revision: 1.4 $ X * X * X * PACX Software Design: R. N. Jesse, M. S. Baldwin at Hopkins ECF X * M. J. Muuss, R. S. Miles, D. P. Kingston X * at US Army BRL/BMD X * X * Original implementation: 6-Sept-81 by Michael S. Baldwin X * X * X * R E V I S I O N H I S T O R Y X * X * 30 Sep 81 DPK Pacxmon now re-execs itself inorder to re-read X * the /etc/ttys file. The child inherits the pacxstats X * file-descriptor so no pacxstats messages are lost. X * X * 10/27/81 MJM Modified so that garbage on the PACX Statistics Port X * is less damaging. X * X * 12/03/81 MJM Modified in an attempt to isolate the recurring X * cause of "untimely death of PACXMON" problems. X * X * 12/31/81 RNJ Now ignores several messages which occur during X * normal operation. X * X * 03/29/82 RSM Use setjmp/longjmp instead of setexit/reset. X * X * 12/01/82 DPK Upped number of lines (LTABSZ) from 100 to 200 X * and added checking of return from sbrk(). X * X * 04/19/83 RSM LTABSZ now max (for single PACX), 256. BLST messages X * are now ignored. Ingore hangup signals too. X * X * 05/20/83 RSM First version for 4.1c BSD. X * X * 12/21/83 RSM This version currently under revision for 4.2 BSD.... X */ X#ifndef lint Xstatic char RCSid[] = "@(#)$Header: pacxmon.c,v 1.4 84/08/07 23:25:33 dpk BRL $ (BRL)"; X#endif X X#include <sys/types.h> X#include <sys/file.h> X#include <sys/socket.h> X#include <sys/stat.h> X#include <sys/time.h> X#include <netinet/in.h> X#include <netdb.h> X#include <ctype.h> X#include <sgtty.h> X#include <signal.h> X#include <stdio.h> X X#define rselect(x) select(20, x, (int *)0, (int *)0, (struct timeval *)0) X X/* port, line and tty table sizes */ X#define PTABSZ 00400 /* Wastefull */ X#define LTABSZ 01000 /* Wastefull */ X#define TTABSZ 128 X X/* Table of PACX port mappings (from /etc/pacxports) */ Xstruct ptab { X int p_line; /* Line # currently connected */ X char p_tty[14]; /* Terminal name */ X} ptab[PTABSZ]; X X/* Table of PACX line attributes (from /etc/pacxlines) */ Xstruct ltab { X int l_port; /* Port # currently connected */ X int l_rate; /* Baud rate at time of connection */ X time_t l_time; /* UNIX Time of connection */ X char l_type[18]; /* TERM type */ X char l_place[18]; /* Location of terminal */ X} ltab[LTABSZ]; X X/* Table of PACX terminal names (from /etc/ttys) */ Xstruct ttab { X char t_tty[14]; X} ttab[TTABSZ], *Ettab; X X/*** BAUD RATE OF STATISTICS PORT SHOULD BE A PROGRAM OPTION ***/ Xstruct sgttyb pacxstty = { B9600, B9600, 0377, 0377, ANYP }; X X/* X * "bauds" maps PACX baud rates to "UNIX" baud rates by indexing X * the following table by the PACX baud rate code. Note that X * currently the PACX does not support 19.2. X */ Xstruct pbauds { X int b_ubaud; X char *b_sbaud; X} bauds[] = { X X/* UNIX meaning PACX meaning */ X X B50, "50", /* B00 -> 50 bps */ X B75, "75", /* B01 -> 75 bps */ X B110, "110", /* B02 -> 110 bps */ X B134, "134.5", /* B03 -> 134.5 bps */ X B150, "150", /* B04 -> 150 bps */ X B300, "300", /* B05 -> 300 bps */ X B600, "600", /* B06 -> 600 bps */ X B1200, "1200", /* B07 -> 1200 bps */ X B1800, "1800", /* B08 -> 1800 bps */ X B0, "2000", /* B09 -> 2000 bps */ X B2400, "2400", /* B10 -> 2400 bps */ X B0, "3600", /* B11 -> 3600 bps */ X B4800, "4800", /* B12 -> 4800 bps */ X B0, "7200", /* B13 -> 7200 bps */ X B9600, "9600", /* B14 -> 9600 bps */ X B200, "200", /* B15 -> 200 bps */ X}; X X/* PACX errors */ Xchar *pacxerr[] = { X "Power on", X "Failure of Sanity Timer", X "Low battery voltage", X "Crosspoint memory timeout error", X "Two ports being simultaneously monitored", X "Port Address Register not cycling", X "Comparator error", X 0, X "Statistics List overflow", X 0, X "Failure of USART number 1", X "Failure of USART number 2", X "Failure of USART number 3", X "Failure of USART number 4", X "Failure of USART number 5", X "Failure of USART number 6", X 0, X 0, X 0, X 0, X "State Sequencer in test mode", X "State Sequencer sequence error", X "State Sequencer deglitch timer run error" X}; X Xchar statmess[50]; /* Place for the statistics output */ X Xchar *pacxfile = "/dev/pacxstats"; Xchar *ttysfile = "/etc/ttys"; Xchar *portfile = "/etc/pacxports1"; Xchar *linefile = "/etc/pacxlines1"; X Xstruct sockaddr_in sin = { AF_INET }; Xint debug = 0; X Xextern char *index(); Xextern char *malloc(); Xextern char *strncpy(); Xextern FILE *fdopen(); Xextern struct servent *getservbyname(); X Xmain( argc, argv ) Xint argc; Xchar **argv; X{ X register int i; X struct servent *servp; X int pacxfd; X int statso; X X for (i = 1; i < argc; i++) { X if (strcmp (argv[i], "-d") == 0) X debug++; X else { X fprintf(stderr, "Usage: %s [-d]\n", argv[0]); X exit(1); X } X } X X /* Ignore nasty signals */ X (void) signal(SIGHUP, SIG_IGN); X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X (void) signal(SIGPIPE, SIG_IGN); X (void) signal(SIGTERM, SIG_IGN); X (void) signal(SIGTSTP, SIG_IGN); X X /* Device names are all relative to /dev */ X if( chdir("/dev") < 0 ) X die("Can't chdir to /dev"); X X /* Open pacx statistics port exclusively */ X if( (pacxfd = open(pacxfile, O_RDONLY|FEXLOCK|FNDELAY)) < 0 ) X die(pacxfile); X X /* Set characteristics of line */ X if( stty(pacxfd, &pacxstty) < 0 ) X die("Can't stty statistics line"); X X (void) nice(-5); /* Give ourselves good priority */ X (void) setpgrp(0, getpid()); /* Our own process group */ X X if(debug) { X time_t tnow; X extern char *ctime(); X X (void) time(&tnow); X printf("PACXMON (pid %d) started %s", getpid(), ctime(&tnow)); X (void) fflush(stdout); X } X X /* Initialize connection tables */ X for(i=0; i<LTABSZ; i++) X ltab[i].l_port = -1; X for(i=0; i<PTABSZ; i++) X ptab[i].p_line = -1; X X /*****************************************/ X /* We don't use UNIX domain IPC since it */ X /* still doesn't work right in 4.2 BSD! */ X /*****************************************/ X X if ((servp = getservbyname("ttyinfo", "tcp")) == NULL) X die("getservbyname (ttyinfo/tcp) failed"); X X /* Settup ability to receive status inquiries */ X if( (statso = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) X die("inet socket"); X X sin.sin_port = servp->s_port; X if( bind(statso, (struct sockaddr *)&sin, sizeof(sin)) == -1 ) X die("inet bind"); X X if( listen(statso, 3) == -1 ) X die("inet listen"); X X /* X * Loop forever waiting for status X * inquiries or PACX messages. X */ X for(;;) { X int readfds; X X readfds = (1<<pacxfd) | (1<<statso); X if( rselect(&readfds) == -1 ) X die("select"); X X if(readfds & (1<<pacxfd)) X pacx(pacxfd); X if(readfds & (1<<statso)) X status(statso); X (void) fflush(stdout); X } X} X X/* X * P A C X X * X * Process a message from the PACX statistics output. X */ Xpacx(fd) Xint fd; X{ X int term; X int port; X int rate; X int nread; X X /* Get the message from the PACX */ X bzero(statmess, sizeof statmess); X nread = read(fd, statmess, sizeof statmess); X X /* Check for error */ X if( nread < 0 ) X die("Read error on statistics line"); X X /* Check for end of file */ X if( nread == 0 ) X die("EOF from statistics line"); X X if(debug) X (void) write(1, statmess, nread); X X /* Check minimum length */ X if( nread < 15 ) { X err_stat("Short message"); X return; X } X X /* Must start with "HH:MM:SS" */ X if( X ! isdigit(statmess[0]) || X ! isdigit(statmess[1]) || X statmess[2] != ':' || X ! isdigit(statmess[3]) || X ! isdigit(statmess[4]) || X statmess[5] != ':' || X ! isdigit(statmess[6]) || X ! isdigit(statmess[7]) X ) { X err_stat("Bad format message"); X return; X } X X /* Oh goodie! Its a connection message of some sort! */ X if( !strncmp(&statmess[10], "CON", 3) ) { X X /* Update our mapping tables (if needed) */ X get_ttys(); /* Enabled terminal descriptions */ X get_ports(); /* Port to Terminal mappings */ X get_lines(); /* Line descriptions */ X X /* See if this is a reasonable length */ X if( nread < 32 ) { X err_stat("Short CON message"); X return; X } X X /* Valid terminal (line), class, and port markers? */ X if( X statmess[14] != 'T' || X statmess[20] != 'C' || X statmess[25] != 'P' X ) { X err_stat("Bad CON message"); X return; X } X X /* Terminal (line) number */ X term = atoo(&statmess[15]); X if( term >= LTABSZ ) { X err_stat("Bad Term"); X return; X } X X /* Port number */ X port = atoo(&statmess[26]); X if( port >= PTABSZ ) { X err_stat("Bad Port"); X return; X } X X /* Valid baud rate marker? */ X if( statmess[35] == 'B' ) { X rate = atoi(&statmess[36]); X X if( rate > 15 ) { X err_stat("Bad Term/Port/Rate"); X return; X } X } else { X /* No baud rate was specified */ X rate = -1; X } X X /* Fill in connection information */ X (void) time(<ab[term].l_time); X ltab[term].l_port = port; X ltab[term].l_rate = rate; X ptab[port].p_line = term; X return; X } X X /* Looks like one of a variety of disconnect messages? */ X if( !strncmp(&statmess[10], "DIS", 3) ) { X X /* See if this is a reasonable length */ X if( nread < 32 ) { X err_stat("Short DIS message"); X return; X } X X /* Valid terminal (line), class, and port markers? */ X if( X statmess[14] != 'T' || X statmess[20] != 'C' || X statmess[25] != 'P' X ) { X err_stat("Bad DIS message"); X return; X } X X /* Terminal (line) number */ X term = atoo(&statmess[15]); X if( term >= LTABSZ ) { X err_stat("Bad Term"); X return; X } X X /* Port number */ X port = atoo(&statmess[26]); X if( port >= 04000 ) /* Queued or USART */ X return; X if( port >= PTABSZ ) { X err_stat("Bad Port"); X return; X } X X /* Flag as not connected any longer */ X ltab[term].l_port = -1; X ptab[port].p_line = -1; X return; X } X X /* Looks like a status message? */ X if( !strncmp(&statmess[9], "STAT", 4) ) { X register int i; X X i = atoi( &statmess[14] ); X if( X i < 0 || X i >= sizeof pacxerr / sizeof(char *) || X pacxerr[i] == 0 X ) { X fprintf(stderr,"PACX: unknown status %d\n",i); X (void) fflush(stderr); X } else { X fprintf(stderr, "PACX: %s\n", pacxerr[i] ); X (void) fflush(stderr); X } X return; X } X X /* Valid, but uninteresting messages? */ X if( X !strncmp(&statmess[9], "REST", 4) || X !strncmp(&statmess[9], "QTRM", 4) || X !strncmp(&statmess[9], "BUSY", 4) || X !strncmp(&statmess[9], "UNAS", 4) || X !strncmp(&statmess[9], "BLST", 4) || X !strncmp(&statmess[9], "UNAV", 4) X ) { X return; /* Ingnore */ X } X X /* If we get here, the message is not understood */ X fprintf(stderr, "PACX: %s\n", statmess ); X (void) fflush(stderr); X} X X/* X * S T A T U S X * X * This cruft is NOT done yet..... X */ Xstatus(so) Xint so; X{ X static struct sockaddr_in sock; X static char ibuf[sizeof(ptab[0].p_tty)]; X int slen = sizeof(struct sockaddr_in); X register struct ptab *pp; X unsigned p; X unsigned l; X int ns; X int nread; X FILE *fp; X extern char *ctime(); X X static struct { X char baud[6]; X char term[14]; X int port; X int line; X time_t time; X } resp; X X bzero(ibuf, sizeof(ibuf)); X if( (ns = accept(so, (struct sockaddr *)&sock, &slen)) == -1 ) { X /* Want to hear about failures? */ X perror("PACXMON: accept"); X return; X } X X if(debug) { X printf("PACXMON: Connection on socket %d from %#X port %d\n", X ns, ntohl(sock.sin_addr.s_addr), ntohs(sock.sin_port)); X (void) fflush(stdout); X } X X /* Validate host address? -- For now don't bother */ X X /* Get information request */ X if( (nread = read(ns, ibuf, sizeof ibuf)) == -1 ) { X perror("PACXMON: socket read"); X goto out; X } X X /* Anything usefull there? */ X if( nread <= 1 ) X goto out; X X switch( *ibuf ) { X X case 'L': /* Line request */ X case 'T': X l = atoo(&ibuf[1]); X if(l >= LTABSZ) X goto out; X p = ltab[l].l_port; X break; X X case 'P': /* Port request */ X p = atoo(&ibuf[1]); X if(p >= PTABSZ) X goto out; X l = ptab[p].p_line; X break; X X default: /* Terminal name request */ X l = p = -1; X for(pp = &ptab[0]; pp < &ptab[PTABSZ]; pp++) { X if( ! strcmp(pp->p_tty, ibuf) ) { X p = pp - &ptab[0]; X l = pp->p_line; X break; X } X } X break; X } X X /* If not connected, don't say anything */ X if( ltab[l].l_port == -1 || ptab[p].p_line == -1 ) X goto out; X X strncpy(resp.baud, bauds[ltab[l].l_rate].b_sbaud, sizeof resp.baud); X strncpy(resp.term, ltab[l].l_type, sizeof resp.term); X resp.port = p; X resp.line = l; X resp.time = ltab[l].l_time; X if( write(ns, (char *)&resp, sizeof resp) != sizeof resp ) X perror("PACXMON: socket write"); Xout: X (void) close(ns); X return; X} X X/* X * E R R _ S T A T X * X * Report error generated by bogus data from statistics port. X */ Xerr_stat(mess) Xregister char *mess; X{ X fprintf(stderr, "PACX: %s: %s\n", mess, statmess); X (void) fflush(stderr); X} X X/* X * E R R _ A D V I S E X * X * Advise everyone of a non-fatal internal error. X */ Xerr_advise(mess) Xregister char *mess; X{ X fprintf(stderr, "PACXMON: %s\n", mess); X (void) fflush(stderr); X} X X/* X * E R R _ L I N E N O X * X * Voice the opinion that something is wrong with a particular X * line in one of our data files. X */ Xerr_lineno(mess, file, line) Xregister char *mess; Xregister char *file; Xregister int line; X{ X fprintf(stderr, "PACXMON: %s: line %d: %s\n", file, line, mess); X (void) fflush(stderr); X} X X/* X * D I E X * X * Some kind of error that we can't recover from has happened. X * Report about it and then "give up the ship." X */ Xdie(mess) Xchar *mess; X{ X extern int errno; X int saverrno; X X saverrno = errno; X fprintf(stderr, "PACXMON: "); X (void) fflush(stderr); X errno = saverrno; X perror(mess); X (void) fflush(stderr); X fprintf(stderr, "PACXMON: exitting\n"); X (void) fflush(stderr); X exit(1); X} X X/* X * A T O O X * X * Convert an ascii string to an octal number. X */ Xatoo(s) Xregister char *s; X{ X register int n = 0; X X while( isdigit(*s) ) X n = n*8 + *s++ - '0'; X X return(n); X} X X/* X * G E T _ T T Y S X * X * This builds a table of all the enabled terminal names X * that claim to be cabled to PACX ports. X */ Xget_ttys() X{ X static time_t modtime = 0; X register int lineno; X register char *cp; X struct stat statb; X char lbuf[30]; X int c; X FILE *fp; X X if(stat(ttysfile, &statb) < 0) X die("Can't stat ttys file"); X X if(statb.st_mtime == modtime) X return; X X modtime = statb.st_mtime; X if( (fp = fopen(ttysfile, "r")) == NULL ) X die("Can't open ttys file"); X X lineno = 0; X Ettab = &ttab[0]; X while( fgets(lbuf, sizeof lbuf, fp) != NULL ) { X X lineno++; X X /* Check for table overrun */ X if(Ettab >= &ttab[TTABSZ]) { X err_advise("Terminal table overflow"); X break; X } X X /* Terminal must be enabled */ X if(lbuf[0] != '1') X continue; X X /* Terminal should be PACX type ('P') */ X if(lbuf[1] != 'P') X continue; X X /* Find the end of the line... */ X if( (cp = index(lbuf, '\n')) == 0 ) { X X /* Line was longer than expected. Gobble rest. */ X while( (c = getc(fp)) != EOF ) { X if(c == '\n') X break; X } X err_lineno("too long", ttysfile, lineno); X continue; X } X *cp = 0; X X /* OK. Copy into our table */ X (void) strncpy(Ettab->t_tty, &lbuf[2], sizeof Ettab->t_tty); X Ettab++; X } X X (void) fclose(fp); X} X X/* X * G E T _ P O R T S X * X * This builds a mapping of PACX port numbers to terminal names. X */ Xget_ports() X{ X static time_t modtime = 0; X register struct ttab *tp; X register int lineno; X register char *cp; X struct stat statb; X unsigned u; X char lbuf[30]; X int c; X FILE *fp; X X if(stat(portfile, &statb) < 0) X die("Can't stat port file"); X X if(statb.st_mtime == modtime) X return; X X modtime = statb.st_mtime; X if( (fp = fopen(portfile, "r")) == NULL ) X die("Can't open port file"); X X lineno = 0; X while( fgets(lbuf, sizeof lbuf, fp) != NULL ) { X X lineno++; X X /* Find the end of the line... */ X if( (cp = index(lbuf, '\n')) == 0 ) { X X /* Line was longer than expected. Gobble rest. */ X while( (c = getc(fp)) != EOF ) { X if(c == '\n') X break; X } X err_lineno("too long", portfile, lineno); X continue; X } X *cp = 0; X X /* Find the colon field separator */ X if( (cp = index(lbuf, ':')) == 0 ) { X err_lineno("no colon", portfile, lineno); X continue; X } X cp++; X X /* Make sure this terminal line is enabled. */ X for(tp = ttab; tp < Ettab; tp++) { X X if( strncmp(tp->t_tty, cp, sizeof tp->t_tty) ) X continue; X X u = atoo(lbuf); X if( u >= PTABSZ ) { X err_lineno("bad port num", portfile, lineno); X break; X } X X /* Copy terminal name (null terminated) */ X (void) strncpy(ptab[u].p_tty, X cp, sizeof(ptab[u].p_tty)-1); X } X } X X (void) fclose(fp); X} X X/* X * G E T _ L I N E S X * X * This builds a mapping of PACX line numbers to TERM types. X */ Xget_lines() X{ X static time_t modtime = 0; X register int lineno; X register char *cp; X struct stat statb; X unsigned u; X char lbuf[200]; X int c; X FILE *fp; X X if(stat(linefile, &statb) < 0) X die("Can't stat line file"); X X if(statb.st_mtime == modtime) X return; X X modtime = statb.st_mtime; X if( (fp = fopen(linefile, "r")) == NULL ) X die("Can't open line file"); X X lineno = 0; X while( fgets(lbuf, sizeof lbuf, fp) != NULL ) { X X lineno++; X X /* Find the end of the line... */ X if( (cp = index(lbuf, '\n')) == 0 ) { X X /* Line was longer than expected. Gobble rest. */ X while( (c = getc(fp)) != EOF ) { X if(c == '\n') X break; X } X err_lineno("too long", linefile, lineno); X continue; X } X X /* For now, skip ALL but valid "line" descriptions. */ X if( strncmp(lbuf, " line:", 6) ) X continue; X X u = atoo(&lbuf[6]); X if(u >= LTABSZ) { X err_lineno("bad line num", linefile, lineno); X continue; X } X if( (cp = index(&lbuf[6], ':')) == NULL ) { X err_lineno("no colon", linefile, lineno); X continue; X } X cp++; X X /* Copy TERM type (null terminated) */ X (void) strncpy(ltab[u].l_type, cp, sizeof(ltab[u].l_type)-1); X if( cp = index(ltab[u].l_type, ':') ) X *cp = 0; X } X X (void) fclose(fp); X} ________This_Is_The_END________ echo 'sh - subr.c' sed 's/^X//' <<'________This_Is_The_END________' >>subr.c X/* X * S U B R . C X * X * $Revision: 1.7 $ X * X * $Log: subr.c,v $ X * Revision 1.7 84/08/19 02:10:27 dpk X * Minor change to the printf format for "line xxx", now forces 3 digits. X * X * Revision 1.6 84/08/09 01:47:33 dpk X * Modified getty to pass line number as hostname to login X * X * Revision 1.5 84/08/07 23:46:26 dpk X * changed to use getservbyname to find TCP port X * for PACX info. X * X * Revision 1.4 84/02/23 22:03:09 dpk X * Changed '\0377' to '\377'. X * X * Revision 1.3 84/02/23 21:45:13 rsm X * Various changes including pacx support and autobauding X * X * Revision 1.2 83/12/16 01:56:01 rsm X * Added distinctive RCS header X * X */ X#ifndef lint Xstatic char RCSid[] = "@(#)$Header: subr.c,v 1.7 84/08/19 02:10:27 dpk BRL $"; X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)subr.c 4.2 (Berkeley) 83/07/07"; X#endif X X/* X * Melbourne getty. X */ X#include <sgtty.h> X#include "gettytab.h" X Xextern struct sgttyb tmode; Xextern struct tchars tc; Xextern struct ltchars ltc; X X/* X * Get a table entry. X */ Xgettable(name, buf, area) X char *name, *buf, *area; X{ X register struct gettystrs *sp; X register struct gettynums *np; X register struct gettyflags *fp; X register n; X X hopcount = 0; /* new lookup, start fresh */ X if (getent(buf, name) != 1) X return; X X for (sp = gettystrs; sp->field; sp++) X sp->value = getstr(sp->field, &area); X for (np = gettynums; np->field; np++) { X n = getnum(np->field); X if (n == -1) X np->set = 0; X else { X np->set = 1; X np->value = n; X } X } X for (fp = gettyflags; fp->field; fp++) { X n = getflag(fp->field); X if (n == -1) X fp->set = 0; X else { X fp->set = 1; X fp->value = n ^ fp->invrt; X } X } X} X Xgendefaults() X{ X register struct gettystrs *sp; X register struct gettynums *np; X register struct gettyflags *fp; X X for (sp = gettystrs; sp->field; sp++) X if (sp->value) X sp->defalt = sp->value; X for (np = gettynums; np->field; np++) X if (np->set) X np->defalt = np->value; X for (fp = gettyflags; fp->field; fp++) X if (fp->set) X fp->defalt = fp->value; X else X fp->defalt = fp->invrt; X} X Xsetdefaults() X{ X register struct gettystrs *sp; X register struct gettynums *np; X register struct gettyflags *fp; X X for (sp = gettystrs; sp->field; sp++) X if (!sp->value) X sp->value = sp->defalt; X for (np = gettynums; np->field; np++) X if (!np->set) X np->value = np->defalt; X for (fp = gettyflags; fp->field; fp++) X if (!fp->set) X fp->value = fp->defalt; X} X Xstatic char ** Xcharnames[] = { X &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, X &SU, &DS, &RP, &FL, &WE, &LN, 0 X}; X Xstatic char * Xcharvars[] = { X &tmode.sg_erase, &tmode.sg_kill, &tc.t_intrc, X &tc.t_quitc, &tc.t_startc, &tc.t_stopc, X &tc.t_eofc, &tc.t_brkc, <c.t_suspc, X <c.t_dsuspc, <c.t_rprntc, <c.t_flushc, X <c.t_werasc, <c.t_lnextc, 0 X}; X Xsetchars() X{ X register int i; X register char *p; X X for (i = 0; charnames[i]; i++) { X p = *charnames[i]; X if (p && *p) X *charvars[i] = *p; X else X *charvars[i] = '\377'; X } X} X Xlong Xsetflags(n) X{ X register long f; X X switch (n) { X case 0: X if (F0set) X return(F0); X break; X case 1: X if (F1set) X return(F1); X break; X default: X if (F2set) X return(F2); X break; X } X X f = 0; X X if (AP) X f |= ANYP; X else if (OP) X f |= ODDP; X else if (EP) X f |= EVENP; X X if (UC) X f |= LCASE; X X if (NL) X f |= CRMOD; X X f |= delaybits(); X X if (n == 1) { /* read mode flags */ X if (RW) X f |= RAW; X else X f |= CBREAK; X return (f); X } X X if (!HT) X f |= XTABS; X X if (n == 0) X return (f); X X if (CB) X f |= CRTBS; X X if (CE) X f |= CRTERA; X X if (PE) X f |= PRTERA; X X if (EC) X f |= ECHO; X X if (XC) X f |= CTLECH; X X return (f); X} X Xstruct delayval { X unsigned delay; /* delay in ms */ X int bits; X}; X X/* X * below are random guesses, I can't be bothered checking X */ X Xstruct delayval crdelay[] = { X 1, CR1, X 2, CR2, X 3, CR3, X 83, CR1, X 166, CR2, X 0, CR3, X}; X Xstruct delayval nldelay[] = { X 1, NL1, /* special, calculated */ X 2, NL2, X 3, NL3, X 100, NL2, X 0, NL3, X}; X Xstruct delayval bsdelay[] = { X 1, BS1, X 0, 0, X}; X Xstruct delayval ffdelay[] = { X 1, FF1, X 1750, FF1, X 0, FF1, X}; X Xstruct delayval tbdelay[] = { X 1, TAB1, X 2, TAB2, X 3, XTABS, /* this is expand tabs */ X 100, TAB1, X 0, TAB2, X}; X Xdelaybits() X{ X register f; X X f = adelay(CD, crdelay); X f |= adelay(ND, nldelay); X f |= adelay(FD, ffdelay); X f |= adelay(TD, tbdelay); X f |= adelay(BD, bsdelay); X return (f); X} X Xadelay(ms, dp) X register ms; X register struct delayval *dp; X{ X if (ms == 0) X return (0); X while (dp->delay && ms > dp->delay) X dp++; X return (dp->bits); X} X Xchar editedhost[32]; X Xedithost(pat) X register char *pat; X{ X register char *host = HN; X register char *res = editedhost; X X if (!pat) X pat = ""; X while (*pat) { X switch (*pat) { X X case '#': X if (*host) X host++; X break; X X case '@': X if (*host) X *res++ = *host++; X break; X X default: X *res++ = *pat; X break; X X } X if (res == &editedhost[sizeof editedhost - 1]) { X *res = '\0'; X return; X } X pat++; X } X if (*host) X strncpy(res, host, sizeof editedhost - (res - editedhost) - 1); X else X *res = '\0'; X editedhost[sizeof editedhost - 1] = '\0'; X} X Xstruct speedtab { X int speed; X int uxname; X} speedtab[] = { X 50, B50, X 75, B75, X 110, B110, X 134, B134, X 150, B150, X 200, B200, X 300, B300, X 600, B600, X 1200, B1200, X 1800, B1800, X 2400, B2400, X 4800, B4800, X 9600, B9600, X 19200, EXTA, X 19, EXTA, /* for people who say 19.2K */ X 38400, EXTB, X 38, EXTB, X 7200, EXTB, /* alternative */ X 0 X}; X Xspeed(val) X{ X register struct speedtab *sp; X X if (val <= 15) X return(val); X X for (sp = speedtab; sp->speed; sp++) X if (sp->speed == val) X return (sp->uxname); X X return (B300); /* default in impossible cases */ X} X Xmakeenv(env) X char *env[]; X{ X static char termbuf[128] = "TERM="; X register char *p, *q; X register char **ep; X char *index(); X X ep = env; X if (TT && *TT) { X strcat(termbuf, TT); X *ep++ = termbuf; X } X if (p = EV) { X q = p; X while (q = index(q, ',')) { X *q++ = '\0'; X *ep++ = p; X p = q; X } X if (*p) X *ep++ = p; X } X *ep = (char *)0; X} X X/* X * This speed select mechanism is written for the Develcon DATASWITCH. X * The Develcon sends a string of the form "B{speed}\n" at a predefined X * baud rate. This string indicates the user's actual speed. X * The routine below returns the terminal type mapped from derived speed. X */ Xstruct portselect { X char *ps_baud; X char *ps_type; X} portspeeds[] = { X { "B110", "std.110" }, X { "B134", "std.134" }, X { "B150", "std.150" }, X { "B300", "std.300" }, X { "B600", "std.600" }, X { "B1200", "std.1200" }, X { "B2400", "std.2400" }, X { "B4800", "std.4800" }, X { "B9600", "std.9600" }, X { 0 } X}; X Xchar * Xportselector() X{ X char c, baud[20], *type = "default"; X register struct portselect *ps; X int len; X X alarm(5*60); X for (len = 0; len < sizeof (baud) - 1; len++) { X if (read(0, &c, 1) <= 0) X break; X c &= 0177; X if (c == '\n' || c == '\r') X break; X if (c == 'B') X len = 0; /* in case of leading garbage */ X baud[len] = c; X } X baud[len] = '\0'; X for (ps = portspeeds; ps->ps_baud; ps++) X if (strcmp(ps->ps_baud, baud) == 0) { X type = ps->ps_type; X break; X } X sleep(2); /* wait for connection to complete */ X return (type); X} X X/* X * This auto-baud speed select machanism is written for the Micom 600 X * portselector. Selection is done by looking at how the character '\r' X * is garbled at the different speeds. X */ X#include <sys/time.h> X Xchar * Xautobaud() X{ X int rfds; X struct timeval timeout; X char c, *type = "2400-baud"; X int null = 0; X X ioctl(0, TIOCFLUSH, &null); X rfds = 1 << 0; X timeout.tv_sec = 5; X timeout.tv_usec = 0; X if(select(32, &rfds, (int *)0, (int *)0, &timeout) <= 0) X return(type); X if(read(0, &c, sizeof(char)) != sizeof(char)) X return(type); X timeout.tv_sec = 0; X timeout.tv_usec = 20; X (void) select(32, (int *)0, (int *)0, (int *)0, &timeout); X ioctl(0, TIOCFLUSH, &null); X switch(c&0377){ X X case 0200: /* 300-baud */ X type = "300-baud"; X break; X X case 0346: /* 1200-baud */ X type = "1200-baud"; X break; X X case 015: /* 2400-baud */ X case 0215: X type = "2400-baud"; X break; X X default: /* 4800-baud */ X type = "4800-baud"; X break; X X case 0377: /* 9600-baud */ X type = "9600-baud"; X break; X } X return(type); X} X X/* This was hacked up very fast. Please excuse stupidities... */ X X#include <sys/types.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <netdb.h> X X#define NORMAL ret X#define AUTOBAUD "Auto-baud" X#define DROP ((char *)0) X Xextern struct servent *getservbyname(); Xchar *pacx_term = 0; Xchar *pacx_line = "line ???"; X Xchar * Xpacx(tty) Xchar *tty; X{ X struct servent *servp; X static char ret[6+6]; X static struct sockaddr_in sin = { AF_INET }; X static struct { X char baud[6]; X char term[14]; X int port; X int line; X time_t time; X } resp; X static char line_str[32]; X int so; X time_t tnow; X X pacx_term = 0; X if ((servp = getservbyname("ttyinfo", "tcp")) == 0) X return(AUTOBAUD); X X if( (so = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) X return(AUTOBAUD); X X /* X * The following assumes a lot... This is the address X * of the "loopback" interface. A portable and fast way X * to get to the current host. We can't rely on gethostid. X */ X sin.sin_addr.s_addr = htonl(0x7f000001); X sin.sin_port = servp->s_port; X X if( connect(so, &sin, sizeof sin) == -1 ) { X close(so); X return(AUTOBAUD); X } X if( write(so, tty, strlen(tty)) != strlen(tty) ) { X close(so); X return(DROP); X } X if( read(so, (char *)&resp, sizeof resp) != sizeof resp ) { X close(so); X return(DROP); X } X close(so); X X (void) time(&tnow); X if(tnow - resp.time > 10) X return(DROP); X strncpy(ret, resp.baud, sizeof(resp.baud)); X ret[sizeof(resp.baud)] = 0; X strcat(ret, "-baud"); X resp.term[sizeof(resp.term)-1] = 0; X pacx_term = resp.term; X sprintf (line_str, "line %03o", resp.line); X pacx_line = line_str; X return(NORMAL); X} ________This_Is_The_END________