1 #ident "$Id: gettydefs.c,v 4.1 1997/01/12 14:53:39 gert Exp $ Copyright (c) 1993 Gert Doering/Chris Lewis"
2 
3 /* gettydefs.c
4  *
5  * Read /etc/gettydefs file, and permit retrieval of individual entries.
6  *
7  * Code in this module by Chris Lewis
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include "syslibs.h"
16 
17 #include "mgetty.h"
18 #include "policy.h"
19 
20 boolean verbose;
21 
22 char * mydup _P1 ((s), register char *s)
23 {
24     register char *p = (char *) malloc(strlen(s) + 1);
25     if (!p) {
26 	lprintf(L_ERROR, "mydup can't malloc");
27 	exit(1);
28     }
29     strcpy(p, s);
30     return(p);
31 }
32 #ifdef USE_GETTYDEFS
33 
34 static char gettydefs_ID[] = "@(#)gettydefs.c compiled with USE_GETTYDEFS";
35 
36 #include "tio.h"
37 
38 struct modeword {
39     char *name;
40     tioflag_t turnon;
41     tioflag_t turnoff;
42     unsigned short metaon;
43     unsigned short metaoff;
44 };
45 
46 /*	Meta tokens */
47 #define SANE	0x0001
48 #define	ODDP	0x0002
49 
50 #define	PARITY	0x0004
51 #define	NPARITY	0x0008
52 
53 #define RAW	0x0010
54 #define	COOKED	0x0020
55 
56 #define NL	0x0040
57 #define NNL	0x0080
58 
59 #define LCASE	0x0100
60 #define NLCASE	0x0200
61 
62 #define TABS	0x0400
63 #define	NTABS	0x0800
64 
65 /* input modes */
66 
67 static struct modeword iflags[] = {
68     { "IGNBRK", IGNBRK, IGNBRK },
69     { "BRKINT", BRKINT, BRKINT, SANE },
70     { "IGNPAR", IGNPAR, IGNPAR, SANE },
71     { "PARMRK", PARMRK, PARMRK },
72     { "INPCK", INPCK, INPCK },
73     { "ISTRIP", ISTRIP, ISTRIP, SANE },
74     { "INLCR", INLCR, INLCR, 0, NNL },
75     { "IGNCR", IGNCR, IGNCR, 0, NNL },
76     { "ICRNL", ICRNL, ICRNL, (SANE|NL), NNL },
77     { "IUCLC", IUCLC, IUCLC, LCASE, NLCASE },
78     { "IXON", IXON, IXON, SANE },
79     { "IXANY", IXANY, IXANY },
80     { "IXOFF", IXOFF, IXOFF },
81     { NULL }
82 };
83 
84 /* output modes */
85 
86 static struct modeword oflags[] = {
87     { "OPOST", OPOST, OPOST, (SANE|COOKED), RAW },
88     { "OLCUC", OLCUC, OLCUC, LCASE, NLCASE },
89     { "ONLCR", ONLCR, ONLCR, NL, NNL },
90     { "OCRNL", OCRNL, OCRNL, 0, NNL },
91     { "ONOCR", ONOCR, ONOCR },
92     { "ONLRET", ONLRET, ONLRET, NNL },
93     { "OFILL", OFILL, OFILL },
94     { "OFDEL", OFDEL, OFDEL },
95     { "NLDLY", NLDLY, NLDLY },
96     { "NL0", NL0, NLDLY },
97     { "NL1", NL1, NLDLY },
98     { "CR0", CR0, CRDLY },
99     { "CR1", CR1, CRDLY },
100     { "CR2", CR2, CRDLY },
101     { "CR3", CR3, CRDLY },
102     { "TAB0", TAB0, TABDLY, TABS },
103     { "TAB1", TAB1, TABDLY },
104     { "TAB2", TAB2, TABDLY },
105     { "TAB3", TAB3, TABDLY, NTABS },
106     { "BS0", BS0, BSDLY },
107     { "BS1", BS1, BSDLY },
108     { "VT0", VT0, VTDLY },
109     { "VT1", VT1, VTDLY },
110     { "FF0", FF0, FFDLY },
111     { "FF1", FF1, FFDLY },
112     { NULL }
113 };
114 
115 /* control modes */
116 
117 static struct modeword cflags[] = {
118     { "B0", B0, CBAUD },
119     { "B50", B50, CBAUD },
120     { "B75", B75, CBAUD },
121     { "B110", B110, CBAUD },
122     { "B134", B134, CBAUD },
123     { "B150", B150, CBAUD },
124     { "B200", B200, CBAUD },
125     { "B300", B300, CBAUD },
126     { "B600", B600, CBAUD },
127 #ifdef B900
128     { "B900", B900, CBAUD },
129 #endif
130     { "B1200", B1200, CBAUD },
131     { "B1800", B1800, CBAUD },
132     { "B2400", B2400, CBAUD },
133 #ifdef B3600
134     { "B3600", B3600, CBAUD },
135 #endif
136     { "B4800", B4800, CBAUD },
137 #ifdef B7200
138     { "B7200", B7200, CBAUD },
139 #endif
140     { "B9600", B9600, CBAUD },
141 #ifdef B19200
142     { "B19200", B19200, CBAUD },
143 #endif
144 #ifdef B38400
145     { "B38400", B38400, CBAUD },
146 #endif
147 #ifdef B57600
148     { "B57600", B57600, CBAUD },
149 #endif
150 #ifdef B76800
151     { "B76800", B76800, CBAUD },
152 #endif
153 #ifdef B115200
154     { "B115200", B115200, CBAUD },
155 #endif
156 #ifdef B230400
157     { "B230400", B230400, CBAUD },
158 #endif
159 #ifdef B230400
160     { "B230400", B230400, CBAUD },
161 #endif
162 #ifdef B460800
163     { "B460800", B460800, CBAUD },
164 #endif
165     { "EXTA", EXTA, CBAUD },
166     { "EXTB", EXTB, CBAUD },
167     { "CS5", CS5, CSIZE },
168     { "CS6", CS6, CSIZE },
169     { "CS7", CS7, CSIZE, (ODDP|PARITY) },
170     { "CS8", CS8, CSIZE, (SANE|NPARITY) },
171     { "CSTOPB", CSTOPB, CSTOPB },
172     { "CREAD", CREAD, CREAD, SANE },
173     { "PARENB", PARENB, PARENB, (ODDP|PARITY), (NPARITY) },
174     { "PARODD", PARODD, PARODD, ODDP },
175     { "HUPCL", HUPCL, HUPCL },
176     { "CLOCAL", CLOCAL, CLOCAL },
177 /* Various handshaking defines */
178 #ifdef CTSCD
179     { "CTSCD", CTSCD, CTSCD },
180 #endif
181 #ifdef CRTSCTS
182     { "CRTSCTS", CRTSCTS, CRTSCTS },
183 #endif
184 #ifdef CRTSFL
185     { "CRTSFL", CRTSFL, CRTSFL },
186 #endif
187 #ifdef RTSFLOW
188     { "RTSFLOW", RTSFLOW, RTSFLOW },
189     { "CTSFLOW", CTSFLOW, CTSFLOW },
190 #endif
191 #ifdef HDX
192     { "HDX", HDX, HDX },
193 #endif
194     { NULL }
195 };
196 
197 /* line discipline */
198 static struct modeword lflags[] =  {
199     { "ISIG", ISIG, ISIG, SANE },
200     { "ICANON", ICANON, ICANON, (SANE|COOKED), RAW },
201     { "XCASE", XCASE, XCASE, LCASE, NLCASE },
202     { "ECHO", ECHO, ECHO, SANE },
203     { "ECHOE", ECHOE, ECHOE },
204     { "ECHOK", ECHOK, ECHOK, SANE },
205     { "ECHONL", ECHONL, ECHONL },
206     { "NOFLSH", NOFLSH, NOFLSH },
207     { NULL }
208 };
209 
210 /* c_cc special characters */
211 static struct modeword ccchars[] = {
212     {"VINTR", VINTR, CINTR},
213     {"VQUIT", VQUIT, CQUIT},
214     {"VERASE", VERASE, CERASE},
215     {"VKILL", VKILL, CKILL},
216     {"VEOF", VEOF, CEOF},
217 #if defined(VEOL) && VEOL < TIONCC
218     {"VEOL", VEOL, CEOL},
219 #endif
220 #if defined(CEOL2) && defined(VEOL2) && VEOL2 < TIONCC
221     {"VEOL2", VEOL2, CEOL2},
222 #endif
223 #if defined(VSUSP) && VSUSP < TIONCC
224     {"VSUSP", VSUSP, CSUSP},
225 #endif
226 #if defined(VSTART) && VSTART < TIONCC
227     {"VSTART", VSTART, CSTART},
228 #endif
229 #if defined(VSTOP) && VSTOP < TIONCC
230     {"VSTOP", VSTOP, CSTOP},
231 #endif
232 #if defined(VSWTCH) && VSWTCH < TIONCC
233     {"VSWTCH", VSWTCH, CSWTCH},
234 #endif
235 /* SVR4.2 */
236 #if defined(VDSUSP) && VDSUSP < TIONCC
237    {"VDSUSP", VDSUSP, CDSUSP},
238 #endif
239 #if defined(VREPRINT) && VREPRINT < TIONCC
240    {"VREPRINT", VREPRINT, CRPRNT},
241 #endif
242 #if defined(VDISCARD) && VDISCARD < TIONCC
243    {"VDISCARD", VDISCARD, CFLUSH},
244 #endif
245 #if defined(VWERASE) && VWERASE < TIONCC
246    {"VWERASE", VWERASE, CWERASE},
247 #endif
248 #if defined(VLNEXT) && VLNEXT < TIONCC
249    {"VLNEXT", VLNEXT, CLNEXT},
250 #endif
251     {"VMIN", VMIN, 0},
252     {"VTIME", VTIME, 0},
253     { NULL }
254 };
255 
256 struct modeword metatokens[] = {
257     { "SANE", SANE },
258     { "ODDP", ODDP },
259 
260     { "PARITY", PARITY },
261     { "EVENP", PARITY },
262     { "-ODDP", NPARITY },
263     { "-PARITY", NPARITY },
264     { "-EVENP", NPARITY },
265 
266     { "RAW", RAW },
267     { "-RAW", COOKED },
268     { "COOKED", COOKED },
269 
270     { "NL", NL },
271     { "-NL", NNL },
272 
273     { "LCASE", LCASE },
274     { "-LCASE", NLCASE },
275 
276     { "TABS", TABS },
277     { "-TABS", NTABS },
278     { "TAB3", NTABS },
279 
280     { NULL }
281 };
282 
283 #define GDCHUNK	5
284 
285 GDE *gdep = (GDE *) NULL;
286 GDE *cur = (GDE *) NULL;
287 static int cntalloc = 0;
288 
289 static struct modeword *
290 findmode _P2 ((modes, tok), struct modeword *modes, register char *tok)
291 {
292     for( ; modes->name; modes++)
293 	if (strcmp(modes->name, tok) == 0)
294 	    return(modes);
295     return((struct modeword *) NULL);
296 }
297 
298 static void
299 metaset _P3((tc, modes, key), tioflag_t *tc, struct modeword *modes, int key)
300 {
301     for ( ; modes->name; modes++) {
302 	if (modes->metaon&key)
303 	    *tc = (*tc & ~ modes->turnoff) | modes->turnon;
304 	if (modes->metaoff&key)
305 	    *tc = (*tc & ~ modes->turnoff);
306     }
307 }
308 
309 static void
310 parsetermio _P2((ti, str), TIO *ti, char *str)
311 {
312     register char *p;
313     struct modeword *m;
314     tioflag_t *flag;
315     int metakey;
316 
317     /* initialize c_cc[] array (tio_* doesn't init INTR/ERASE!) */
318     tio_default_cc( ti );
319     ti->c_cc[VINTR] = CINTR;
320     ti->c_cc[VERASE] = CERASE;
321 
322 #ifndef POSIX_TERMIOS
323     ti->c_line = 0;
324 #endif
325 
326     for (p = str; *p; p++)
327 	if (islower(*p))
328 	    *p = toupper(*p);
329 
330     while ( (p = strtok(str, " \t")) != NULL ) {
331 	int not = FALSE;
332 
333 	str = NULL;
334 
335 	metakey = 0;
336 
337 	if (strcmp(p, "EK") == 0) {
338 	    ti->c_cc[VERASE] = '#';
339 	    ti->c_cc[VKILL] = CKILL;
340 	    continue;
341 	}
342 
343 	for (m = metatokens; m->name; m++)
344 	    if (strcmp(p, m->name) == 0) {
345 		metakey = m->turnon;
346 		break;
347 	    }
348 
349 	if (metakey) {
350 	    metaset(&ti->c_lflag, lflags, metakey);
351 	    metaset(&ti->c_oflag, oflags, metakey);
352 	    metaset(&ti->c_iflag, iflags, metakey);
353 	    metaset(&ti->c_cflag, cflags, metakey);
354 	    continue;
355 	}
356 
357 	if (*p == '-') {
358 	    not = TRUE;
359 	    p++;
360 	}
361 
362 	if      ((m = findmode(lflags, p)) != NULL)
363 	    flag = &ti->c_lflag;
364 	else if ((m = findmode(oflags, p)) != NULL)
365 	    flag = &ti->c_oflag;
366 	else if ((m = findmode(iflags, p)) != NULL)
367 	    flag = &ti->c_iflag;
368 	else if ((m = findmode(cflags, p)) != NULL)
369 	    flag = &ti->c_cflag;
370 	if (m) {
371 	    if (not)
372 		*flag = (*flag & ~ m->turnoff);
373 	    else
374 		*flag = (*flag & ~ m->turnoff) | m->turnon;
375 	} else {
376 	    if ((m = findmode(ccchars, p)) != NULL) {
377 		char *p2;
378 		p2 = strtok(str, " \t");
379 		if (!p2) {
380 		    if (verbose)
381 			fprintf(stderr, "No value after %s\n", p);
382 		    return;
383 		}
384 		if (*p2 == '\\')
385 		    switch(*(p2+1)) {
386 			case 'n': *p2 = '\n'; break;
387 			case 'r': *p2 = '\r'; break;
388 			case 'b': *p2 = '\010'; break;
389 			case 'v': *p2 = '\013'; break;
390 			case 'g': *p2 = '\007'; break;
391 			case 'f': *p2 = '\f'; break;
392 			case '0': case '1': case '2': case '3':
393 			case '4': case '5': case '6': case '7': {
394 			    char tbuf[4];
395 			    strncpy(tbuf, p2+1, 3);
396 			    tbuf[3] = '\0';
397 			    *p2 = strtol(tbuf, (char **) NULL, 8);
398 			    break;
399 			}
400 			default:
401 			    *p2 = *(p2+1);
402 		    }
403 		else if (*p2 == '^')		/* ^x means C-x, ^? is DEL */
404 		    *p2 = (*(p2+1) == '?')? 0x7f : *(p2+1) - '@';
405 
406 		ti->c_cc[m->turnon] = *p2;
407 	    } else
408 		if (verbose)
409 		    fprintf(stderr, "Can't parse %s\n", p);
410 	}
411     }
412 
413 }
414 
415 static char *
416 stripblanks _P1 ((s), register char *s)
417 {
418     register char *p;
419     while(*s && isspace(*s)) s++;
420     p = s;
421     while(*p && !isspace(*p)) p++;
422     *p = '\0';
423     return(s);
424 }
425 
426 #define	GETTYBUFSIZE	(10*BUFSIZ)
427 
428 int
429 getentry _P3((entry, elen, f), char *entry, int elen, FILE *f) {
430     char buf[BUFSIZ*2];
431     register char *p;
432 
433     entry[0] = '\0';
434 
435     do {
436 	if (!fgets(buf, sizeof(buf), f))
437 	    return(0);
438 	for (p = buf; isspace(*p); p++);
439     } while(*p == '#' || *p == '\n');
440 
441     p = strchr(buf, '\n');
442     if (p)
443 	*p = '\0';
444     strcat(entry, buf);
445 
446     while (1) {
447 	if (!fgets(buf, sizeof(buf), f))
448 	    break;
449 	p = strchr(buf, '\n');
450 	if (p)
451 	    *p = '\0';
452 	for (p = buf; isspace(*p); p++);
453 	if (!*p)
454 	    break;
455 	strcat(entry, " ");
456 	strcat(entry, p);
457     }
458     return(1);
459 }
460 
461 /*
462  * loads all of the entries from the gettydefs file
463  * returns 0 if it fails.
464  */
465 int
466 loadgettydefs _P1((file), char *file ) {
467     FILE *gd = fopen(file, "r");
468     char buf[GETTYBUFSIZE];
469     register char *p;
470     char *tag, *prompt, *nexttag, *before, *after;
471 
472     if (!gd) {
473 	lprintf(L_WARN, "Can't open %s\n", file);
474 	return(0);
475     }
476 
477     while(getentry(buf, sizeof(buf), gd)) {
478 
479 	p = buf;
480 
481 	tag = strtok(p, "#");
482 	if (!tag)
483 	    continue;
484 	tag = stripblanks(tag);
485 	tag = mydup(tag);
486 
487 	before = strtok(NULL, "#");
488 	if (!before)
489 	    continue;
490 
491 	after = strtok(NULL, "#");
492 	if (!after)
493 	    continue;
494 
495 	prompt = strtok(NULL, "#");
496 	if (!prompt)
497 	    continue;
498 
499 	/* do NOT escape prompt here - it may contain \D and \T, and
500 	 * for that, the real time at login should be used
501 	 */
502 	prompt = mydup(prompt);
503 
504 	nexttag = strtok(NULL, "#");
505 	if (!nexttag)
506 	    continue;
507 
508 	p = strchr(nexttag, '\n');
509 	if (p)
510 	    *p = '\0';
511 
512 	nexttag = stripblanks(nexttag);
513 	nexttag = mydup(nexttag);
514 
515 #ifdef NEVER
516 	printf("tag: %s\nbefore: %s\nafter: %s\nprompt: %s\nnexttag: %s\n\n",
517 	    tag, before, after, prompt, nexttag);
518 #endif
519 
520 	if (cur - gdep >= cntalloc-2) {
521 	    GDE *sav;
522 	    sav = gdep;
523 	    if (!gdep) {
524 		gdep = (GDE *) malloc(sizeof(GDE) * GDCHUNK);
525 		cur = gdep;
526 	    } else {
527 		gdep = (GDE *) realloc(gdep, sizeof(GDE) * (GDCHUNK + cntalloc));
528 		cur = gdep + (cur - sav);
529 	    }
530 	    cntalloc += GDCHUNK;
531 	}
532 
533 	memset(cur, sizeof(*cur), '\0');
534 
535 	cur->tag = tag;
536 	cur->prompt = prompt;
537 	cur->nexttag = nexttag;
538 	parsetermio(&cur->before, before);
539 	parsetermio(&cur->after, after);
540 	if (verbose)
541 	    printf("Processed `%s' gettydefs entry\n", tag);
542 	cur++;
543 	cur->tag = (char *) NULL;
544     }
545     fclose(gd);
546     return(1);
547 }
548 
549 GDE *
550 getgettydef _P1 ((s), register char *s)
551 {
552     for (cur = gdep; cur && cur->tag; cur++)
553 	if (strcmp(cur->tag, s) == 0)
554 	    return(cur);
555     if (gdep && gdep->tag) {
556 	lprintf(L_WARN, "getgettydef(%s) entry not found using %s",
557 	    s, gdep->tag);
558 	return(gdep);
559     }
560     lprintf(L_WARN, "getgettydef(%s) no entry found", s);
561     return((GDE *) NULL);
562 }
563 
564 void
565 dumpflag _P3((type, modes, flag),
566 	     char *type,
567 	     struct modeword *modes, tioflag_t flag)
568 {
569     printf("%s: %08lo", type, (unsigned long) flag);
570     for(; modes->name; modes++)
571 	if ((flag&modes->turnoff) == modes->turnon)
572 	    printf(" %s", modes->name);
573     putchar('\n');
574 }
575 
576 void
577 dump _P2((ti, s), TIO *ti, char *s)
578 {
579     register int i;
580     register struct modeword *modes;
581 
582     printf("%s:", s);
583     dumpflag("\tiflags", iflags, ti->c_iflag);
584     dumpflag("\toflags", oflags, ti->c_oflag);
585     dumpflag("\tcflags", cflags, ti->c_cflag);
586     dumpflag("\tlflags", lflags, ti->c_lflag);
587     printf("\tc_cc:\t");
588     for (i = 0; i < TIONCC; i++) {
589 	if (i == 6)
590 	    printf("\n\t\t");
591 	for (modes = ccchars; modes->name; modes++)
592 	    if (modes->turnon == i) {
593 		printf("%s(", modes->name);
594 		break;
595 	    }
596 	if (!modes->name)	/* skip unallocated ones */
597 	    continue;
598 	/* Yeah, I know.  But who's ever heard of getty on a EBCDIC system ;-) */
599 	if (ti->c_cc[i] < ' ')
600 	    printf("^%c", ti->c_cc[i] + '@');
601 	else if (ti->c_cc[i] == (0xff & _POSIX_VDISABLE))
602 	    printf("disabled");
603 	else if (ti->c_cc[i] >= 0x7f)
604 	    printf("\\%03o", 0xff&ti->c_cc[i]);
605 	else
606 	    putchar(ti->c_cc[i]);
607 	printf(") ");
608     }
609     printf("\n\n");
610 }
611 
612 static void
613 spew _P1 ((gd), GDE *gd)
614 {
615     printf("tag: `%s'\nprompt: `%s'\nnexttag: `%s'\n",
616 	gd->tag, gd->prompt, gd->nexttag);
617     dump(&gd->before, "before");
618     dump(&gd->after, "after");
619     printf("\n");
620 }
621 
622 void
623 dumpgettydefs _P1((file), char *file) {
624     if (! loadgettydefs(file)) {
625 	fprintf(stderr, "Couldn't read %s\n", file);
626 	exit(1);
627     }
628     printf("loaded entries:\n");
629     for (cur = gdep; cur->tag; cur++)
630 	spew(cur);
631 
632 }
633 #endif
634