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