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