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