xref: /netbsd-src/libexec/getty/subr.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
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.14 1994/09/05 09:09:51 pk 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 void
175 setflags(n)
176 	int n;
177 {
178 	register tcflag_t iflag, oflag, cflag, lflag;
179 
180 #ifdef COMPAT_43
181 	switch (n) {
182 	case 0:
183 		if (F0set) {
184 			compatflags(F0);
185 			return;
186 		}
187 		break;
188 	case 1:
189 		if (F1set) {
190 			compatflags(F1);
191 			return;
192 		}
193 		break;
194 	default:
195 		if (F2set) {
196 			compatflags(F2);
197 			return;
198 		}
199 		break;
200 	}
201 #endif
202 
203 	switch (n) {
204 	case 0:
205 		if (C0set && I0set && L0set && O0set) {
206 			tmode.c_cflag = C0;
207 			tmode.c_iflag = I0;
208 			tmode.c_lflag = L0;
209 			tmode.c_oflag = O0;
210 			return;
211 		}
212 		break;
213 	case 1:
214 		if (C1set && I1set && L1set && O1set) {
215 			tmode.c_cflag = C1;
216 			tmode.c_iflag = I1;
217 			tmode.c_lflag = L1;
218 			tmode.c_oflag = O1;
219 			return;
220 		}
221 		break;
222 	default:
223 		if (C2set && I2set && L2set && O2set) {
224 			tmode.c_cflag = C2;
225 			tmode.c_iflag = I2;
226 			tmode.c_lflag = L2;
227 			tmode.c_oflag = O2;
228 			return;
229 		}
230 		break;
231 	}
232 
233 #define BIC(v,c)	(v) &= ~(c)
234 #define BIS(v,s)	(v) |= (s)
235 #define BICS(v,c,s)	BIC(v,c),BIS(v,s)
236 
237 	iflag = omode.c_iflag;
238 	oflag = omode.c_oflag;
239 	cflag = omode.c_cflag;
240 	lflag = omode.c_lflag;
241 
242 	if (NP) {
243 		BIC(iflag, ISTRIP|INPCK|IGNPAR);
244 		BICS(cflag, CSIZE|PARENB|PARODD, CS8);
245 	} else if (OP && !EP) {
246 		BIS(iflag, ISTRIP|INPCK|IGNPAR);
247 		BICS(cflag, CSIZE, PARENB|PARODD|CS7);
248 		if (AP)
249 			BIC(iflag, INPCK);
250 	} else if (EP && !OP) {
251 		BIS(iflag, ISTRIP|INPCK|IGNPAR);
252 		BICS(cflag, CSIZE|PARODD, PARENB|CS7);
253 		if (AP)
254 			BIC(iflag, INPCK);
255 	} else if (AP || EP && OP) {
256 		BICS(iflag, INPCK|IGNPAR, ISTRIP);
257 		BICS(cflag, CSIZE|PARODD, PARENB|CS7);
258 	} /* else, leave as is */
259 
260 #if 0
261 	if (UC)
262 		f |= LCASE;
263 #endif
264 
265 	if (HC)
266 		cflag |= HUPCL;
267 	else
268 		cflag &= ~HUPCL;
269 
270 	if (MB)
271 		cflag |= MDMBUF;
272 	else
273 		cflag &= ~MDMBUF;
274 
275 	if (NL) {
276 		iflag |= ICRNL;
277 		oflag |= ONLCR;
278 	}
279 
280 #ifdef XXX_DELAY
281 	f |= delaybits();
282 #endif
283 
284 	if (n == 1) {		/* read mode flags */
285 		if (RW) {
286 			iflag = 0;
287 			oflag = 0;
288 			BICS(cflag, CSIZE|PARENB|PARODD, CS8);
289 			lflag = 0;
290 		} else {
291 			lflag &= ~ICANON;
292 		}
293 		goto out;
294 	}
295 
296 	if (HT)
297 		oflag &= ~OXTABS;
298 	else
299 		oflag |= OXTABS;
300 
301 	if (n == 0)
302 		goto out;
303 
304 #if 0
305 	if (CB)
306 		f |= CRTBS;
307 #endif
308 
309 	if (CE)
310 		lflag |= ECHOE;
311 
312 	if (CK)
313 		lflag |= ECHOKE;
314 
315 	if (PE)
316 		lflag |= ECHOPRT;
317 
318 	if (EC)
319 		lflag |= ECHO;
320 
321 	if (XC)
322 		lflag |= ECHOCTL;
323 
324 	if (DX)
325 		lflag |= IXANY;
326 
327 out:
328 	tmode.c_iflag = iflag;
329 	tmode.c_oflag = oflag;
330 	tmode.c_cflag = cflag;
331 	tmode.c_lflag = lflag;
332 }
333 
334 #ifdef COMPAT_43
335 /*
336  * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
337  */
338 void
339 compatflags(flags)
340 register long flags;
341 {
342 	register tcflag_t iflag, oflag, cflag, lflag;
343 
344 	iflag = (BRKINT|ICRNL|IMAXBEL|IXON|IXANY);
345 	oflag = (OPOST|ONLCR|OXTABS);
346 	cflag = (CREAD);
347 	lflag = (ICANON|ISIG|IEXTEN);
348 
349 	if (flags & TANDEM)
350 		iflag |= IXOFF;
351 	else
352 		iflag &= ~IXOFF;
353 	if (flags & ECHO)
354 		lflag |= ECHO;
355 	else
356 		lflag &= ~ECHO;
357 	if (flags & CRMOD) {
358 		iflag |= ICRNL;
359 		oflag |= ONLCR;
360 	} else {
361 		iflag &= ~ICRNL;
362 		oflag &= ~ONLCR;
363 	}
364 	if (flags & XTABS)
365 		oflag |= OXTABS;
366 	else
367 		oflag &= ~OXTABS;
368 
369 	if (flags & RAW) {
370 		iflag &= IXOFF;
371 		lflag &= ~(ISIG|ICANON|IEXTEN);
372 	} else {
373 		iflag |= BRKINT|IXON|IMAXBEL;
374 		lflag |= ISIG|IEXTEN;
375 		if (flags & CBREAK)
376 			lflag &= ~ICANON;
377 		else
378 			lflag |= ICANON;
379 	}
380 
381 	switch (flags & ANYP) {
382 	case EVENP:
383 		iflag |= INPCK;
384 		cflag &= ~PARODD;
385 		break;
386 	case ODDP:
387 		iflag |= INPCK;
388 		cflag |= PARODD;
389 		break;
390 	default:
391 		iflag &= ~INPCK;
392 		break;
393 	}
394 
395 	if (flags & (RAW|LITOUT|PASS8)) {
396 		cflag &= ~(CSIZE|PARENB);
397 		cflag |= CS8;
398 		if ((flags & (RAW|PASS8)) == 0)
399 			iflag |= ISTRIP;
400 		else
401 			iflag &= ~ISTRIP;
402 		if ((flags & (RAW|LITOUT)) == 0)
403 			oflag |= OPOST;
404 		else
405 			oflag &= ~OPOST;
406 	} else {
407 		cflag &= ~CSIZE;
408 		cflag |= CS7|PARENB;
409 		iflag |= ISTRIP;
410 		oflag |= OPOST;
411 	}
412 
413 	if (flags & PRTERA)
414 		lflag |= ECHOPRT;
415 	else
416 		lflag &= ~ECHOPRT;
417 	if (flags & CRTERA)
418 		lflag |= ECHOE;
419 	else
420 		lflag &= ~ECHOE;
421 	if (flags & MDMBUF)
422 		cflag |= MDMBUF;
423 	else
424 		cflag &= ~MDMBUF;
425 	if (flags & NOHANG)
426 		cflag &= ~HUPCL;
427 	else
428 		cflag |= HUPCL;
429 	if (flags & CRTKIL)
430 		lflag |= ECHOKE;
431 	else
432 		lflag &= ~ECHOKE;
433 	if (flags & CTLECH)
434 		lflag |= ECHOCTL;
435 	else
436 		lflag &= ~ECHOCTL;
437 	if ((flags & DECCTQ) == 0)
438 		lflag |= IXANY;
439 	else
440 		lflag &= ~IXANY;
441 	lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
442 	lflag |= flags & (TOSTOP|FLUSHO|PENDIN|NOFLSH);
443 
444 	if (flags & (RAW|LITOUT|PASS8)) {
445 		cflag &= ~(CSIZE|PARENB);
446 		cflag |= CS8;
447 		if ((flags & (RAW|PASS8)) == 0)
448 			iflag |= ISTRIP;
449 		else
450 			iflag &= ~ISTRIP;
451 		if ((flags & (RAW|LITOUT)) == 0)
452 			oflag |= OPOST;
453 		else
454 			oflag &= ~OPOST;
455 	} else {
456 		cflag &= ~CSIZE;
457 		cflag |= CS7|PARENB;
458 		iflag |= ISTRIP;
459 		oflag |= OPOST;
460 	}
461 
462 	tmode.c_iflag = iflag;
463 	tmode.c_oflag = oflag;
464 	tmode.c_cflag = cflag;
465 	tmode.c_lflag = lflag;
466 }
467 #endif
468 
469 #ifdef XXX_DELAY
470 struct delayval {
471 	unsigned	delay;		/* delay in ms */
472 	int		bits;
473 };
474 
475 /*
476  * below are random guesses, I can't be bothered checking
477  */
478 
479 struct delayval	crdelay[] = {
480 	{ 1,		CR1 },
481 	{ 2,		CR2 },
482 	{ 3,		CR3 },
483 	{ 83,		CR1 },
484 	{ 166,		CR2 },
485 	{ 0,		CR3 },
486 };
487 
488 struct delayval nldelay[] = {
489 	{ 1,		NL1 },		/* special, calculated */
490 	{ 2,		NL2 },
491 	{ 3,		NL3 },
492 	{ 100,		NL2 },
493 	{ 0,		NL3 },
494 };
495 
496 struct delayval	bsdelay[] = {
497 	{ 1,		BS1 },
498 	{ 0,		0 },
499 };
500 
501 struct delayval	ffdelay[] = {
502 	{ 1,		FF1 },
503 	{ 1750,		FF1 },
504 	{ 0,		FF1 },
505 };
506 
507 struct delayval	tbdelay[] = {
508 	{ 1,		 TAB1 },
509 	{ 2,		 TAB2 },
510 	{ 3,		XTABS },	/* this is expand tabs */
511 	{ 100,		 TAB1 },
512 	{ 0,		 TAB2 },
513 };
514 
515 int
516 delaybits()
517 {
518 	register int f;
519 
520 	f  = adelay(CD, crdelay);
521 	f |= adelay(ND, nldelay);
522 	f |= adelay(FD, ffdelay);
523 	f |= adelay(TD, tbdelay);
524 	f |= adelay(BD, bsdelay);
525 	return (f);
526 }
527 
528 int
529 adelay(ms, dp)
530 	register ms;
531 	register struct delayval *dp;
532 {
533 	if (ms == 0)
534 		return (0);
535 	while (dp->delay && ms > dp->delay)
536 		dp++;
537 	return (dp->bits);
538 }
539 #endif
540 
541 char	editedhost[32];
542 
543 void
544 edithost(pat)
545 	register char *pat;
546 {
547 	register char *host = HN;
548 	register char *res = editedhost;
549 
550 	if (!pat)
551 		pat = "";
552 	while (*pat) {
553 		switch (*pat) {
554 
555 		case '#':
556 			if (*host)
557 				host++;
558 			break;
559 
560 		case '@':
561 			if (*host)
562 				*res++ = *host++;
563 			break;
564 
565 		default:
566 			*res++ = *pat;
567 			break;
568 
569 		}
570 		if (res == &editedhost[sizeof editedhost - 1]) {
571 			*res = '\0';
572 			return;
573 		}
574 		pat++;
575 	}
576 	if (*host)
577 		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
578 	else
579 		*res = '\0';
580 	editedhost[sizeof editedhost - 1] = '\0';
581 }
582 
583 void
584 makeenv(env)
585 	char *env[];
586 {
587 	static char termbuf[128] = "TERM=";
588 	register char *p, *q;
589 	register char **ep;
590 
591 	ep = env;
592 	if (TT && *TT) {
593 		strcat(termbuf, TT);
594 		*ep++ = termbuf;
595 	}
596 	if (p = EV) {
597 		q = p;
598 		while (q = strchr(q, ',')) {
599 			*q++ = '\0';
600 			*ep++ = p;
601 			p = q;
602 		}
603 		if (*p)
604 			*ep++ = p;
605 	}
606 	*ep = (char *)0;
607 }
608 
609 /*
610  * This speed select mechanism is written for the Develcon DATASWITCH.
611  * The Develcon sends a string of the form "B{speed}\n" at a predefined
612  * baud rate. This string indicates the user's actual speed.
613  * The routine below returns the terminal type mapped from derived speed.
614  */
615 struct	portselect {
616 	char	*ps_baud;
617 	char	*ps_type;
618 } portspeeds[] = {
619 	{ "B110",	"std.110" },
620 	{ "B134",	"std.134" },
621 	{ "B150",	"std.150" },
622 	{ "B300",	"std.300" },
623 	{ "B600",	"std.600" },
624 	{ "B1200",	"std.1200" },
625 	{ "B2400",	"std.2400" },
626 	{ "B4800",	"std.4800" },
627 	{ "B9600",	"std.9600" },
628 	{ "B19200",	"std.19200" },
629 	{ 0 }
630 };
631 
632 char *
633 portselector()
634 {
635 	char c, baud[20], *type = "default";
636 	register struct portselect *ps;
637 	int len;
638 
639 	alarm(5*60);
640 	for (len = 0; len < sizeof (baud) - 1; len++) {
641 		if (read(STDIN_FILENO, &c, 1) <= 0)
642 			break;
643 		c &= 0177;
644 		if (c == '\n' || c == '\r')
645 			break;
646 		if (c == 'B')
647 			len = 0;	/* in case of leading garbage */
648 		baud[len] = c;
649 	}
650 	baud[len] = '\0';
651 	for (ps = portspeeds; ps->ps_baud; ps++)
652 		if (strcmp(ps->ps_baud, baud) == 0) {
653 			type = ps->ps_type;
654 			break;
655 		}
656 	sleep(2);	/* wait for connection to complete */
657 	return (type);
658 }
659 
660 /*
661  * This auto-baud speed select mechanism is written for the Micom 600
662  * portselector. Selection is done by looking at how the character '\r'
663  * is garbled at the different speeds.
664  */
665 #include <sys/time.h>
666 
667 char *
668 autobaud()
669 {
670 	int rfds;
671 	struct timeval timeout;
672 	char c, *type = "9600-baud";
673 
674 	(void)tcflush(0, TCIOFLUSH);
675 	rfds = 1 << 0;
676 	timeout.tv_sec = 5;
677 	timeout.tv_usec = 0;
678 	if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
679 	    (fd_set *)NULL, &timeout) <= 0)
680 		return (type);
681 	if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
682 		return (type);
683 	timeout.tv_sec = 0;
684 	timeout.tv_usec = 20;
685 	(void) select(32, (fd_set *)NULL, (fd_set *)NULL,
686 	    (fd_set *)NULL, &timeout);
687 	(void)tcflush(0, TCIOFLUSH);
688 	switch (c & 0377) {
689 
690 	case 0200:		/* 300-baud */
691 		type = "300-baud";
692 		break;
693 
694 	case 0346:		/* 1200-baud */
695 		type = "1200-baud";
696 		break;
697 
698 	case  015:		/* 2400-baud */
699 	case 0215:
700 		type = "2400-baud";
701 		break;
702 
703 	default:		/* 4800-baud */
704 		type = "4800-baud";
705 		break;
706 
707 	case 0377:		/* 9600-baud */
708 		type = "9600-baud";
709 		break;
710 	}
711 	return (type);
712 }
713