1 /* $NetBSD: subr.c,v 1.22 1997/08/06 07:22:26 mikel 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.22 1997/08/06 07:22:26 mikel 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 __P((long)); 64 65 /* 66 * Get a table entry. 67 */ 68 void 69 gettable(name, buf) 70 char *name, *buf; 71 { 72 register struct gettystrs *sp; 73 register struct gettynums *np; 74 register struct gettyflags *fp; 75 long n; 76 char *dba[2]; 77 dba[0] = _PATH_GETTYTAB; 78 dba[1] = 0; 79 80 if (cgetent(&buf, dba, name) != 0) 81 return; 82 83 for (sp = gettystrs; sp->field; sp++) 84 cgetstr(buf, sp->field, &sp->value); 85 for (np = gettynums; np->field; np++) { 86 if (cgetnum(buf, np->field, &n) == -1) 87 np->set = 0; 88 else { 89 np->set = 1; 90 np->value = n; 91 } 92 } 93 for (fp = gettyflags; fp->field; fp++) { 94 if (cgetcap(buf, fp->field, ':') == NULL) 95 fp->set = 0; 96 else { 97 fp->set = 1; 98 fp->value = 1 ^ fp->invrt; 99 } 100 } 101 #ifdef DEBUG 102 printf("name=\"%s\", buf=\"%s\"\n", name, buf); 103 for (sp = gettystrs; sp->field; sp++) 104 printf("cgetstr: %s=%s\n", sp->field, sp->value); 105 for (np = gettynums; np->field; np++) 106 printf("cgetnum: %s=%d\n", np->field, np->value); 107 for (fp = gettyflags; fp->field; fp++) 108 printf("cgetflags: %s='%c' set='%c'\n", fp->field, 109 fp->value + '0', fp->set + '0'); 110 exit(1); 111 #endif /* DEBUG */ 112 } 113 114 void 115 gendefaults() 116 { 117 register struct gettystrs *sp; 118 register struct gettynums *np; 119 register struct gettyflags *fp; 120 121 for (sp = gettystrs; sp->field; sp++) 122 if (sp->value) 123 sp->defalt = sp->value; 124 for (np = gettynums; np->field; np++) 125 if (np->set) 126 np->defalt = np->value; 127 for (fp = gettyflags; fp->field; fp++) 128 if (fp->set) 129 fp->defalt = fp->value; 130 else 131 fp->defalt = fp->invrt; 132 } 133 134 void 135 setdefaults() 136 { 137 register struct gettystrs *sp; 138 register struct gettynums *np; 139 register struct gettyflags *fp; 140 141 for (sp = gettystrs; sp->field; sp++) 142 if (!sp->value) 143 sp->value = sp->defalt; 144 for (np = gettynums; np->field; np++) 145 if (!np->set) 146 np->value = np->defalt; 147 for (fp = gettyflags; fp->field; fp++) 148 if (!fp->set) 149 fp->value = fp->defalt; 150 } 151 152 static char ** 153 charnames[] = { 154 &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, 155 &SU, &DS, &RP, &FL, &WE, &LN, 0 156 }; 157 158 static char * 159 charvars[] = { 160 &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR], 161 &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP], 162 &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP], 163 &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD], 164 &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0 165 }; 166 167 void 168 setchars() 169 { 170 register int i; 171 register char *p; 172 173 for (i = 0; charnames[i]; i++) { 174 p = *charnames[i]; 175 if (p && *p) 176 *charvars[i] = *p; 177 else 178 *charvars[i] = _POSIX_VDISABLE; 179 } 180 } 181 182 /* Macros to clear/set/test flags. */ 183 #define SET(t, f) (t) |= (f) 184 #define CLR(t, f) (t) &= ~(f) 185 #define ISSET(t, f) ((t) & (f)) 186 187 void 188 setflags(n) 189 int n; 190 { 191 register tcflag_t iflag, oflag, cflag, lflag; 192 193 #ifdef COMPAT_43 194 switch (n) { 195 case 0: 196 if (F0set) { 197 compatflags(F0); 198 return; 199 } 200 break; 201 case 1: 202 if (F1set) { 203 compatflags(F1); 204 return; 205 } 206 break; 207 default: 208 if (F2set) { 209 compatflags(F2); 210 return; 211 } 212 break; 213 } 214 #endif 215 216 switch (n) { 217 case 0: 218 if (C0set && I0set && L0set && O0set) { 219 tmode.c_cflag = C0; 220 tmode.c_iflag = I0; 221 tmode.c_lflag = L0; 222 tmode.c_oflag = O0; 223 return; 224 } 225 break; 226 case 1: 227 if (C1set && I1set && L1set && O1set) { 228 tmode.c_cflag = C1; 229 tmode.c_iflag = I1; 230 tmode.c_lflag = L1; 231 tmode.c_oflag = O1; 232 return; 233 } 234 break; 235 default: 236 if (C2set && I2set && L2set && O2set) { 237 tmode.c_cflag = C2; 238 tmode.c_iflag = I2; 239 tmode.c_lflag = L2; 240 tmode.c_oflag = O2; 241 return; 242 } 243 break; 244 } 245 246 iflag = omode.c_iflag; 247 oflag = omode.c_oflag; 248 cflag = omode.c_cflag; 249 lflag = omode.c_lflag; 250 251 if (NP) { 252 CLR(cflag, CSIZE|PARENB); 253 SET(cflag, CS8); 254 CLR(iflag, ISTRIP|INPCK|IGNPAR); 255 } else if (AP || EP || OP) { 256 CLR(cflag, CSIZE); 257 SET(cflag, CS7|PARENB); 258 SET(iflag, ISTRIP); 259 if (OP && !EP) { 260 SET(iflag, INPCK|IGNPAR); 261 SET(cflag, PARODD); 262 if (AP) 263 CLR(iflag, INPCK); 264 } else if (EP && !OP) { 265 SET(iflag, INPCK|IGNPAR); 266 CLR(cflag, PARODD); 267 if (AP) 268 CLR(iflag, INPCK); 269 } else if (AP || (EP && OP)) { 270 CLR(iflag, INPCK|IGNPAR); 271 CLR(cflag, PARODD); 272 } 273 } /* else, leave as is */ 274 275 #if 0 276 if (UC) 277 f |= LCASE; 278 #endif 279 280 if (HC) 281 SET(cflag, HUPCL); 282 else 283 CLR(cflag, HUPCL); 284 285 if (MB) 286 SET(cflag, MDMBUF); 287 else 288 CLR(cflag, MDMBUF); 289 290 if (NL) { 291 SET(iflag, ICRNL); 292 SET(oflag, ONLCR|OPOST); 293 } else { 294 CLR(iflag, ICRNL); 295 CLR(oflag, ONLCR); 296 } 297 298 if (!HT) 299 SET(oflag, OXTABS|OPOST); 300 else 301 CLR(oflag, OXTABS); 302 303 #ifdef XXX_DELAY 304 SET(f, delaybits()); 305 #endif 306 307 if (n == 1) { /* read mode flags */ 308 if (RW) { 309 iflag = 0; 310 CLR(oflag, OPOST); 311 CLR(cflag, CSIZE|PARENB); 312 SET(cflag, CS8); 313 lflag = 0; 314 } else { 315 CLR(lflag, ICANON); 316 } 317 goto out; 318 } 319 320 if (n == 0) 321 goto out; 322 323 #if 0 324 if (CB) 325 SET(f, CRTBS); 326 #endif 327 328 if (CE) 329 SET(lflag, ECHOE); 330 else 331 CLR(lflag, ECHOE); 332 333 if (CK) 334 SET(lflag, ECHOKE); 335 else 336 CLR(lflag, ECHOKE); 337 338 if (PE) 339 SET(lflag, ECHOPRT); 340 else 341 CLR(lflag, ECHOPRT); 342 343 if (EC) 344 SET(lflag, ECHO); 345 else 346 CLR(lflag, ECHO); 347 348 if (XC) 349 SET(lflag, ECHOCTL); 350 else 351 CLR(lflag, ECHOCTL); 352 353 if (DX) 354 SET(lflag, IXANY); 355 else 356 CLR(lflag, IXANY); 357 358 out: 359 tmode.c_iflag = iflag; 360 tmode.c_oflag = oflag; 361 tmode.c_cflag = cflag; 362 tmode.c_lflag = lflag; 363 } 364 365 #ifdef COMPAT_43 366 /* 367 * Old TTY => termios, snatched from <sys/kern/tty_compat.c> 368 */ 369 void 370 compatflags(flags) 371 register long flags; 372 { 373 register tcflag_t iflag, oflag, cflag, lflag; 374 375 iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY; 376 oflag = OPOST|ONLCR|OXTABS; 377 cflag = CREAD; 378 lflag = ICANON|ISIG|IEXTEN; 379 380 if (ISSET(flags, TANDEM)) 381 SET(iflag, IXOFF); 382 else 383 CLR(iflag, IXOFF); 384 if (ISSET(flags, ECHO)) 385 SET(lflag, ECHO); 386 else 387 CLR(lflag, ECHO); 388 if (ISSET(flags, CRMOD)) { 389 SET(iflag, ICRNL); 390 SET(oflag, ONLCR); 391 } else { 392 CLR(iflag, ICRNL); 393 CLR(oflag, ONLCR); 394 } 395 if (ISSET(flags, XTABS)) 396 SET(oflag, OXTABS); 397 else 398 CLR(oflag, OXTABS); 399 400 401 if (ISSET(flags, RAW)) { 402 iflag &= IXOFF; 403 CLR(lflag, ISIG|ICANON|IEXTEN); 404 CLR(cflag, PARENB); 405 } else { 406 SET(iflag, BRKINT|IXON|IMAXBEL); 407 SET(lflag, ISIG|IEXTEN); 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 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 538 delaybits() 539 { 540 register 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 551 adelay(ms, dp) 552 register ms; 553 register struct delayval *dp; 554 { 555 if (ms == 0) 556 return (0); 557 while (dp->delay && ms > dp->delay) 558 dp++; 559 return (dp->bits); 560 } 561 #endif 562 563 char editedhost[MAXHOSTNAMELEN]; 564 565 void 566 edithost(pat) 567 register char *pat; 568 { 569 register char *host = HN; 570 register char *res = editedhost; 571 572 if (!pat) 573 pat = ""; 574 while (*pat) { 575 switch (*pat) { 576 577 case '#': 578 if (*host) 579 host++; 580 break; 581 582 case '@': 583 if (*host) 584 *res++ = *host++; 585 break; 586 587 default: 588 *res++ = *pat; 589 break; 590 591 } 592 if (res == &editedhost[sizeof editedhost - 1]) { 593 *res = '\0'; 594 return; 595 } 596 pat++; 597 } 598 if (*host) 599 strncpy(res, host, sizeof editedhost - (res - editedhost) - 1); 600 else 601 *res = '\0'; 602 editedhost[sizeof editedhost - 1] = '\0'; 603 } 604 605 void 606 makeenv(env) 607 char *env[]; 608 { 609 static char termbuf[128] = "TERM="; 610 register char *p, *q; 611 register char **ep; 612 613 ep = env; 614 if (TT && *TT) { 615 strncat(termbuf, TT, 128); 616 termbuf[127] = (char)NULL; 617 *ep++ = termbuf; 618 } 619 if ((p = EV) != NULL) { 620 q = p; 621 while ((q = strchr(q, ',')) != NULL) { 622 *q++ = '\0'; 623 *ep++ = p; 624 p = q; 625 } 626 if (*p) 627 *ep++ = p; 628 } 629 *ep = (char *)0; 630 } 631 632 /* 633 * This speed select mechanism is written for the Develcon DATASWITCH. 634 * The Develcon sends a string of the form "B{speed}\n" at a predefined 635 * baud rate. This string indicates the user's actual speed. 636 * The routine below returns the terminal type mapped from derived speed. 637 */ 638 struct portselect { 639 char *ps_baud; 640 char *ps_type; 641 } portspeeds[] = { 642 { "B110", "std.110" }, 643 { "B134", "std.134" }, 644 { "B150", "std.150" }, 645 { "B300", "std.300" }, 646 { "B600", "std.600" }, 647 { "B1200", "std.1200" }, 648 { "B2400", "std.2400" }, 649 { "B4800", "std.4800" }, 650 { "B9600", "std.9600" }, 651 { "B19200", "std.19200" }, 652 { 0 } 653 }; 654 655 char * 656 portselector() 657 { 658 char c, baud[20], *type = "default"; 659 register struct portselect *ps; 660 int len; 661 662 alarm(5*60); 663 for (len = 0; len < sizeof (baud) - 1; len++) { 664 if (read(STDIN_FILENO, &c, 1) <= 0) 665 break; 666 c &= 0177; 667 if (c == '\n' || c == '\r') 668 break; 669 if (c == 'B') 670 len = 0; /* in case of leading garbage */ 671 baud[len] = c; 672 } 673 baud[len] = '\0'; 674 for (ps = portspeeds; ps->ps_baud; ps++) 675 if (strcmp(ps->ps_baud, baud) == 0) { 676 type = ps->ps_type; 677 break; 678 } 679 sleep(2); /* wait for connection to complete */ 680 return (type); 681 } 682 683 /* 684 * This auto-baud speed select mechanism is written for the Micom 600 685 * portselector. Selection is done by looking at how the character '\r' 686 * is garbled at the different speeds. 687 */ 688 #include <sys/time.h> 689 690 char * 691 autobaud() 692 { 693 int rfds; 694 struct timeval timeout; 695 char c, *type = "9600-baud"; 696 697 (void)tcflush(0, TCIOFLUSH); 698 rfds = 1 << 0; 699 timeout.tv_sec = 5; 700 timeout.tv_usec = 0; 701 if (select(32, (fd_set *)&rfds, (fd_set *)NULL, 702 (fd_set *)NULL, &timeout) <= 0) 703 return (type); 704 if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char)) 705 return (type); 706 timeout.tv_sec = 0; 707 timeout.tv_usec = 20; 708 (void) select(32, (fd_set *)NULL, (fd_set *)NULL, 709 (fd_set *)NULL, &timeout); 710 (void)tcflush(0, TCIOFLUSH); 711 switch (c & 0377) { 712 713 case 0200: /* 300-baud */ 714 type = "300-baud"; 715 break; 716 717 case 0346: /* 1200-baud */ 718 type = "1200-baud"; 719 break; 720 721 case 015: /* 2400-baud */ 722 case 0215: 723 type = "2400-baud"; 724 break; 725 726 default: /* 4800-baud */ 727 type = "4800-baud"; 728 break; 729 730 case 0377: /* 9600-baud */ 731 type = "9600-baud"; 732 break; 733 } 734 return (type); 735 } 736