xref: /netbsd/libexec/getty/subr.c (revision bf9ec67e)
1 /*	$NetBSD: subr.c,v 1.25 2001/11/10 17:35:54 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)subr.c	8.1 (Berkeley) 6/4/93";
40 #else
41 __RCSID("$NetBSD: subr.c,v 1.25 2001/11/10 17:35:54 thorpej Exp $");
42 #endif
43 #endif /* not lint */
44 
45 /*
46  * Melbourne getty.
47  */
48 #define COMPAT_43
49 #include <sys/param.h>
50 #include <sys/ioctl.h>
51 
52 #include <stdlib.h>
53 #include <string.h>
54 #include <termios.h>
55 #include <unistd.h>
56 
57 #include "extern.h"
58 #include "gettytab.h"
59 #include "pathnames.h"
60 
61 extern	struct termios tmode, omode;
62 
63 static void	compatflags(long);
64 
65 /*
66  * Get a table entry.
67  */
68 void
69 gettable(char *name, char *buf)
70 {
71 	struct gettystrs *sp;
72 	struct gettynums *np;
73 	struct gettyflags *fp;
74 	long n;
75 	char *dba[2];
76 	dba[0] = _PATH_GETTYTAB;
77 	dba[1] = 0;
78 
79 	if (cgetent(&buf, dba, name) != 0)
80 		return;
81 
82 	for (sp = gettystrs; sp->field; sp++)
83 		cgetstr(buf, sp->field, &sp->value);
84 	for (np = gettynums; np->field; np++) {
85 		if (cgetnum(buf, np->field, &n) == -1)
86 			np->set = 0;
87 		else {
88 			np->set = 1;
89 			np->value = n;
90 		}
91 	}
92 	for (fp = gettyflags; fp->field; fp++) {
93 		if (cgetcap(buf, fp->field, ':') == NULL)
94 			fp->set = 0;
95 		else {
96 			fp->set = 1;
97 			fp->value = 1 ^ fp->invrt;
98 		}
99 	}
100 #ifdef DEBUG
101 	printf("name=\"%s\", buf=\"%s\"\n", name, buf);
102 	for (sp = gettystrs; sp->field; sp++)
103 		printf("cgetstr: %s=%s\n", sp->field, sp->value);
104 	for (np = gettynums; np->field; np++)
105 		printf("cgetnum: %s=%d\n", np->field, np->value);
106 	for (fp = gettyflags; fp->field; fp++)
107 		printf("cgetflags: %s='%c' set='%c'\n", fp->field,
108 		       fp->value + '0', fp->set + '0');
109 	exit(1);
110 #endif /* DEBUG */
111 }
112 
113 void
114 gendefaults(void)
115 {
116 	struct gettystrs *sp;
117 	struct gettynums *np;
118 	struct gettyflags *fp;
119 
120 	for (sp = gettystrs; sp->field; sp++)
121 		if (sp->value)
122 			sp->defalt = sp->value;
123 	for (np = gettynums; np->field; np++)
124 		if (np->set)
125 			np->defalt = np->value;
126 	for (fp = gettyflags; fp->field; fp++)
127 		if (fp->set)
128 			fp->defalt = fp->value;
129 		else
130 			fp->defalt = fp->invrt;
131 }
132 
133 void
134 setdefaults(void)
135 {
136 	struct gettystrs *sp;
137 	struct gettynums *np;
138 	struct gettyflags *fp;
139 
140 	for (sp = gettystrs; sp->field; sp++)
141 		if (!sp->value)
142 			sp->value = sp->defalt;
143 	for (np = gettynums; np->field; np++)
144 		if (!np->set)
145 			np->value = np->defalt;
146 	for (fp = gettyflags; fp->field; fp++)
147 		if (!fp->set)
148 			fp->value = fp->defalt;
149 }
150 
151 static char **
152 charnames[] = {
153 	&ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
154 	&SU, &DS, &RP, &FL, &WE, &LN, 0
155 };
156 
157 static char *
158 charvars[] = {
159 	&tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
160 	&tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
161 	&tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
162 	&tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
163 	&tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
164 };
165 
166 void
167 setchars(void)
168 {
169 	int i;
170 	char *p;
171 
172 	for (i = 0; charnames[i]; i++) {
173 		p = *charnames[i];
174 		if (p && *p)
175 			*charvars[i] = *p;
176 		else
177 			*charvars[i] = _POSIX_VDISABLE;
178 	}
179 }
180 
181 /* Macros to clear/set/test flags. */
182 #define	SET(t, f)	(t) |= (f)
183 #define	CLR(t, f)	(t) &= ~(f)
184 #define	ISSET(t, f)	((t) & (f))
185 
186 void
187 setflags(int n)
188 {
189 	tcflag_t iflag, oflag, cflag, lflag;
190 
191 #ifdef COMPAT_43
192 	switch (n) {
193 	case 0:
194 		if (F0set) {
195 			compatflags(F0);
196 			return;
197 		}
198 		break;
199 	case 1:
200 		if (F1set) {
201 			compatflags(F1);
202 			return;
203 		}
204 		break;
205 	default:
206 		if (F2set) {
207 			compatflags(F2);
208 			return;
209 		}
210 		break;
211 	}
212 #endif
213 
214 	switch (n) {
215 	case 0:
216 		if (C0set && I0set && L0set && O0set) {
217 			tmode.c_cflag = C0;
218 			tmode.c_iflag = I0;
219 			tmode.c_lflag = L0;
220 			tmode.c_oflag = O0;
221 			return;
222 		}
223 		break;
224 	case 1:
225 		if (C1set && I1set && L1set && O1set) {
226 			tmode.c_cflag = C1;
227 			tmode.c_iflag = I1;
228 			tmode.c_lflag = L1;
229 			tmode.c_oflag = O1;
230 			return;
231 		}
232 		break;
233 	default:
234 		if (C2set && I2set && L2set && O2set) {
235 			tmode.c_cflag = C2;
236 			tmode.c_iflag = I2;
237 			tmode.c_lflag = L2;
238 			tmode.c_oflag = O2;
239 			return;
240 		}
241 		break;
242 	}
243 
244 	iflag = omode.c_iflag;
245 	oflag = omode.c_oflag;
246 	cflag = omode.c_cflag;
247 	lflag = omode.c_lflag;
248 
249 	if (NP) {
250 		CLR(cflag, CSIZE|PARENB);
251 		SET(cflag, CS8);
252 		CLR(iflag, ISTRIP|INPCK|IGNPAR);
253 	} else if (AP || EP || OP) {
254 		CLR(cflag, CSIZE);
255 		SET(cflag, CS7|PARENB);
256 		SET(iflag, ISTRIP);
257 		if (OP && !EP) {
258 			SET(iflag, INPCK|IGNPAR);
259 			SET(cflag, PARODD);
260 			if (AP)
261 				CLR(iflag, INPCK);
262 		} else if (EP && !OP) {
263 			SET(iflag, INPCK|IGNPAR);
264 			CLR(cflag, PARODD);
265 			if (AP)
266 				CLR(iflag, INPCK);
267 		} else if (AP || (EP && OP)) {
268 			CLR(iflag, INPCK|IGNPAR);
269 			CLR(cflag, PARODD);
270 		}
271 	} /* else, leave as is */
272 
273 #if 0
274 	if (UC)
275 		f |= LCASE;
276 #endif
277 
278 	if (HC)
279 		SET(cflag, HUPCL);
280 	else
281 		CLR(cflag, HUPCL);
282 
283 	if (MB)
284 		SET(cflag, MDMBUF);
285 	else
286 		CLR(cflag, MDMBUF);
287 
288 	if (NL) {
289 		SET(iflag, ICRNL);
290 		SET(oflag, ONLCR|OPOST);
291 	} else {
292 		CLR(iflag, ICRNL);
293 		CLR(oflag, ONLCR);
294 	}
295 
296 	if (!HT)
297 		SET(oflag, OXTABS|OPOST);
298 	else
299 		CLR(oflag, OXTABS);
300 
301 #ifdef XXX_DELAY
302 	SET(f, delaybits());
303 #endif
304 
305 	if (n == 1) {		/* read mode flags */
306 		if (RW) {
307 			iflag = 0;
308 			CLR(oflag, OPOST);
309 			CLR(cflag, CSIZE|PARENB);
310 			SET(cflag, CS8);
311 			lflag = 0;
312 		} else {
313 			CLR(lflag, ICANON);
314 		}
315 		goto out;
316 	}
317 
318 	if (n == 0)
319 		goto out;
320 
321 #if 0
322 	if (CB)
323 		SET(f, CRTBS);
324 #endif
325 
326 	if (CE)
327 		SET(lflag, ECHOE);
328 	else
329 		CLR(lflag, ECHOE);
330 
331 	if (CK)
332 		SET(lflag, ECHOKE);
333 	else
334 		CLR(lflag, ECHOKE);
335 
336 	if (PE)
337 		SET(lflag, ECHOPRT);
338 	else
339 		CLR(lflag, ECHOPRT);
340 
341 	if (EC)
342 		SET(lflag, ECHO);
343 	else
344 		CLR(lflag, ECHO);
345 
346 	if (XC)
347 		SET(lflag, ECHOCTL);
348 	else
349 		CLR(lflag, ECHOCTL);
350 
351 	if (DX)
352 		SET(lflag, IXANY);
353 	else
354 		CLR(lflag, IXANY);
355 
356 out:
357 	tmode.c_iflag = iflag;
358 	tmode.c_oflag = oflag;
359 	tmode.c_cflag = cflag;
360 	tmode.c_lflag = lflag;
361 }
362 
363 #ifdef COMPAT_43
364 /*
365  * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
366  */
367 void
368 compatflags(long flags)
369 {
370 	tcflag_t iflag, oflag, cflag, lflag;
371 
372 	iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY;
373 	oflag = OPOST|ONLCR|OXTABS;
374 	cflag = CREAD;
375 	lflag = ICANON|ISIG|IEXTEN;
376 
377 	if (ISSET(flags, TANDEM))
378 		SET(iflag, IXOFF);
379 	else
380 		CLR(iflag, IXOFF);
381 	if (ISSET(flags, ECHO))
382 		SET(lflag, ECHO);
383 	else
384 		CLR(lflag, ECHO);
385 	if (ISSET(flags, CRMOD)) {
386 		SET(iflag, ICRNL);
387 		SET(oflag, ONLCR);
388 	} else {
389 		CLR(iflag, ICRNL);
390 		CLR(oflag, ONLCR);
391 	}
392 	if (ISSET(flags, XTABS))
393 		SET(oflag, OXTABS);
394 	else
395 		CLR(oflag, OXTABS);
396 
397 
398 	if (ISSET(flags, RAW)) {
399 		iflag &= IXOFF;
400 		CLR(lflag, ISIG|ICANON|IEXTEN);
401 		CLR(cflag, PARENB);
402 	} else {
403 		SET(iflag, BRKINT|IXON|IMAXBEL);
404 		SET(lflag, ISIG|IEXTEN);
405 		if (ISSET(flags, CBREAK))
406 			CLR(lflag, ICANON);
407 		else
408 			SET(lflag, ICANON);
409 		switch (ISSET(flags, ANYP)) {
410 		case 0:
411 			CLR(cflag, PARENB);
412 			break;
413 		case ANYP:
414 			SET(cflag, PARENB);
415 			CLR(iflag, INPCK);
416 			break;
417 		case EVENP:
418 			SET(cflag, PARENB);
419 			SET(iflag, INPCK);
420 			CLR(cflag, PARODD);
421 			break;
422 		case ODDP:
423 			SET(cflag, PARENB);
424 			SET(iflag, INPCK);
425 			SET(cflag, PARODD);
426 			break;
427 		}
428 	}
429 
430 	/* Nothing we can do with CRTBS. */
431 	if (ISSET(flags, PRTERA))
432 		SET(lflag, ECHOPRT);
433 	else
434 		CLR(lflag, ECHOPRT);
435 	if (ISSET(flags, CRTERA))
436 		SET(lflag, ECHOE);
437 	else
438 		CLR(lflag, ECHOE);
439 	/* Nothing we can do with TILDE. */
440 	if (ISSET(flags, MDMBUF))
441 		SET(cflag, MDMBUF);
442 	else
443 		CLR(cflag, MDMBUF);
444 	if (ISSET(flags, NOHANG))
445 		CLR(cflag, HUPCL);
446 	else
447 		SET(cflag, HUPCL);
448 	if (ISSET(flags, CRTKIL))
449 		SET(lflag, ECHOKE);
450 	else
451 		CLR(lflag, ECHOKE);
452 	if (ISSET(flags, CTLECH))
453 		SET(lflag, ECHOCTL);
454 	else
455 		CLR(lflag, ECHOCTL);
456 	if (!ISSET(flags, DECCTQ))
457 		SET(iflag, IXANY);
458 	else
459 		CLR(iflag, IXANY);
460 	CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
461 	SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
462 
463 	if (ISSET(flags, RAW|LITOUT|PASS8)) {
464 		CLR(cflag, CSIZE);
465 		SET(cflag, CS8);
466 		if (!ISSET(flags, RAW|PASS8))
467 			SET(iflag, ISTRIP);
468 		else
469 			CLR(iflag, ISTRIP);
470 		if (!ISSET(flags, RAW|LITOUT))
471 			SET(oflag, OPOST);
472 		else
473 			CLR(oflag, OPOST);
474 	} else {
475 		CLR(cflag, CSIZE);
476 		SET(cflag, CS7);
477 		SET(iflag, ISTRIP);
478 		SET(oflag, OPOST);
479 	}
480 
481 	tmode.c_iflag = iflag;
482 	tmode.c_oflag = oflag;
483 	tmode.c_cflag = cflag;
484 	tmode.c_lflag = lflag;
485 }
486 #endif
487 
488 #ifdef XXX_DELAY
489 struct delayval {
490 	unsigned	delay;		/* delay in ms */
491 	int		bits;
492 };
493 
494 /*
495  * below are random guesses, I can't be bothered checking
496  */
497 
498 struct delayval	crdelay[] = {
499 	{ 1,		CR1 },
500 	{ 2,		CR2 },
501 	{ 3,		CR3 },
502 	{ 83,		CR1 },
503 	{ 166,		CR2 },
504 	{ 0,		CR3 },
505 };
506 
507 struct delayval nldelay[] = {
508 	{ 1,		NL1 },		/* special, calculated */
509 	{ 2,		NL2 },
510 	{ 3,		NL3 },
511 	{ 100,		NL2 },
512 	{ 0,		NL3 },
513 };
514 
515 struct delayval	bsdelay[] = {
516 	{ 1,		BS1 },
517 	{ 0,		0 },
518 };
519 
520 struct delayval	ffdelay[] = {
521 	{ 1,		FF1 },
522 	{ 1750,		FF1 },
523 	{ 0,		FF1 },
524 };
525 
526 struct delayval	tbdelay[] = {
527 	{ 1,		 TAB1 },
528 	{ 2,		 TAB2 },
529 	{ 3,		XTABS },	/* this is expand tabs */
530 	{ 100,		 TAB1 },
531 	{ 0,		 TAB2 },
532 };
533 
534 int
535 delaybits(void)
536 {
537 	int f;
538 
539 	f  = adelay(CD, crdelay);
540 	f |= adelay(ND, nldelay);
541 	f |= adelay(FD, ffdelay);
542 	f |= adelay(TD, tbdelay);
543 	f |= adelay(BD, bsdelay);
544 	return (f);
545 }
546 
547 int
548 adelay(int ms, struct delayval *dp)
549 {
550 	if (ms == 0)
551 		return (0);
552 	while (dp->delay && ms > dp->delay)
553 		dp++;
554 	return (dp->bits);
555 }
556 #endif
557 
558 char	editedhost[MAXHOSTNAMELEN];
559 
560 void
561 edithost(char *pat)
562 {
563 	char *host = HN;
564 	char *res = editedhost;
565 
566 	if (!pat)
567 		pat = "";
568 	while (*pat) {
569 		switch (*pat) {
570 
571 		case '#':
572 			if (*host)
573 				host++;
574 			break;
575 
576 		case '@':
577 			if (*host)
578 				*res++ = *host++;
579 			break;
580 
581 		default:
582 			*res++ = *pat;
583 			break;
584 
585 		}
586 		if (res == &editedhost[sizeof editedhost - 1]) {
587 			*res = '\0';
588 			return;
589 		}
590 		pat++;
591 	}
592 	if (*host)
593 		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
594 	else
595 		*res = '\0';
596 	editedhost[sizeof editedhost - 1] = '\0';
597 }
598 
599 void
600 makeenv(char *env[])
601 {
602 	static char termbuf[128] = "TERM=";
603 	char *p, *q;
604 	char **ep;
605 
606 	ep = env;
607 	if (TT && *TT) {
608 		strlcat(termbuf, TT, sizeof(termbuf));
609 		*ep++ = termbuf;
610 	}
611 	if ((p = EV) != NULL) {
612 		q = p;
613 		while ((q = strchr(q, ',')) != NULL) {
614 			*q++ = '\0';
615 			*ep++ = p;
616 			p = q;
617 		}
618 		if (*p)
619 			*ep++ = p;
620 	}
621 	*ep = (char *)0;
622 }
623 
624 /*
625  * This speed select mechanism is written for the Develcon DATASWITCH.
626  * The Develcon sends a string of the form "B{speed}\n" at a predefined
627  * baud rate. This string indicates the user's actual speed.
628  * The routine below returns the terminal type mapped from derived speed.
629  */
630 struct	portselect {
631 	char	*ps_baud;
632 	char	*ps_type;
633 } portspeeds[] = {
634 	{ "B110",	"std.110" },
635 	{ "B134",	"std.134" },
636 	{ "B150",	"std.150" },
637 	{ "B300",	"std.300" },
638 	{ "B600",	"std.600" },
639 	{ "B1200",	"std.1200" },
640 	{ "B2400",	"std.2400" },
641 	{ "B4800",	"std.4800" },
642 	{ "B9600",	"std.9600" },
643 	{ "B19200",	"std.19200" },
644 	{ 0 }
645 };
646 
647 char *
648 portselector(void)
649 {
650 	char c, baud[20], *type = "default";
651 	struct portselect *ps;
652 	int len;
653 
654 	alarm(5*60);
655 	for (len = 0; len < sizeof (baud) - 1; len++) {
656 		if (read(STDIN_FILENO, &c, 1) <= 0)
657 			break;
658 		c &= 0177;
659 		if (c == '\n' || c == '\r')
660 			break;
661 		if (c == 'B')
662 			len = 0;	/* in case of leading garbage */
663 		baud[len] = c;
664 	}
665 	baud[len] = '\0';
666 	for (ps = portspeeds; ps->ps_baud; ps++)
667 		if (strcmp(ps->ps_baud, baud) == 0) {
668 			type = ps->ps_type;
669 			break;
670 		}
671 	sleep(2);	/* wait for connection to complete */
672 	return (type);
673 }
674 
675 /*
676  * This auto-baud speed select mechanism is written for the Micom 600
677  * portselector. Selection is done by looking at how the character '\r'
678  * is garbled at the different speeds.
679  */
680 #include <sys/time.h>
681 
682 char *
683 autobaud(void)
684 {
685 	int rfds;
686 	struct timeval timeout;
687 	char c, *type = "9600-baud";
688 
689 	(void)tcflush(0, TCIOFLUSH);
690 	rfds = 1 << 0;
691 	timeout.tv_sec = 5;
692 	timeout.tv_usec = 0;
693 	if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
694 	    (fd_set *)NULL, &timeout) <= 0)
695 		return (type);
696 	if (read(STDIN_FILENO, &c, 1) != 1)
697 		return (type);
698 	timeout.tv_sec = 0;
699 	timeout.tv_usec = 20;
700 	(void) select(32, (fd_set *)NULL, (fd_set *)NULL,
701 	    (fd_set *)NULL, &timeout);
702 	(void)tcflush(0, TCIOFLUSH);
703 	switch (c & 0377) {
704 
705 	case 0200:		/* 300-baud */
706 		type = "300-baud";
707 		break;
708 
709 	case 0346:		/* 1200-baud */
710 		type = "1200-baud";
711 		break;
712 
713 	case  015:		/* 2400-baud */
714 	case 0215:
715 		type = "2400-baud";
716 		break;
717 
718 	default:		/* 4800-baud */
719 		type = "4800-baud";
720 		break;
721 
722 	case 0377:		/* 9600-baud */
723 		type = "9600-baud";
724 		break;
725 	}
726 	return (type);
727 }
728