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