#ident "@(#)gettydefs.c 1.6 94/03/13 Copyright(c) 1993 Gert Doering/Chris Lewis" ; /* gettydefs.c * * Read /etc/gettydefs file, and permit retrieval of individual entries. * * Code in this module by Chris Lewis */ #include #include #include #include #include #include #include #include "gettydefs.h" int gettycheck = 0; /* set to 1 for getty -c */ int lineno; /* when getty -c runs */ int gettyerrors = 0; /* # of errors encountered processing gettytab */ #define BAD(fmt, arg) (gettycheck && (((lineno) && printf("%d: ", lineno)),\ printf(fmt, arg),\ putchar('\n'),\ gettyerrors++\ )) struct modeword { char *name; int turnon; int turnoff; int metaon; int metaoff; }; /* Meta tokens */ #define SANE 0x0001 #define ODDP 0x0002 #define PARITY 0x0004 #define NPARITY 0x0008 #define RAW 0x0010 #define COOKED 0x0020 #define NL 0x0040 #define NNL 0x0080 #define LCASE 0x0100 #define NLCASE 0x0200 #define TABS 0x0400 #define NTABS 0x0800 /* input modes */ static struct modeword iflags[] = { { "ignbrk", IGNBRK, IGNBRK }, { "brkint", BRKINT, BRKINT, SANE }, { "ignpar", IGNPAR, IGNPAR, SANE }, { "parmrk", PARMRK, PARMRK }, { "inpck", INPCK, INPCK }, { "istrip", ISTRIP, ISTRIP, SANE }, { "inlcr", INLCR, INLCR, 0, NNL }, { "igncr", IGNCR, IGNCR, 0, NNL }, { "icrnl", ICRNL, ICRNL,(SANE|NL), NNL }, { "iuclc", IUCLC, IUCLC, LCASE, NLCASE }, { "ixon", IXON, IXON, SANE }, { "ixany", IXANY, IXANY }, { "ixoff", IXOFF, IXOFF }, { NULL } }; /* output modes */ static struct modeword oflags[] = { { "opost", OPOST, OPOST,(SANE|COOKED), RAW }, { "olcuc", OLCUC, OLCUC, LCASE, NLCASE }, { "onlcr", ONLCR, ONLCR, (SANE|NL), NNL }, { "ocrnl", OCRNL, OCRNL, 0, NNL }, { "onocr", ONOCR, ONOCR }, { "onlret", ONLRET, ONLRET, NNL }, { "ofill", OFILL, OFILL }, { "ofdel", OFDEL, OFDEL }, { "nldly", NLDLY, NLDLY }, { "nl0", NL0, NLDLY }, { "nl1", NL1, NLDLY }, { "cr0", CR0, CRDLY }, { "cr1", CR1, CRDLY }, { "cr2", CR2, CRDLY }, { "cr3", CR3, CRDLY }, { "tab0", TAB0, TABDLY, TABS }, { "tab1", TAB1, TABDLY }, { "tab2", TAB2, TABDLY }, { "Tab3", TAB3, TABDLY, NTABS }, { "bs0", BS0, BSDLY }, { "bs1", BS1, BSDLY }, { "vt0", VT0, VTDLY }, { "vt1", VT1, VTDLY }, { "ff0", FF0, FFDLY }, { "ff1", FF1, FFDLY }, { NULL } }; /* control modes */ static struct modeword cflags[] = { { "b0", B0, CBAUD }, { "b50", B50, CBAUD }, { "b75", B75, CBAUD }, { "b110", B110, CBAUD }, { "b134", B134, CBAUD }, { "b150", B150, CBAUD }, { "b200", B200, CBAUD }, { "b300", B300, CBAUD }, { "b600", B600, CBAUD }, #ifdef B900 { "b900", B900, CBAUD }, #endif { "b1200", B1200, CBAUD }, { "b1800", B1800, CBAUD }, { "b2400", B2400, CBAUD }, #ifdef B3600 { "b3600", B3600, CBAUD }, #endif { "b4800", B4800, CBAUD }, #ifdef B7200 { "b7200", B7200, CBAUD }, #endif { "b9600", B9600, CBAUD }, #ifdef B19200 { "b19200", B19200, CBAUD }, #endif #ifdef B38400 { "b38400", B38400, CBAUD }, #endif #ifdef B57600 { "b57600", B57600, CBAUD }, #endif #ifdef B115200 { "b115200", B115200, CBAUD }, #endif #ifdef B230400 { "b230400", B230400, CBAUD }, #endif #ifdef B230400 { "b230400", B230400, CBAUD }, #endif #ifdef B460800 { "b460800", B460800, CBAUD }, #endif { "exta", EXTA, CBAUD }, { "extb", EXTB, CBAUD }, { "cs5", CS5, CSIZE }, { "cs6", CS6, CSIZE }, { "cs7", CS7, CSIZE,(ODDP|PARITY) }, { "cs8", CS8, CSIZE,(SANE|NPARITY) }, { "cstopb", CSTOPB, CSTOPB }, { "cread", CREAD, CREAD, SANE }, { "parenb", PARENB, PARENB,(ODDP|PARITY),(NPARITY) }, { "parodd", PARODD, PARODD, ODDP }, { "hupcl", HUPCL, HUPCL }, { "clocal", CLOCAL, CLOCAL }, /* Various handshaking defines */ #ifdef CTSCD { "ctscd", CTSCD, CTSCD }, #endif #ifdef CRTSCTS { "crtscts", CRTSCTS, CRTSCTS }, #endif #ifdef CRTSFL { "crtsfl", CRTSFL, CRTSFL }, #endif #ifdef RTSFLOW { "rtsflow", RTSFLOW, RTSFLOW }, { "ctsflow", CTSFLOW, CTSFLOW }, #endif #ifdef HDX { "hdx", HDX, HDX }, #endif { NULL } }; /* line discipline */ static struct modeword lflags[] = { { "isig", ISIG, ISIG, SANE }, { "icanon", ICANON, ICANON,(SANE|COOKED), RAW }, { "xcase", XCASE, XCASE, LCASE, NLCASE }, { "echo", ECHO, ECHO, SANE }, { "echoe", ECHOE, ECHOE, SANE }, { "echok", ECHOK, ECHOK, SANE }, { "echonl", ECHONL, ECHONL }, { "echoprt", ECHOPRT, ECHOPRT }, { "noflsh", NOFLSH, NOFLSH }, { NULL } }; #define CINTR 003 /* ^C */ #define CQUIT 034 /* ^\ */ #define CERASE 010 /* ^H */ #define CKILL 025 /* ^U */ #define CEOF 004 /* ^D */ #define CEOL 015 /* ^M */ #define CSUSP 032 /* ^Z */ #define CSTART 021 /* ^Q */ #define CSTOP 023 /* ^S */ #define CRPRNT 022 /* ^R */ #define CFLUSH 017 /* ^O */ #define CWERASE 027 /* ^W */ #define CLNEXT 026 /* ^V */ /* c_cc special characters */ static struct modeword ccchars[] = { {"vintr", VINTR, CINTR}, {"vquit", VQUIT, CQUIT}, {"verase", VERASE, CERASE}, {"vkill", VKILL, CKILL}, {"veof", VEOF, CEOF}, #if defined(VEOL) && defined(TIONCC) && VEOL < TIONCC {"veol", VEOL, CEOL}, #endif #if defined(CEOL2) && defined(VEOL2) && VEOL2 < TIONCC {"veol2", VEOL2, CEOL2}, #endif #if defined(VSUSP) && VSUSP < TIONCC {"vsusp", VSUSP, CSUSP}, #endif #if defined(VSTART) && VSTART < TIONCC {"vstart", VSTART, CSTART}, #endif #if defined(VSTOP) && VSTOP < TIONCC {"vstop", VSTOP, CSTOP}, #endif #if defined(VSWTCH) && VSWTCH < TIONCC {"vswtch", VSWTCH, CSWTCH}, #endif /* SVR4.2 */ #if defined(VDSUSP) && VDSUSP < TIONCC {"vdsusp", VDSUSP, CDSUSP}, #endif #if defined(VREPRINT) && VREPRINT < TIONCC {"vreprint", VREPRINT, CRPRNT}, #endif #if defined(VDISCARD) && VDISCARD < TIONCC {"vdiscard", VDISCARD, CFLUSH}, #endif #if defined(VWERASE) && VWERASE < TIONCC {"vwerase", VWERASE, CWERASE}, #endif #if defined(VLNEXT) && VLNEXT < TIONCC {"vlnext", VLNEXT, CLNEXT}, #endif {"vmin", VMIN, 0}, {"vtime", VTIME, 0}, { NULL } }; struct modeword metatokens[] = { { "sane", SANE }, { "oddp", ODDP }, { "parity", PARITY }, { "evenp", PARITY }, { "-oddp", NPARITY }, { "-parity", NPARITY }, { "-evenp", NPARITY }, { "raw", RAW }, { "-raw", COOKED }, { "cooked", COOKED }, { "nl", NL, NNL }, { "lcase", LCASE, NLCASE }, { "tabs", TABS, NTABS }, { "tab3", NTABS }, { NULL } }; #define GDCHUNK 5 GDE *gdep =(GDE *) NULL; GDE *cur =(GDE *) NULL; static int cntalloc = 0; static struct modeword * findmode(struct modeword *modes, register char *tok) { for ( ; modes->name; modes++) if (strcasecmp(modes->name, tok) == 0) return(modes); return((struct modeword *) NULL); } static void metaset(tcflag_t *tc, struct modeword *modes, int key) { for (; modes->name; modes++) { if (modes->metaon&key) *tc =(*tc & ~ modes->turnoff) | modes->turnon; if (modes->metaoff&key) *tc =(*tc & ~ modes->turnoff); } } static void tio_default_cc(struct termios *t) { t->c_cc[VQUIT] = CQUIT; t->c_cc[VKILL] = CKILL; t->c_cc[VEOF] = CEOF; #if defined(VEOL) && VEOL < TIONCC t->c_cc[VEOL] = CEOL; #endif #if defined(VSTART) && VSTART < TIONCC t->c_cc[VSTART] = CSTART; #endif #if defined(VSTOP) && VSTOP < TIONCC t->c_cc[VSTOP] = CSTOP; #endif #if defined(VSUSP) && VSUSP < TIONCC t->c_cc[VSUSP] = CSUSP; #endif #if defined(VSWTCH) && VSWTCH < TIONCC t->c_cc[VSWTCH] = CSWTCH; #endif /* the following are for SVR4.2 (and higher) */ #if defined(VDSUSP) && VDSUSP < TIONCC t->c_cc[VDSUSP] = CDSUSP; #endif #if defined(VREPRINT) && VREPRINT < TIONCC t->c_cc[VREPRINT] = CRPRNT; #endif #if defined(VDISCARD) && VDISCARD < TIONCC t->c_cc[VDISCARD] = CFLUSH; #endif #if defined(VWERASE) && VWERASE < TIONCC t->c_cc[VWERASE] = CWERASE; #endif #if defined(VLNEXT) && VLNEXT < TIONCC t->c_cc[VLNEXT] = CLNEXT; #endif } static void parsetermio(struct termios *ti, char *str) { register char *p; struct modeword *m; tcflag_t *flag; int metakey; /* initialize c_cc[] array(tio_* doesn't init INTR/ERASE!) */ tio_default_cc(ti); ti->c_cc[VINTR] = CINTR; ti->c_cc[VERASE] = CERASE; ti->c_cc[VMIN] = 1; ti->c_cc[VTIME] = 0; #ifndef POSIX_TERMIOS ti->c_line = 0; #endif for (p = str; *p; p++) if (islower(*p)) *p = toupper(*p); while ((p = strtok(str, " \t")) != NULL ) { int not = 0; str = NULL; metakey = 0; if (strcasecmp(p, "ek") == 0) { ti->c_cc[VERASE] = '#'; ti->c_cc[VKILL] = CKILL; continue; } for (m = metatokens; m->name; m++) if (strcasecmp(p, m->name) == 0) { metakey = m->turnon; break; } if (metakey) { metaset(&ti->c_lflag, lflags, metakey); metaset(&ti->c_oflag, oflags, metakey); metaset(&ti->c_iflag, iflags, metakey); metaset(&ti->c_cflag, cflags, metakey); continue; } if (*p == '-') { not = 1; p++; } if ((m = findmode(lflags, p)) != NULL) flag = &ti->c_lflag; else if ((m = findmode(oflags, p)) != NULL) flag = &ti->c_oflag; else if ((m = findmode(iflags, p)) != NULL) flag = &ti->c_iflag; else if ((m = findmode(cflags, p)) != NULL) flag = &ti->c_cflag; if (m) { if (not) *flag =(*flag & ~ m->turnoff); else *flag =(*flag & ~ m->turnoff) | m->turnon; } else { if ((m = findmode(ccchars, p)) != NULL) { char *p2; if ((p2 = strtok(str, " \t")) == 0) { BAD("parse error", ""); return; /* can't find field */ } if (*p2 == '\\') switch(*(p2+1)) { case 'n': *p2 = '\n'; break; case 'r': *p2 = '\r'; break; case 'b': *p2 = '\010'; break; case 'v': *p2 = '\013'; break; case 'g': *p2 = '\007'; break; case 'f': *p2 = '\f'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { char tbuf[4]; strncpy(tbuf, p2+1, 3); tbuf[3] = '\0'; *p2 = strtol(tbuf,(char **) NULL, 8); break; } default: *p2 = *(p2+1); } else if (*p2 == '^') *p2 = (*(p2+1) == '?') ? 0x7f : (*(p2+1) - '@'); ti->c_cc[m->turnon] = *p2; } else BAD("can't parse <%s>", p); /* else can't parse msg */ } } } static char * stripblanks(register char *s) { register char *p; while (*s && isspace(*s)) s++; p = s; while (*p && !isspace(*p)) p++; *p = '\0'; return(s); } #define GETTYBUFSIZE (10*BUFSIZ) int getentry(char *entry, int elen, FILE *f) { char buf[BUFSIZ*2]; register char *p; entry[0] = '\0'; do { if (!fgets(buf, sizeof(buf), f)) return(0); lineno++; for (p = buf; isspace(*p); p++); } while (*p == '#' || *p == '\n'); p = strchr(buf, '\n'); if (p) *p = '\0'; strcat(entry, buf); while (1) { if (!fgets(buf, sizeof(buf), f)) break; lineno++; p = strchr(buf, '\n'); if (p) *p = '\0'; for (p = buf; isspace(*p); p++); if (!*p) break; strcat(entry, " "); strcat(entry, p); } return(1); } /* * loads all of the entries from the gettydefs file * returns 0 if it fails. */ int loadgettydefs (char *file) { FILE *gd = fopen(file, "r"); char buf[GETTYBUFSIZE]; register char *p; char *tag, *prompt, *nexttag, *before, *after; if (!gd) return 0; while (getentry(buf, sizeof(buf), gd)) { p = buf; if (tag = strtok(p, "#")) { tag = stripblanks(tag); tag = strdup(tag); } else { BAD("no tag field", ""); continue; } if ((before = strtok(NULL, "#")) == 0) { BAD("no before field", ""); continue; } if ((after = strtok(NULL, "#")) == 0) { BAD("no after field", ""); continue; } if ((prompt = strtok(NULL, "#")) == 0) { BAD("no prompt field", ""); continue; } /* do NOT escape prompt here - it may contain \D and \T, and * for that, the real time at login should be used */ prompt = strdup(prompt); if ((nexttag = strtok(NULL, "#")) == 0) continue; if (p = strchr(nexttag, '\n')) *p = '\0'; nexttag = stripblanks(nexttag); nexttag = strdup(nexttag); #ifdef NEVER printf("tag: %s\nbefore: %s\nafter: %s\nprompt: %s\nnexttag: %s\n\n", tag, before, after, prompt, nexttag); #endif if (cur - gdep >= cntalloc-2) { GDE *sav; sav = gdep; if (!gdep) { gdep =(GDE *) malloc(sizeof(GDE) * GDCHUNK); cur = gdep; } else { gdep =(GDE *) realloc(gdep, sizeof(GDE) *(GDCHUNK + cntalloc)); cur = gdep +(cur - sav); } cntalloc += GDCHUNK; } memset(cur, sizeof *cur, 0); cur->tag = tag; cur->prompt = prompt; cur->nexttag = nexttag; parsetermio(&cur->before, before); parsetermio(&cur->after, after); cur++; cur->tag =(char *) NULL; } /* check and make sure that all the next tags are legitimate */ if (gettycheck) { GDE *p; lineno=0; for (cur = gdep; cur->tag; cur++) { for (p=gdep; p->tag; p++) if (strcmp(p->tag, cur->nexttag) == 0) break; if (!p->tag) BAD("unmatched next tag for %s", cur->tag); } } fclose(gd); return 1; } GDE * getgettydef(register char *s) { for (cur = gdep; cur && cur->tag; cur++) if (strcasecmp(cur->tag, s) == 0) return(cur); return((GDE *) NULL); } void dumpflag(char *type, struct modeword *modes, int flag) { printf("%s: %08lo", type,(unsigned long) flag); for (; modes->name; modes++) if ((flag&modes->turnoff) == modes->turnon) printf(" %s", modes->name); putchar('\n'); } void dump(struct termios *ti, char *s) { register int i; register struct modeword *modes; printf("%s:", s); dumpflag("\tiflags", iflags, ti->c_iflag); dumpflag("\toflags", oflags, ti->c_oflag); dumpflag("\tcflags", cflags, ti->c_cflag); dumpflag("\tlflags", lflags, ti->c_lflag); printf("\tc_cc:\t"); for (i = 0; i < TIONCC; i++) { if (i%6 == 5) printf("\n\t\t"); for (modes = ccchars; modes->name; modes++) if (modes->turnon == i) { printf("%s(", modes->name); break; } if (!modes->name) /* skip unallocated ones */ continue; /* Yeah, I know. But who's ever heard of getty on a EBCDIC system ;-) */ if (ti->c_cc[i] < ' ') printf("^%c", ti->c_cc[i] + '@'); else if (ti->c_cc[i] ==(0xff & _POSIX_VDISABLE)) printf("disabled"); else if (ti->c_cc[i] == 0x7f) printf("^?"); else if (ti->c_cc[i] > 0x7f) printf("\\%03o", 0xff&ti->c_cc[i]); else putchar(ti->c_cc[i]); printf(") "); } printf("\n\n"); } void spew(GDE *gd) { printf("tag: `%s'\nprompt: `%s'\nnexttag: `%s'\n", gd->tag, gd->prompt, gd->nexttag); dump(&gd->before, "before"); dump(&gd->after, "after"); putchar('\n'); } void dumpgettydefs(char *file) { if ( !loadgettydefs(file) ) { printf("Couldn't read %s\n", file); exit(1); } printf("loaded entries:\n"); for (cur = gdep; cur->tag; cur++) spew(cur); }