xref: /freebsd/libexec/getty/subr.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
1 /*
2  * Copyright (c) 1983 The Regents of the University of California.
3  * 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  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
34  * --------------------         -----   ----------------------
35  * CURRENT PATCH LEVEL:         1       00150
36  * --------------------         -----   ----------------------
37  *
38  * 22 Apr 93	Rodney W. Grimes	support for 57600 and 115200 baud
39  *
40  */
41 
42 #ifndef lint
43 static char sccsid[] = "@(#)subr.c	5.10 (Berkeley) 2/26/91";
44 #endif /* not lint */
45 
46 /*
47  * Melbourne getty.
48  */
49 #include <sys/param.h>
50 #include <sgtty.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include "gettytab.h"
54 
55 extern	struct sgttyb tmode;
56 extern	struct tchars tc;
57 extern	struct ltchars ltc;
58 
59 /*
60  * Get a table entry.
61  */
62 gettable(name, buf, area)
63 	char *name, *buf, *area;
64 {
65 	register struct gettystrs *sp;
66 	register struct gettynums *np;
67 	register struct gettyflags *fp;
68 	register n;
69 
70 	hopcount = 0;		/* new lookup, start fresh */
71 	if (getent(buf, name) != 1)
72 		return;
73 
74 	for (sp = gettystrs; sp->field; sp++)
75 		sp->value = getstr(sp->field, &area);
76 	for (np = gettynums; np->field; np++) {
77 		n = getnum(np->field);
78 		if (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 		n = getflag(fp->field);
87 		if (n == -1)
88 			fp->set = 0;
89 		else {
90 			fp->set = 1;
91 			fp->value = n ^ fp->invrt;
92 		}
93 	}
94 }
95 
96 gendefaults()
97 {
98 	register struct gettystrs *sp;
99 	register struct gettynums *np;
100 	register struct gettyflags *fp;
101 
102 	for (sp = gettystrs; sp->field; sp++)
103 		if (sp->value)
104 			sp->defalt = sp->value;
105 	for (np = gettynums; np->field; np++)
106 		if (np->set)
107 			np->defalt = np->value;
108 	for (fp = gettyflags; fp->field; fp++)
109 		if (fp->set)
110 			fp->defalt = fp->value;
111 		else
112 			fp->defalt = fp->invrt;
113 }
114 
115 setdefaults()
116 {
117 	register struct gettystrs *sp;
118 	register struct gettynums *np;
119 	register struct gettyflags *fp;
120 
121 	for (sp = gettystrs; sp->field; sp++)
122 		if (!sp->value)
123 			sp->value = sp->defalt;
124 	for (np = gettynums; np->field; np++)
125 		if (!np->set)
126 			np->value = np->defalt;
127 	for (fp = gettyflags; fp->field; fp++)
128 		if (!fp->set)
129 			fp->value = fp->defalt;
130 }
131 
132 static char **
133 charnames[] = {
134 	&ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
135 	&SU, &DS, &RP, &FL, &WE, &LN, 0
136 };
137 
138 static char *
139 charvars[] = {
140 	&tmode.sg_erase, &tmode.sg_kill, &tc.t_intrc,
141 	&tc.t_quitc, &tc.t_startc, &tc.t_stopc,
142 	&tc.t_eofc, &tc.t_brkc, &ltc.t_suspc,
143 	&ltc.t_dsuspc, &ltc.t_rprntc, &ltc.t_flushc,
144 	&ltc.t_werasc, &ltc.t_lnextc, 0
145 };
146 
147 setchars()
148 {
149 	register int i;
150 	register char *p;
151 
152 	for (i = 0; charnames[i]; i++) {
153 		p = *charnames[i];
154 		if (p && *p)
155 			*charvars[i] = *p;
156 		else
157 			*charvars[i] = '\377';
158 	}
159 }
160 
161 long
162 setflags(n)
163 {
164 	register long f;
165 
166 	switch (n) {
167 	case 0:
168 		if (F0set)
169 			return(F0);
170 		break;
171 	case 1:
172 		if (F1set)
173 			return(F1);
174 		break;
175 	default:
176 		if (F2set)
177 			return(F2);
178 		break;
179 	}
180 
181 	f = 0;
182 
183 	if (AP)
184 		f |= ANYP;
185 	else if (OP)
186 		f |= ODDP;
187 	else if (EP)
188 		f |= EVENP;
189 	if (NP)
190 		f |= PASS8;
191 
192 	if (UC)
193 		f |= LCASE;
194 
195 	if (NL)
196 		f |= CRMOD;
197 
198 	f |= delaybits();
199 
200 	if (n == 1) {		/* read mode flags */
201 		if (RW)
202 			f |= RAW;
203 		else
204 			f |= CBREAK;
205 		return (f);
206 	}
207 
208 	if (!HT)
209 		f |= XTABS;
210 
211 	if (n == 0)
212 		return (f);
213 
214 	if (CB)
215 		f |= CRTBS;
216 
217 	if (CE)
218 		f |= CRTERA;
219 
220 	if (CK)
221 		f |= CRTKIL;
222 
223 	if (PE)
224 		f |= PRTERA;
225 
226 	if (EC)
227 		f |= ECHO;
228 
229 	if (XC)
230 		f |= CTLECH;
231 
232 	if (DX)
233 		f |= DECCTQ;
234 
235 	return (f);
236 }
237 
238 struct delayval {
239 	unsigned	delay;		/* delay in ms */
240 	int		bits;
241 };
242 
243 /*
244  * below are random guesses, I can't be bothered checking
245  */
246 
247 struct delayval	crdelay[] = {
248 	1,		CR1,
249 	2,		CR2,
250 	3,		CR3,
251 	83,		CR1,
252 	166,		CR2,
253 	0,		CR3,
254 };
255 
256 struct delayval nldelay[] = {
257 	1,		NL1,		/* special, calculated */
258 	2,		NL2,
259 	3,		NL3,
260 	100,		NL2,
261 	0,		NL3,
262 };
263 
264 struct delayval	bsdelay[] = {
265 	1,		BS1,
266 	0,		0,
267 };
268 
269 struct delayval	ffdelay[] = {
270 	1,		FF1,
271 	1750,		FF1,
272 	0,		FF1,
273 };
274 
275 struct delayval	tbdelay[] = {
276 	1,		TAB1,
277 	2,		TAB2,
278 	3,		XTABS,		/* this is expand tabs */
279 	100,		TAB1,
280 	0,		TAB2,
281 };
282 
283 delaybits()
284 {
285 	register f;
286 
287 	f  = adelay(CD, crdelay);
288 	f |= adelay(ND, nldelay);
289 	f |= adelay(FD, ffdelay);
290 	f |= adelay(TD, tbdelay);
291 	f |= adelay(BD, bsdelay);
292 	return (f);
293 }
294 
295 adelay(ms, dp)
296 	register ms;
297 	register struct delayval *dp;
298 {
299 	if (ms == 0)
300 		return (0);
301 	while (dp->delay && ms > dp->delay)
302 		dp++;
303 	return (dp->bits);
304 }
305 
306 char    editedhost[MAXHOSTNAMELEN];
307 
308 edithost(pat)
309 	register char *pat;
310 {
311 	register char *host = HN;
312 	register char *res = editedhost;
313 
314 	if (!pat)
315 		pat = "";
316 	while (*pat) {
317 		switch (*pat) {
318 
319 		case '#':
320 			if (*host)
321 				host++;
322 			break;
323 
324 		case '@':
325 			if (*host)
326 				*res++ = *host++;
327 			break;
328 
329 		default:
330 			*res++ = *pat;
331 			break;
332 
333 		}
334 		if (res == &editedhost[sizeof editedhost - 1]) {
335 			*res = '\0';
336 			return;
337 		}
338 		pat++;
339 	}
340 	if (*host)
341 		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
342 	else
343 		*res = '\0';
344 	editedhost[sizeof editedhost - 1] = '\0';
345 }
346 
347 struct speedtab {
348 	int	speed;
349 	int	uxname;
350 } speedtab[] = {
351 	50,	B50,
352 	75,	B75,
353 	110,	B110,
354 	134,	B134,
355 	150,	B150,
356 	200,	B200,
357 	300,	B300,
358 	600,	B600,
359 	1200,	B1200,
360 	1800,	B1800,
361 	2400,	B2400,
362 	4800,	B4800,
363 	9600,	B9600,
364 	19200,	EXTA,
365 	19,	EXTA,		/* for people who say 19.2K */
366 	38400,	EXTB,
367 	38,	EXTB,
368 	7200,	EXTB,		/* alternative */
369 	57600,	B57600,
370 	115200,	B115200,
371 	0
372 };
373 
374 speed(val)
375 {
376 	register struct speedtab *sp;
377 
378 	if (val <= B115200)
379 		return (val);
380 
381 	for (sp = speedtab; sp->speed; sp++)
382 		if (sp->speed == val)
383 			return (sp->uxname);
384 
385 	return (B300);		/* default in impossible cases */
386 }
387 
388 makeenv(env)
389 	char *env[];
390 {
391 	static char termbuf[128] = "TERM=";
392 	register char *p, *q;
393 	register char **ep;
394 	char *index();
395 
396 	ep = env;
397 	if (TT && *TT) {
398 		strcat(termbuf, TT);
399 		*ep++ = termbuf;
400 	}
401 	if (p = EV) {
402 		q = p;
403 		while (q = index(q, ',')) {
404 			*q++ = '\0';
405 			*ep++ = p;
406 			p = q;
407 		}
408 		if (*p)
409 			*ep++ = p;
410 	}
411 	*ep = (char *)0;
412 }
413 
414 /*
415  * This speed select mechanism is written for the Develcon DATASWITCH.
416  * The Develcon sends a string of the form "B{speed}\n" at a predefined
417  * baud rate. This string indicates the user's actual speed.
418  * The routine below returns the terminal type mapped from derived speed.
419  */
420 struct	portselect {
421 	char	*ps_baud;
422 	char	*ps_type;
423 } portspeeds[] = {
424 	{ "B110",	"std.110" },
425 	{ "B134",	"std.134" },
426 	{ "B150",	"std.150" },
427 	{ "B300",	"std.300" },
428 	{ "B600",	"std.600" },
429 	{ "B1200",	"std.1200" },
430 	{ "B2400",	"std.2400" },
431 	{ "B4800",	"std.4800" },
432 	{ "B9600",	"std.9600" },
433 	{ "B19200",	"std.19200" },
434 	{ 0 }
435 };
436 
437 char *
438 portselector()
439 {
440 	char c, baud[20], *type = "default";
441 	register struct portselect *ps;
442 	int len;
443 
444 	alarm(5*60);
445 	for (len = 0; len < sizeof (baud) - 1; len++) {
446 		if (read(STDIN_FILENO, &c, 1) <= 0)
447 			break;
448 		c &= 0177;
449 		if (c == '\n' || c == '\r')
450 			break;
451 		if (c == 'B')
452 			len = 0;	/* in case of leading garbage */
453 		baud[len] = c;
454 	}
455 	baud[len] = '\0';
456 	for (ps = portspeeds; ps->ps_baud; ps++)
457 		if (strcmp(ps->ps_baud, baud) == 0) {
458 			type = ps->ps_type;
459 			break;
460 		}
461 	sleep(2);	/* wait for connection to complete */
462 	return (type);
463 }
464 
465 /*
466  * This auto-baud speed select mechanism is written for the Micom 600
467  * portselector. Selection is done by looking at how the character '\r'
468  * is garbled at the different speeds.
469  */
470 #include <sys/time.h>
471 
472 char *
473 autobaud()
474 {
475 	int rfds;
476 	struct timeval timeout;
477 	char c, *type = "9600-baud";
478 	int null = 0;
479 
480 	ioctl(0, TIOCFLUSH, &null);
481 	rfds = 1 << 0;
482 	timeout.tv_sec = 5;
483 	timeout.tv_usec = 0;
484 	if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
485 	    (fd_set *)NULL, &timeout) <= 0)
486 		return (type);
487 	if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
488 		return (type);
489 	timeout.tv_sec = 0;
490 	timeout.tv_usec = 20;
491 	(void) select(32, (fd_set *)NULL, (fd_set *)NULL,
492 	    (fd_set *)NULL, &timeout);
493 	ioctl(0, TIOCFLUSH, &null);
494 	switch (c & 0377) {
495 
496 	case 0200:		/* 300-baud */
497 		type = "300-baud";
498 		break;
499 
500 	case 0346:		/* 1200-baud */
501 		type = "1200-baud";
502 		break;
503 
504 	case  015:		/* 2400-baud */
505 	case 0215:
506 		type = "2400-baud";
507 		break;
508 
509 	default:		/* 4800-baud */
510 		type = "4800-baud";
511 		break;
512 
513 	case 0377:		/* 9600-baud */
514 		type = "9600-baud";
515 		break;
516 	}
517 	return (type);
518 }
519