1 /* $OpenBSD: subr.c,v 1.18 2003/06/02 19:38:24 millert 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 /*static char sccsid[] = "from: @(#)subr.c 8.1 (Berkeley) 6/4/93";*/ 34 static char rcsid[] = "$OpenBSD: subr.c,v 1.18 2003/06/02 19:38:24 millert Exp $"; 35 #endif /* not lint */ 36 37 /* 38 * Melbourne getty. 39 */ 40 #define COMPAT_43 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <string.h> 44 #include <termios.h> 45 #include <sys/ioctl.h> 46 47 #include "gettytab.h" 48 #include "pathnames.h" 49 #include "extern.h" 50 51 extern struct termios tmode, omode; 52 53 static void compatflags(long); 54 55 /* 56 * Get a table entry. 57 */ 58 void 59 gettable(char *name, char *buf) 60 { 61 struct gettystrs *sp; 62 struct gettynums *np; 63 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 void 104 gendefaults(void) 105 { 106 struct gettystrs *sp; 107 struct gettynums *np; 108 struct gettyflags *fp; 109 110 for (sp = gettystrs; sp->field; sp++) 111 if (sp->value) 112 sp->defalt = sp->value; 113 for (np = gettynums; np->field; np++) 114 if (np->set) 115 np->defalt = np->value; 116 for (fp = gettyflags; fp->field; fp++) 117 if (fp->set) 118 fp->defalt = fp->value; 119 else 120 fp->defalt = fp->invrt; 121 } 122 123 void 124 setdefaults(void) 125 { 126 struct gettystrs *sp; 127 struct gettynums *np; 128 struct gettyflags *fp; 129 130 for (sp = gettystrs; sp->field; sp++) 131 if (!sp->value) 132 sp->value = sp->defalt; 133 for (np = gettynums; np->field; np++) 134 if (!np->set) 135 np->value = np->defalt; 136 for (fp = gettyflags; fp->field; fp++) 137 if (!fp->set) 138 fp->value = fp->defalt; 139 } 140 141 static char ** 142 charnames[] = { 143 &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, 144 &SU, &DS, &RP, &FL, &WE, &LN, 0 145 }; 146 147 static char * 148 charvars[] = { 149 &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR], 150 &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP], 151 &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP], 152 &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD], 153 &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0 154 }; 155 156 void 157 setchars(void) 158 { 159 int i; 160 char *p; 161 162 for (i = 0; charnames[i]; i++) { 163 p = *charnames[i]; 164 if (p && *p) 165 *charvars[i] = *p; 166 else 167 *charvars[i] = _POSIX_VDISABLE; 168 } 169 } 170 171 /* Macros to clear/set/test flags. */ 172 #define SET(t, f) (t) |= (f) 173 #define CLR(t, f) (t) &= ~(f) 174 #define ISSET(t, f) ((t) & (f)) 175 176 void 177 setflags(int n) 178 { 179 tcflag_t iflag, oflag, cflag, lflag; 180 181 #ifdef COMPAT_43 182 switch (n) { 183 case 0: 184 if (F0set) { 185 compatflags(F0); 186 return; 187 } 188 break; 189 case 1: 190 if (F1set) { 191 compatflags(F1); 192 return; 193 } 194 break; 195 default: 196 if (F2set) { 197 compatflags(F2); 198 return; 199 } 200 break; 201 } 202 #endif 203 204 switch (n) { 205 case 0: 206 if (C0set && I0set && L0set && O0set) { 207 tmode.c_cflag = C0; 208 tmode.c_iflag = I0; 209 tmode.c_lflag = L0; 210 tmode.c_oflag = O0; 211 return; 212 } 213 break; 214 case 1: 215 if (C1set && I1set && L1set && O1set) { 216 tmode.c_cflag = C1; 217 tmode.c_iflag = I1; 218 tmode.c_lflag = L1; 219 tmode.c_oflag = O1; 220 return; 221 } 222 break; 223 default: 224 if (C2set && I2set && L2set && O2set) { 225 tmode.c_cflag = C2; 226 tmode.c_iflag = I2; 227 tmode.c_lflag = L2; 228 tmode.c_oflag = O2; 229 return; 230 } 231 break; 232 } 233 234 iflag = omode.c_iflag; 235 oflag = omode.c_oflag; 236 cflag = omode.c_cflag; 237 lflag = omode.c_lflag; 238 239 if (NP) { 240 CLR(cflag, CSIZE|PARENB); 241 SET(cflag, CS8); 242 CLR(iflag, ISTRIP|INPCK|IGNPAR); 243 } else if (AP || EP || OP) { 244 CLR(cflag, CSIZE); 245 SET(cflag, CS7|PARENB); 246 SET(iflag, ISTRIP); 247 if (OP && !EP) { 248 SET(iflag, INPCK|IGNPAR); 249 SET(cflag, PARODD); 250 if (AP) 251 CLR(iflag, INPCK); 252 } else if (EP && !OP) { 253 SET(iflag, INPCK|IGNPAR); 254 CLR(cflag, PARODD); 255 if (AP) 256 CLR(iflag, INPCK); 257 } else if (AP || (EP && OP)) { 258 CLR(iflag, INPCK|IGNPAR); 259 CLR(cflag, PARODD); 260 } 261 } /* else, leave as is */ 262 263 if (UC) { 264 SET(iflag, IUCLC); 265 SET(oflag, OLCUC); 266 SET(lflag, XCASE); 267 } 268 269 if (HC) 270 SET(cflag, HUPCL); 271 else 272 CLR(cflag, HUPCL); 273 274 if (MB) 275 SET(cflag, MDMBUF); 276 else 277 CLR(cflag, MDMBUF); 278 279 if (NL) { 280 SET(iflag, ICRNL); 281 SET(oflag, ONLCR|OPOST); 282 } else { 283 CLR(iflag, ICRNL); 284 CLR(oflag, ONLCR); 285 } 286 287 if (!HT) 288 SET(oflag, OXTABS|OPOST); 289 else 290 CLR(oflag, OXTABS); 291 292 #ifdef XXX_DELAY 293 SET(f, delaybits()); 294 #endif 295 296 if (n == 1) { /* read mode flags */ 297 if (RW) { 298 iflag = 0; 299 CLR(oflag, OPOST); 300 CLR(cflag, CSIZE|PARENB); 301 SET(cflag, CS8); 302 lflag = 0; 303 } else { 304 CLR(lflag, ICANON); 305 } 306 goto out; 307 } 308 309 if (n == 0) 310 goto out; 311 312 #if 0 313 if (CB) 314 SET(f, CRTBS); 315 #endif 316 317 if (CE) 318 SET(lflag, ECHOE); 319 else 320 CLR(lflag, ECHOE); 321 322 if (CK) 323 SET(lflag, ECHOKE); 324 else 325 CLR(lflag, ECHOKE); 326 327 if (PE) 328 SET(lflag, ECHOPRT); 329 else 330 CLR(lflag, ECHOPRT); 331 332 if (EC) 333 SET(lflag, ECHO); 334 else 335 CLR(lflag, ECHO); 336 337 if (XC) 338 SET(lflag, ECHOCTL); 339 else 340 CLR(lflag, ECHOCTL); 341 342 if (DX) 343 SET(lflag, IXANY); 344 else 345 CLR(lflag, IXANY); 346 347 out: 348 tmode.c_iflag = iflag; 349 tmode.c_oflag = oflag; 350 tmode.c_cflag = cflag; 351 tmode.c_lflag = lflag; 352 } 353 354 #ifdef COMPAT_43 355 /* 356 * Old TTY => termios, snatched from <sys/kern/tty_compat.c> 357 */ 358 void 359 compatflags(long flags) 360 { 361 tcflag_t iflag, oflag, cflag, lflag; 362 363 iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY; 364 oflag = OPOST|ONLCR|OXTABS; 365 cflag = CREAD; 366 lflag = ICANON|ISIG|IEXTEN; 367 368 if (ISSET(flags, TANDEM)) 369 SET(iflag, IXOFF); 370 else 371 CLR(iflag, IXOFF); 372 if (ISSET(flags, ECHO)) 373 SET(lflag, ECHO); 374 else 375 CLR(lflag, ECHO); 376 if (ISSET(flags, CRMOD)) { 377 SET(iflag, ICRNL); 378 SET(oflag, ONLCR); 379 } else { 380 CLR(iflag, ICRNL); 381 CLR(oflag, ONLCR); 382 } 383 if (ISSET(flags, XTABS)) 384 SET(oflag, OXTABS); 385 else 386 CLR(oflag, OXTABS); 387 if (ISSET(flags, LCASE)) { 388 SET(iflag, IUCLC); 389 SET(oflag, OLCUC); 390 SET(lflag, XCASE); 391 } 392 else { 393 CLR(iflag, IUCLC); 394 CLR(oflag, OLCUC); 395 CLR(lflag, XCASE); 396 } 397 398 399 if (ISSET(flags, RAW)) { 400 iflag &= IXOFF; 401 CLR(lflag, ISIG|ICANON|IEXTEN|XCASE); 402 CLR(cflag, PARENB); 403 } else { 404 SET(iflag, BRKINT|IXON|IMAXBEL); 405 SET(lflag, ISIG|IEXTEN); 406 if (ISSET(iflag, IUCLC) && ISSET(oflag, OLCUC)) 407 SET(lflag, XCASE); 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 int 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 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(int ms, struct delayval *dp) 552 { 553 if (ms == 0) 554 return (0); 555 while (dp->delay && ms > dp->delay) 556 dp++; 557 return (dp->bits); 558 } 559 #endif 560 561 char editedhost[48]; 562 563 void 564 edithost(char *pat) 565 { 566 char *host = HN; 567 char *res = editedhost; 568 569 if (!pat) 570 pat = ""; 571 while (*pat) { 572 switch (*pat) { 573 574 case '#': 575 if (*host) 576 host++; 577 break; 578 579 case '@': 580 if (*host) 581 *res++ = *host++; 582 break; 583 584 default: 585 *res++ = *pat; 586 break; 587 588 } 589 if (res == &editedhost[sizeof editedhost - 1]) { 590 *res = '\0'; 591 return; 592 } 593 pat++; 594 } 595 if (*host) 596 strlcpy(res, host, sizeof editedhost - (res - editedhost)); 597 else 598 *res = '\0'; 599 } 600 601 void 602 makeenv(char *env[]) 603 { 604 static char termbuf[128] = "TERM="; 605 char *p, *q; 606 char **ep; 607 608 ep = env; 609 if (TT && *TT) { 610 strlcat(termbuf, TT, sizeof(termbuf)); 611 *ep++ = termbuf; 612 } 613 if ((p = EV)) { 614 q = p; 615 while ((q = strchr(q, ','))) { 616 *q++ = '\0'; 617 *ep++ = p; 618 p = q; 619 } 620 if (*p) 621 *ep++ = p; 622 } 623 *ep = (char *)0; 624 } 625 626 /* 627 * This speed select mechanism is written for the Develcon DATASWITCH. 628 * The Develcon sends a string of the form "B{speed}\n" at a predefined 629 * baud rate. This string indicates the user's actual speed. 630 * The routine below returns the terminal type mapped from derived speed. 631 */ 632 struct portselect { 633 char *ps_baud; 634 char *ps_type; 635 } portspeeds[] = { 636 { "B110", "std.110" }, 637 { "B134", "std.134" }, 638 { "B150", "std.150" }, 639 { "B300", "std.300" }, 640 { "B600", "std.600" }, 641 { "B1200", "std.1200" }, 642 { "B2400", "std.2400" }, 643 { "B4800", "std.4800" }, 644 { "B9600", "std.9600" }, 645 { "B19200", "std.19200" }, 646 { 0 } 647 }; 648 649 char * 650 portselector(void) 651 { 652 char c, baud[20], *type = "default"; 653 struct portselect *ps; 654 int len; 655 656 alarm(5*60); 657 for (len = 0; len < sizeof (baud) - 1; len++) { 658 if (read(STDIN_FILENO, &c, 1) <= 0) 659 break; 660 c &= 0177; 661 if (c == '\n' || c == '\r') 662 break; 663 if (c == 'B') 664 len = 0; /* in case of leading garbage */ 665 baud[len] = c; 666 } 667 baud[len] = '\0'; 668 for (ps = portspeeds; ps->ps_baud; ps++) 669 if (strcmp(ps->ps_baud, baud) == 0) { 670 type = ps->ps_type; 671 break; 672 } 673 sleep(2); /* wait for connection to complete */ 674 return (type); 675 } 676 677 /* 678 * This auto-baud speed select mechanism is written for the Micom 600 679 * portselector. Selection is done by looking at how the character '\r' 680 * is garbled at the different speeds. 681 */ 682 #include <sys/time.h> 683 684 char * 685 autobaud(void) 686 { 687 fd_set rfds; 688 struct timeval timeout; 689 char c, *type = "9600-baud"; 690 691 (void)tcflush(0, TCIOFLUSH); 692 FD_ZERO(&rfds); 693 FD_SET(0, &rfds); 694 timeout.tv_sec = 5; 695 timeout.tv_usec = 0; 696 if (select(1, &rfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) <= 0) 697 return (type); 698 if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char)) 699 return (type); 700 timeout.tv_sec = 0; 701 timeout.tv_usec = 20; 702 (void) select(0, (fd_set *)NULL, (fd_set *)NULL, 703 (fd_set *)NULL, &timeout); 704 (void)tcflush(0, TCIOFLUSH); 705 switch (c & 0377) { 706 707 case 0200: /* 300-baud */ 708 type = "300-baud"; 709 break; 710 711 case 0346: /* 1200-baud */ 712 type = "1200-baud"; 713 break; 714 715 case 015: /* 2400-baud */ 716 case 0215: 717 type = "2400-baud"; 718 break; 719 720 default: /* 4800-baud */ 721 type = "4800-baud"; 722 break; 723 724 case 0377: /* 9600-baud */ 725 type = "9600-baud"; 726 break; 727 } 728 return (type); 729 } 730