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