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