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