subr.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
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. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33#if 0
34static char sccsid[] = "@(#)from: subr.c	8.1 (Berkeley) 6/4/93";
35#endif
36static const char rcsid[] =
37  "$FreeBSD: stable/11/libexec/getty/subr.c 330897 2018-03-14 03:19:51Z eadler $";
38#endif /* not lint */
39
40/*
41 * Melbourne getty.
42 */
43#include <sys/ioctl.h>
44#include <sys/param.h>
45#include <sys/time.h>
46
47#include <poll.h>
48#include <regex.h>
49#include <stdlib.h>
50#include <string.h>
51#include <syslog.h>
52#include <termios.h>
53#include <unistd.h>
54
55#include "gettytab.h"
56#include "pathnames.h"
57#include "extern.h"
58
59/*
60 * Get a table entry.
61 */
62void
63gettable(const char *name, char *buf)
64{
65	struct gettystrs *sp;
66	struct gettynums *np;
67	struct gettyflags *fp;
68	long n;
69	int l;
70	char *p;
71	char *msg = NULL;
72	const char *dba[2];
73
74	static int firsttime = 1;
75
76	dba[0] = _PATH_GETTYTAB;
77	dba[1] = NULL;
78
79	if (firsttime) {
80		/*
81		 * we need to strdup() anything in the strings array
82		 * initially in order to simplify things later
83		 */
84		for (sp = gettystrs; sp->field; sp++)
85			if (sp->value != NULL) {
86				/* handle these ones more carefully */
87				if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
88					l = 2;
89				else
90					l = strlen(sp->value) + 1;
91				if ((p = malloc(l)) != NULL) {
92					strncpy(p, sp->value, l);
93					p[l-1] = '\0';
94				}
95				/*
96				 * replace, even if NULL, else we'll
97				 * have problems with free()ing static mem
98				 */
99				sp->value = p;
100			}
101		firsttime = 0;
102	}
103
104	switch (cgetent(&buf, (char **)dba, (char *)name)) {
105	case 1:
106		msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
107	case 0:
108		break;
109	case -1:
110		msg = "%s: unknown gettytab entry '%s'";
111		break;
112	case -2:
113		msg = "%s: retrieving gettytab entry '%s': %m";
114		break;
115	case -3:
116		msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
117		break;
118	default:
119		msg = "%s: unexpected cgetent() error for entry '%s'";
120		break;
121	}
122
123	if (msg != NULL) {
124		syslog(LOG_ERR, msg, "getty", name);
125		return;
126	}
127
128	for (sp = gettystrs; sp->field; sp++) {
129		if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
130			if (sp->value) {
131				/* prefer existing value */
132				if (strcmp(p, sp->value) != 0)
133					free(sp->value);
134				else {
135					free(p);
136					p = sp->value;
137				}
138			}
139			sp->value = p;
140		} else if (l == -1) {
141			free(sp->value);
142			sp->value = NULL;
143		}
144	}
145
146	for (np = gettynums; np->field; np++) {
147		if (cgetnum(buf, (char*)np->field, &n) == -1)
148			np->set = 0;
149		else {
150			np->set = 1;
151			np->value = n;
152		}
153	}
154
155	for (fp = gettyflags; fp->field; fp++) {
156		if (cgetcap(buf, (char *)fp->field, ':') == NULL)
157			fp->set = 0;
158		else {
159			fp->set = 1;
160			fp->value = 1 ^ fp->invrt;
161		}
162	}
163}
164
165void
166gendefaults(void)
167{
168	struct gettystrs *sp;
169	struct gettynums *np;
170	struct gettyflags *fp;
171
172	for (sp = gettystrs; sp->field; sp++)
173		if (sp->value)
174			sp->defalt = strdup(sp->value);
175	for (np = gettynums; np->field; np++)
176		if (np->set)
177			np->defalt = np->value;
178	for (fp = gettyflags; fp->field; fp++)
179		if (fp->set)
180			fp->defalt = fp->value;
181		else
182			fp->defalt = fp->invrt;
183}
184
185void
186setdefaults(void)
187{
188	struct gettystrs *sp;
189	struct gettynums *np;
190	struct gettyflags *fp;
191
192	for (sp = gettystrs; sp->field; sp++)
193		if (!sp->value)
194			sp->value = !sp->defalt ? sp->defalt
195						: strdup(sp->defalt);
196	for (np = gettynums; np->field; np++)
197		if (!np->set)
198			np->value = np->defalt;
199	for (fp = gettyflags; fp->field; fp++)
200		if (!fp->set)
201			fp->value = fp->defalt;
202}
203
204static char **
205charnames[] = {
206	&ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
207	&SU, &DS, &RP, &FL, &WE, &LN, 0
208};
209
210static char *
211charvars[] = {
212	&tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
213	&tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
214	&tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
215	&tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
216	&tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
217};
218
219void
220setchars(void)
221{
222	int i;
223	const char *p;
224
225	for (i = 0; charnames[i]; i++) {
226		p = *charnames[i];
227		if (p && *p)
228			*charvars[i] = *p;
229		else
230			*charvars[i] = _POSIX_VDISABLE;
231	}
232}
233
234/* Macros to clear/set/test flags. */
235#define	SET(t, f)	(t) |= (f)
236#define	CLR(t, f)	(t) &= ~(f)
237#define	ISSET(t, f)	((t) & (f))
238
239void
240set_flags(int n)
241{
242	tcflag_t iflag, oflag, cflag, lflag;
243
244
245	switch (n) {
246	case 0:
247		if (C0set && I0set && L0set && O0set) {
248			tmode.c_cflag = C0;
249			tmode.c_iflag = I0;
250			tmode.c_lflag = L0;
251			tmode.c_oflag = O0;
252			return;
253		}
254		break;
255	case 1:
256		if (C1set && I1set && L1set && O1set) {
257			tmode.c_cflag = C1;
258			tmode.c_iflag = I1;
259			tmode.c_lflag = L1;
260			tmode.c_oflag = O1;
261			return;
262		}
263		break;
264	default:
265		if (C2set && I2set && L2set && O2set) {
266			tmode.c_cflag = C2;
267			tmode.c_iflag = I2;
268			tmode.c_lflag = L2;
269			tmode.c_oflag = O2;
270			return;
271		}
272		break;
273	}
274
275	iflag = omode.c_iflag;
276	oflag = omode.c_oflag;
277	cflag = omode.c_cflag;
278	lflag = omode.c_lflag;
279
280	if (NP) {
281		CLR(cflag, CSIZE|PARENB);
282		SET(cflag, CS8);
283		CLR(iflag, ISTRIP|INPCK|IGNPAR);
284	} else if (AP || EP || OP) {
285		CLR(cflag, CSIZE);
286		SET(cflag, CS7|PARENB);
287		SET(iflag, ISTRIP);
288		if (OP && !EP) {
289			SET(iflag, INPCK|IGNPAR);
290			SET(cflag, PARODD);
291			if (AP)
292				CLR(iflag, INPCK);
293		} else if (EP && !OP) {
294			SET(iflag, INPCK|IGNPAR);
295			CLR(cflag, PARODD);
296			if (AP)
297				CLR(iflag, INPCK);
298		} else if (AP || (EP && OP)) {
299			CLR(iflag, INPCK|IGNPAR);
300			CLR(cflag, PARODD);
301		}
302	} /* else, leave as is */
303
304#if 0
305	if (UC)
306		f |= LCASE;
307#endif
308
309	if (HC)
310		SET(cflag, HUPCL);
311	else
312		CLR(cflag, HUPCL);
313
314	if (MB)
315		SET(cflag, MDMBUF);
316	else
317		CLR(cflag, MDMBUF);
318
319	if (HW)
320		SET(cflag, CRTSCTS);
321	else
322		CLR(cflag, CRTSCTS);
323
324	if (NL) {
325		SET(iflag, ICRNL);
326		SET(oflag, ONLCR|OPOST);
327	} else {
328		CLR(iflag, ICRNL);
329		CLR(oflag, ONLCR);
330	}
331
332	if (!HT)
333		SET(oflag, OXTABS|OPOST);
334	else
335		CLR(oflag, OXTABS);
336
337#ifdef XXX_DELAY
338	SET(f, delaybits());
339#endif
340
341	if (n == 1) {		/* read mode flags */
342		if (RW) {
343			iflag = 0;
344			CLR(oflag, OPOST);
345			CLR(cflag, CSIZE|PARENB);
346			SET(cflag, CS8);
347			lflag = 0;
348		} else {
349			CLR(lflag, ICANON);
350		}
351		goto out;
352	}
353
354	if (n == 0)
355		goto out;
356
357#if 0
358	if (CB)
359		SET(f, CRTBS);
360#endif
361
362	if (CE)
363		SET(lflag, ECHOE);
364	else
365		CLR(lflag, ECHOE);
366
367	if (CK)
368		SET(lflag, ECHOKE);
369	else
370		CLR(lflag, ECHOKE);
371
372	if (PE)
373		SET(lflag, ECHOPRT);
374	else
375		CLR(lflag, ECHOPRT);
376
377	if (EC)
378		SET(lflag, ECHO);
379	else
380		CLR(lflag, ECHO);
381
382	if (XC)
383		SET(lflag, ECHOCTL);
384	else
385		CLR(lflag, ECHOCTL);
386
387	if (DX)
388		SET(lflag, IXANY);
389	else
390		CLR(lflag, IXANY);
391
392out:
393	tmode.c_iflag = iflag;
394	tmode.c_oflag = oflag;
395	tmode.c_cflag = cflag;
396	tmode.c_lflag = lflag;
397}
398
399
400#ifdef XXX_DELAY
401struct delayval {
402	unsigned	delay;		/* delay in ms */
403	int		bits;
404};
405
406/*
407 * below are random guesses, I can't be bothered checking
408 */
409
410struct delayval	crdelay[] = {
411	{ 1,		CR1 },
412	{ 2,		CR2 },
413	{ 3,		CR3 },
414	{ 83,		CR1 },
415	{ 166,		CR2 },
416	{ 0,		CR3 },
417};
418
419struct delayval nldelay[] = {
420	{ 1,		NL1 },		/* special, calculated */
421	{ 2,		NL2 },
422	{ 3,		NL3 },
423	{ 100,		NL2 },
424	{ 0,		NL3 },
425};
426
427struct delayval	bsdelay[] = {
428	{ 1,		BS1 },
429	{ 0,		0 },
430};
431
432struct delayval	ffdelay[] = {
433	{ 1,		FF1 },
434	{ 1750,		FF1 },
435	{ 0,		FF1 },
436};
437
438struct delayval	tbdelay[] = {
439	{ 1,		TAB1 },
440	{ 2,		TAB2 },
441	{ 3,		XTABS },	/* this is expand tabs */
442	{ 100,		TAB1 },
443	{ 0,		TAB2 },
444};
445
446int
447delaybits(void)
448{
449	int f;
450
451	f  = adelay(CD, crdelay);
452	f |= adelay(ND, nldelay);
453	f |= adelay(FD, ffdelay);
454	f |= adelay(TD, tbdelay);
455	f |= adelay(BD, bsdelay);
456	return (f);
457}
458
459int
460adelay(int ms, struct delayval *dp)
461{
462	if (ms == 0)
463		return (0);
464	while (dp->delay && ms > dp->delay)
465		dp++;
466	return (dp->bits);
467}
468#endif
469
470char	editedhost[MAXHOSTNAMELEN];
471
472void
473edithost(const char *pattern)
474{
475	regex_t regex;
476	regmatch_t *match;
477	int found;
478
479	if (pattern == NULL || *pattern == '\0')
480		goto copyasis;
481	if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
482		goto copyasis;
483
484	match = calloc(regex.re_nsub + 1, sizeof(*match));
485	if (match == NULL) {
486		regfree(&regex);
487		goto copyasis;
488	}
489
490	found = !regexec(&regex, HN, regex.re_nsub + 1, match, 0);
491	if (found) {
492		size_t subex, totalsize;
493
494		/*
495		 * We found a match.  If there were no parenthesized
496		 * subexpressions in the pattern, use entire matched
497		 * string as ``editedhost''; otherwise use the first
498		 * matched subexpression.
499		 */
500		subex = !!regex.re_nsub;
501		totalsize = match[subex].rm_eo - match[subex].rm_so + 1;
502		strlcpy(editedhost, HN + match[subex].rm_so, totalsize >
503		    sizeof(editedhost) ? sizeof(editedhost) : totalsize);
504	}
505	free(match);
506	regfree(&regex);
507	if (found)
508		return;
509	/*
510	 * In case of any errors, or if the pattern did not match, pass
511	 * the original hostname as is.
512	 */
513 copyasis:
514	strlcpy(editedhost, HN, sizeof(editedhost));
515}
516
517static struct speedtab {
518	int	speed;
519	int	uxname;
520} speedtab[] = {
521	{ 50,	B50 },
522	{ 75,	B75 },
523	{ 110,	B110 },
524	{ 134,	B134 },
525	{ 150,	B150 },
526	{ 200,	B200 },
527	{ 300,	B300 },
528	{ 600,	B600 },
529	{ 1200,	B1200 },
530	{ 1800,	B1800 },
531	{ 2400,	B2400 },
532	{ 4800,	B4800 },
533	{ 9600,	B9600 },
534	{ 19200, EXTA },
535	{ 19,	EXTA },		/* for people who say 19.2K */
536	{ 38400, EXTB },
537	{ 38,	EXTB },
538	{ 7200,	EXTB },		/* alternative */
539	{ 57600, B57600 },
540	{ 115200, B115200 },
541	{ 230400, B230400 },
542	{ 0 }
543};
544
545int
546speed(int val)
547{
548	struct speedtab *sp;
549
550	if (val <= B230400)
551		return (val);
552
553	for (sp = speedtab; sp->speed; sp++)
554		if (sp->speed == val)
555			return (sp->uxname);
556
557	return (B300);		/* default in impossible cases */
558}
559
560void
561makeenv(char *env[])
562{
563	static char termbuf[128] = "TERM=";
564	char *p, *q;
565	char **ep;
566
567	ep = env;
568	if (TT && *TT) {
569		strlcat(termbuf, TT, sizeof(termbuf));
570		*ep++ = termbuf;
571	}
572	if ((p = EV)) {
573		q = p;
574		while ((q = strchr(q, ','))) {
575			*q++ = '\0';
576			*ep++ = p;
577			p = q;
578		}
579		if (*p)
580			*ep++ = p;
581	}
582	*ep = (char *)0;
583}
584
585/*
586 * This speed select mechanism is written for the Develcon DATASWITCH.
587 * The Develcon sends a string of the form "B{speed}\n" at a predefined
588 * baud rate. This string indicates the user's actual speed.
589 * The routine below returns the terminal type mapped from derived speed.
590 */
591struct	portselect {
592	const char	*ps_baud;
593	const char	*ps_type;
594} portspeeds[] = {
595	{ "B110",	"std.110" },
596	{ "B134",	"std.134" },
597	{ "B150",	"std.150" },
598	{ "B300",	"std.300" },
599	{ "B600",	"std.600" },
600	{ "B1200",	"std.1200" },
601	{ "B2400",	"std.2400" },
602	{ "B4800",	"std.4800" },
603	{ "B9600",	"std.9600" },
604	{ "B19200",	"std.19200" },
605	{ NULL, NULL }
606};
607
608const char *
609portselector(void)
610{
611	char c, baud[20];
612	const char *type = "default";
613	struct portselect *ps;
614	size_t len;
615
616	alarm(5*60);
617	for (len = 0; len < sizeof (baud) - 1; len++) {
618		if (read(STDIN_FILENO, &c, 1) <= 0)
619			break;
620		c &= 0177;
621		if (c == '\n' || c == '\r')
622			break;
623		if (c == 'B')
624			len = 0;	/* in case of leading garbage */
625		baud[len] = c;
626	}
627	baud[len] = '\0';
628	for (ps = portspeeds; ps->ps_baud; ps++)
629		if (strcmp(ps->ps_baud, baud) == 0) {
630			type = ps->ps_type;
631			break;
632		}
633	sleep(2);	/* wait for connection to complete */
634	return (type);
635}
636
637/*
638 * This auto-baud speed select mechanism is written for the Micom 600
639 * portselector. Selection is done by looking at how the character '\r'
640 * is garbled at the different speeds.
641 */
642const char *
643autobaud(void)
644{
645	struct pollfd set[1];
646	struct timespec timeout;
647	char c;
648	const char *type = "9600-baud";
649
650	(void)tcflush(0, TCIOFLUSH);
651	set[0].fd = STDIN_FILENO;
652	set[0].events = POLLIN;
653	if (poll(set, 1, 5000) <= 0)
654		return (type);
655	if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
656		return (type);
657	timeout.tv_sec = 0;
658	timeout.tv_nsec = 20000;
659	(void)nanosleep(&timeout, NULL);
660	(void)tcflush(0, TCIOFLUSH);
661	switch (c & 0377) {
662
663	case 0200:		/* 300-baud */
664		type = "300-baud";
665		break;
666
667	case 0346:		/* 1200-baud */
668		type = "1200-baud";
669		break;
670
671	case  015:		/* 2400-baud */
672	case 0215:
673		type = "2400-baud";
674		break;
675
676	default:		/* 4800-baud */
677		type = "4800-baud";
678		break;
679
680	case 0377:		/* 9600-baud */
681		type = "9600-baud";
682		break;
683	}
684	return (type);
685}
686