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