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