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