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