1 /* $NetBSD: subr.c,v 1.30 2004/04/23 21:04:25 christos 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 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "from: @(#)subr.c 8.1 (Berkeley) 6/4/93"; 36 #else 37 __RCSID("$NetBSD: subr.c,v 1.30 2004/04/23 21:04:25 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 /* 42 * Melbourne getty. 43 */ 44 #define COMPAT_43 45 #include <sys/param.h> 46 #include <sys/ioctl.h> 47 48 #include <stdlib.h> 49 #include <string.h> 50 #include <termios.h> 51 #include <unistd.h> 52 #include <poll.h> 53 54 #include "extern.h" 55 #include "gettytab.h" 56 #include "pathnames.h" 57 58 extern struct termios tmode, omode; 59 60 static void compatflags(long); 61 62 /* 63 * Get a table entry. 64 */ 65 void 66 gettable(char *name, char *buf) 67 { 68 struct gettystrs *sp; 69 struct gettynums *np; 70 struct gettyflags *fp; 71 long n; 72 const char *dba[2]; 73 dba[0] = _PATH_GETTYTAB; 74 dba[1] = 0; 75 76 if (cgetent(&buf, dba, name) != 0) 77 return; 78 79 for (sp = gettystrs; sp->field; sp++) 80 cgetstr(buf, sp->field, &sp->value); 81 for (np = gettynums; np->field; np++) { 82 if (cgetnum(buf, np->field, &n) == -1) 83 np->set = 0; 84 else { 85 np->set = 1; 86 np->value = n; 87 } 88 } 89 for (fp = gettyflags; fp->field; fp++) { 90 if (cgetcap(buf, fp->field, ':') == NULL) 91 fp->set = 0; 92 else { 93 fp->set = 1; 94 fp->value = 1 ^ fp->invrt; 95 } 96 } 97 #ifdef DEBUG 98 printf("name=\"%s\", buf=\"%s\"\n", name, buf); 99 for (sp = gettystrs; sp->field; sp++) 100 printf("cgetstr: %s=%s\n", sp->field, sp->value); 101 for (np = gettynums; np->field; np++) 102 printf("cgetnum: %s=%d\n", np->field, np->value); 103 for (fp = gettyflags; fp->field; fp++) 104 printf("cgetflags: %s='%c' set='%c'\n", fp->field, 105 fp->value + '0', fp->set + '0'); 106 exit(1); 107 #endif /* DEBUG */ 108 } 109 110 void 111 gendefaults(void) 112 { 113 struct gettystrs *sp; 114 struct gettynums *np; 115 struct gettyflags *fp; 116 117 for (sp = gettystrs; sp->field; sp++) 118 if (sp->value) 119 sp->defalt = sp->value; 120 for (np = gettynums; np->field; np++) 121 if (np->set) 122 np->defalt = np->value; 123 for (fp = gettyflags; fp->field; fp++) 124 if (fp->set) 125 fp->defalt = fp->value; 126 else 127 fp->defalt = fp->invrt; 128 } 129 130 void 131 setdefaults(void) 132 { 133 struct gettystrs *sp; 134 struct gettynums *np; 135 struct gettyflags *fp; 136 137 for (sp = gettystrs; sp->field; sp++) 138 if (!sp->value) 139 sp->value = sp->defalt; 140 for (np = gettynums; np->field; np++) 141 if (!np->set) 142 np->value = np->defalt; 143 for (fp = gettyflags; fp->field; fp++) 144 if (!fp->set) 145 fp->value = fp->defalt; 146 } 147 148 static char ** 149 charnames[] = { 150 &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, 151 &SU, &DS, &RP, &FL, &WE, &LN, 0 152 }; 153 154 static char * 155 charvars[] = { 156 &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR], 157 &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP], 158 &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP], 159 &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD], 160 &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0 161 }; 162 163 void 164 setchars(void) 165 { 166 int i; 167 char *p; 168 169 for (i = 0; charnames[i]; i++) { 170 p = *charnames[i]; 171 if (p && *p) 172 *charvars[i] = *p; 173 else 174 *charvars[i] = _POSIX_VDISABLE; 175 } 176 } 177 178 /* Macros to clear/set/test flags. */ 179 #define SET(t, f) (t) |= (f) 180 #define CLR(t, f) (t) &= ~(f) 181 #define ISSET(t, f) ((t) & (f)) 182 183 void 184 setflags(int n) 185 { 186 tcflag_t iflag, oflag, cflag, lflag; 187 188 #ifdef COMPAT_43 189 switch (n) { 190 case 0: 191 if (F0set) { 192 compatflags(F0); 193 return; 194 } 195 break; 196 case 1: 197 if (F1set) { 198 compatflags(F1); 199 return; 200 } 201 break; 202 default: 203 if (F2set) { 204 compatflags(F2); 205 return; 206 } 207 break; 208 } 209 #endif 210 211 switch (n) { 212 case 0: 213 if (C0set && I0set && L0set && O0set) { 214 tmode.c_cflag = C0; 215 tmode.c_iflag = I0; 216 tmode.c_lflag = L0; 217 tmode.c_oflag = O0; 218 return; 219 } 220 break; 221 case 1: 222 if (C1set && I1set && L1set && O1set) { 223 tmode.c_cflag = C1; 224 tmode.c_iflag = I1; 225 tmode.c_lflag = L1; 226 tmode.c_oflag = O1; 227 return; 228 } 229 break; 230 default: 231 if (C2set && I2set && L2set && O2set) { 232 tmode.c_cflag = C2; 233 tmode.c_iflag = I2; 234 tmode.c_lflag = L2; 235 tmode.c_oflag = O2; 236 return; 237 } 238 break; 239 } 240 241 iflag = omode.c_iflag; 242 oflag = omode.c_oflag; 243 cflag = omode.c_cflag; 244 lflag = omode.c_lflag; 245 246 if (NP) { 247 CLR(cflag, CSIZE|PARENB); 248 SET(cflag, CS8); 249 CLR(iflag, ISTRIP|INPCK|IGNPAR); 250 } else if (AP || EP || OP) { 251 CLR(cflag, CSIZE); 252 SET(cflag, CS7|PARENB); 253 SET(iflag, ISTRIP); 254 if (OP && !EP) { 255 SET(iflag, INPCK|IGNPAR); 256 SET(cflag, PARODD); 257 if (AP) 258 CLR(iflag, INPCK); 259 } else if (EP && !OP) { 260 SET(iflag, INPCK|IGNPAR); 261 CLR(cflag, PARODD); 262 if (AP) 263 CLR(iflag, INPCK); 264 } else if (AP || (EP && OP)) { 265 CLR(iflag, INPCK|IGNPAR); 266 CLR(cflag, PARODD); 267 } 268 } /* else, leave as is */ 269 270 #if 0 271 if (UC) 272 f |= LCASE; 273 #endif 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(long flags) 366 { 367 tcflag_t iflag, oflag, cflag, lflag; 368 369 iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY; 370 oflag = OPOST|ONLCR|OXTABS; 371 cflag = CREAD; 372 lflag = ICANON|ISIG|IEXTEN; 373 374 if (ISSET(flags, TANDEM)) 375 SET(iflag, IXOFF); 376 else 377 CLR(iflag, IXOFF); 378 if (ISSET(flags, ECHO)) 379 SET(lflag, ECHO); 380 else 381 CLR(lflag, ECHO); 382 if (ISSET(flags, CRMOD)) { 383 SET(iflag, ICRNL); 384 SET(oflag, ONLCR); 385 } else { 386 CLR(iflag, ICRNL); 387 CLR(oflag, ONLCR); 388 } 389 if (ISSET(flags, XTABS)) 390 SET(oflag, OXTABS); 391 else 392 CLR(oflag, OXTABS); 393 394 395 if (ISSET(flags, RAW)) { 396 iflag &= IXOFF; 397 CLR(lflag, ISIG|ICANON|IEXTEN); 398 CLR(cflag, PARENB); 399 } else { 400 SET(iflag, BRKINT|IXON|IMAXBEL); 401 SET(lflag, ISIG|IEXTEN); 402 if (ISSET(flags, CBREAK)) 403 CLR(lflag, ICANON); 404 else 405 SET(lflag, ICANON); 406 switch (ISSET(flags, ANYP)) { 407 case 0: 408 CLR(cflag, PARENB); 409 break; 410 case ANYP: 411 SET(cflag, PARENB); 412 CLR(iflag, INPCK); 413 break; 414 case EVENP: 415 SET(cflag, PARENB); 416 SET(iflag, INPCK); 417 CLR(cflag, PARODD); 418 break; 419 case ODDP: 420 SET(cflag, PARENB); 421 SET(iflag, INPCK); 422 SET(cflag, PARODD); 423 break; 424 } 425 } 426 427 /* Nothing we can do with CRTBS. */ 428 if (ISSET(flags, PRTERA)) 429 SET(lflag, ECHOPRT); 430 else 431 CLR(lflag, ECHOPRT); 432 if (ISSET(flags, CRTERA)) 433 SET(lflag, ECHOE); 434 else 435 CLR(lflag, ECHOE); 436 /* Nothing we can do with TILDE. */ 437 if (ISSET(flags, MDMBUF)) 438 SET(cflag, MDMBUF); 439 else 440 CLR(cflag, MDMBUF); 441 if (ISSET(flags, NOHANG)) 442 CLR(cflag, HUPCL); 443 else 444 SET(cflag, HUPCL); 445 if (ISSET(flags, CRTKIL)) 446 SET(lflag, ECHOKE); 447 else 448 CLR(lflag, ECHOKE); 449 if (ISSET(flags, CTLECH)) 450 SET(lflag, ECHOCTL); 451 else 452 CLR(lflag, ECHOCTL); 453 if (!ISSET(flags, DECCTQ)) 454 SET(iflag, IXANY); 455 else 456 CLR(iflag, IXANY); 457 CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH); 458 SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH)); 459 460 if (ISSET(flags, RAW|LITOUT|PASS8)) { 461 CLR(cflag, CSIZE); 462 SET(cflag, CS8); 463 if (!ISSET(flags, RAW|PASS8)) 464 SET(iflag, ISTRIP); 465 else 466 CLR(iflag, ISTRIP); 467 if (!ISSET(flags, RAW|LITOUT)) 468 SET(oflag, OPOST); 469 else 470 CLR(oflag, OPOST); 471 } else { 472 CLR(cflag, CSIZE); 473 SET(cflag, CS7); 474 SET(iflag, ISTRIP); 475 SET(oflag, OPOST); 476 } 477 478 tmode.c_iflag = iflag; 479 tmode.c_oflag = oflag; 480 tmode.c_cflag = cflag; 481 tmode.c_lflag = lflag; 482 } 483 #endif 484 485 #ifdef XXX_DELAY 486 struct delayval { 487 unsigned delay; /* delay in ms */ 488 int bits; 489 }; 490 491 /* 492 * below are random guesses, I can't be bothered checking 493 */ 494 495 struct delayval crdelay[] = { 496 { 1, CR1 }, 497 { 2, CR2 }, 498 { 3, CR3 }, 499 { 83, CR1 }, 500 { 166, CR2 }, 501 { 0, CR3 }, 502 }; 503 504 struct delayval nldelay[] = { 505 { 1, NL1 }, /* special, calculated */ 506 { 2, NL2 }, 507 { 3, NL3 }, 508 { 100, NL2 }, 509 { 0, NL3 }, 510 }; 511 512 struct delayval bsdelay[] = { 513 { 1, BS1 }, 514 { 0, 0 }, 515 }; 516 517 struct delayval ffdelay[] = { 518 { 1, FF1 }, 519 { 1750, FF1 }, 520 { 0, FF1 }, 521 }; 522 523 struct delayval tbdelay[] = { 524 { 1, TAB1 }, 525 { 2, TAB2 }, 526 { 3, XTABS }, /* this is expand tabs */ 527 { 100, TAB1 }, 528 { 0, TAB2 }, 529 }; 530 531 int 532 delaybits(void) 533 { 534 int f; 535 536 f = adelay(CD, crdelay); 537 f |= adelay(ND, nldelay); 538 f |= adelay(FD, ffdelay); 539 f |= adelay(TD, tbdelay); 540 f |= adelay(BD, bsdelay); 541 return (f); 542 } 543 544 int 545 adelay(int ms, struct delayval *dp) 546 { 547 if (ms == 0) 548 return (0); 549 while (dp->delay && ms > dp->delay) 550 dp++; 551 return (dp->bits); 552 } 553 #endif 554 555 char editedhost[MAXHOSTNAMELEN]; 556 557 void 558 edithost(char *pat) 559 { 560 char *host = HN; 561 char *res = editedhost; 562 563 if (!pat) 564 pat = ""; 565 while (*pat) { 566 switch (*pat) { 567 568 case '#': 569 if (*host) 570 host++; 571 break; 572 573 case '@': 574 if (*host) 575 *res++ = *host++; 576 break; 577 578 default: 579 *res++ = *pat; 580 break; 581 582 } 583 if (res == &editedhost[sizeof editedhost - 1]) { 584 *res = '\0'; 585 return; 586 } 587 pat++; 588 } 589 if (*host) 590 strncpy(res, host, sizeof editedhost - (res - editedhost) - 1); 591 else 592 *res = '\0'; 593 editedhost[sizeof editedhost - 1] = '\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) != NULL) { 609 q = p; 610 while ((q = strchr(q, ',')) != NULL) { 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 struct pollfd set[1]; 683 struct timespec timeout; 684 char c, *type = "9600-baud"; 685 686 (void)tcflush(0, TCIOFLUSH); 687 set[0].fd = STDIN_FILENO; 688 set[0].events = POLLIN; 689 if (poll(set, 1, 5000) <= 0) 690 return (type); 691 if (read(STDIN_FILENO, &c, 1) != 1) 692 return (type); 693 timeout.tv_sec = 0; 694 timeout.tv_nsec = 20000; 695 (void)nanosleep(&timeout, NULL); 696 (void)tcflush(0, TCIOFLUSH); 697 switch (c & 0377) { 698 699 case 0200: /* 300-baud */ 700 type = "300-baud"; 701 break; 702 703 case 0346: /* 1200-baud */ 704 type = "1200-baud"; 705 break; 706 707 case 015: /* 2400-baud */ 708 case 0215: 709 type = "2400-baud"; 710 break; 711 712 default: /* 4800-baud */ 713 type = "4800-baud"; 714 break; 715 716 case 0377: /* 9600-baud */ 717 type = "9600-baud"; 718 break; 719 } 720 return (type); 721 } 722