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