1 /* $NetBSD: subr.c,v 1.33 2006/11/16 04:31:24 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.33 2006/11/16 04:31:24 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 (void)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, &ST, &B2, 0 152 }; 153 154 static cc_t * 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], &tmode.c_cc[VSTATUS], 161 &tmode.c_cc[VEOL2], 0 162 }; 163 164 void 165 setchars(void) 166 { 167 int i; 168 char *p; 169 170 for (i = 0; charnames[i]; i++) { 171 p = *charnames[i]; 172 if (p && *p) 173 *charvars[i] = *p; 174 else 175 *charvars[i] = _POSIX_VDISABLE; 176 } 177 } 178 179 /* Macros to clear/set/test flags. */ 180 #define SET(t, f) (t) |= (f) 181 #define CLR(t, f) (t) &= ~(f) 182 #define ISSET(t, f) ((t) & (f)) 183 184 void 185 setflags(int n) 186 { 187 tcflag_t iflag, oflag, cflag, lflag; 188 189 #ifdef COMPAT_43 190 switch (n) { 191 case 0: 192 if (F0set) { 193 compatflags(F0); 194 return; 195 } 196 break; 197 case 1: 198 if (F1set) { 199 compatflags(F1); 200 return; 201 } 202 break; 203 default: 204 if (F2set) { 205 compatflags(F2); 206 return; 207 } 208 break; 209 } 210 #endif 211 212 switch (n) { 213 case 0: 214 if (C0set && I0set && L0set && O0set) { 215 tmode.c_cflag = C0; 216 tmode.c_iflag = I0; 217 tmode.c_lflag = L0; 218 tmode.c_oflag = O0; 219 return; 220 } 221 break; 222 case 1: 223 if (C1set && I1set && L1set && O1set) { 224 tmode.c_cflag = C1; 225 tmode.c_iflag = I1; 226 tmode.c_lflag = L1; 227 tmode.c_oflag = O1; 228 return; 229 } 230 break; 231 default: 232 if (C2set && I2set && L2set && O2set) { 233 tmode.c_cflag = C2; 234 tmode.c_iflag = I2; 235 tmode.c_lflag = L2; 236 tmode.c_oflag = O2; 237 return; 238 } 239 break; 240 } 241 242 iflag = omode.c_iflag; 243 oflag = omode.c_oflag; 244 cflag = omode.c_cflag; 245 lflag = omode.c_lflag; 246 247 if (NP) { 248 CLR(cflag, CSIZE|PARENB); 249 SET(cflag, CS8); 250 CLR(iflag, ISTRIP|INPCK|IGNPAR); 251 } else if (AP || EP || OP) { 252 CLR(cflag, CSIZE); 253 SET(cflag, CS7|PARENB); 254 SET(iflag, ISTRIP); 255 if (OP && !EP) { 256 SET(iflag, INPCK|IGNPAR); 257 SET(cflag, PARODD); 258 if (AP) 259 CLR(iflag, INPCK); 260 } else if (EP && !OP) { 261 SET(iflag, INPCK|IGNPAR); 262 CLR(cflag, PARODD); 263 if (AP) 264 CLR(iflag, INPCK); 265 } else if (AP || (EP && OP)) { 266 CLR(iflag, INPCK|IGNPAR); 267 CLR(cflag, PARODD); 268 } 269 } /* else, leave as is */ 270 271 #if 0 272 if (UC) 273 f |= LCASE; 274 #endif 275 276 if (HC) 277 SET(cflag, HUPCL); 278 else 279 CLR(cflag, HUPCL); 280 281 if (MB) 282 SET(cflag, MDMBUF); 283 else 284 CLR(cflag, MDMBUF); 285 286 if (NL) { 287 SET(iflag, ICRNL); 288 SET(oflag, ONLCR|OPOST); 289 } else { 290 CLR(iflag, ICRNL); 291 CLR(oflag, ONLCR); 292 } 293 294 if (!HT) 295 SET(oflag, OXTABS|OPOST); 296 else 297 CLR(oflag, OXTABS); 298 299 #ifdef XXX_DELAY 300 SET(f, delaybits()); 301 #endif 302 303 if (n == 1) { /* read mode flags */ 304 if (RW) { 305 iflag = 0; 306 CLR(oflag, OPOST); 307 CLR(cflag, CSIZE|PARENB); 308 SET(cflag, CS8); 309 lflag = 0; 310 } else { 311 CLR(lflag, ICANON); 312 } 313 goto out; 314 } 315 316 if (n == 0) 317 goto out; 318 319 #if 0 320 if (CB) 321 SET(f, CRTBS); 322 #endif 323 324 if (CE) 325 SET(lflag, ECHOE); 326 else 327 CLR(lflag, ECHOE); 328 329 if (CK) 330 SET(lflag, ECHOKE); 331 else 332 CLR(lflag, ECHOKE); 333 334 if (PE) 335 SET(lflag, ECHOPRT); 336 else 337 CLR(lflag, ECHOPRT); 338 339 if (EC) 340 SET(lflag, ECHO); 341 else 342 CLR(lflag, ECHO); 343 344 if (XC) 345 SET(lflag, ECHOCTL); 346 else 347 CLR(lflag, ECHOCTL); 348 349 if (DX) 350 SET(lflag, IXANY); 351 else 352 CLR(lflag, IXANY); 353 354 out: 355 tmode.c_iflag = iflag; 356 tmode.c_oflag = oflag; 357 tmode.c_cflag = cflag; 358 tmode.c_lflag = lflag; 359 } 360 361 #ifdef COMPAT_43 362 /* 363 * Old TTY => termios, snatched from <sys/kern/tty_compat.c> 364 */ 365 void 366 compatflags(long flags) 367 { 368 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 395 396 if (ISSET(flags, RAW)) { 397 iflag &= IXOFF; 398 CLR(lflag, ISIG|ICANON|IEXTEN); 399 CLR(cflag, PARENB); 400 } else { 401 SET(iflag, BRKINT|IXON|IMAXBEL); 402 SET(lflag, ISIG|IEXTEN); 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 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(void) 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[MAXHOSTNAMELEN]; 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 (void)strncpy(res, host, 592 sizeof editedhost - (res - editedhost) - 1); 593 else 594 *res = '\0'; 595 editedhost[sizeof editedhost - 1] = '\0'; 596 } 597 598 void 599 makeenv(char *env[]) 600 { 601 static char termbuf[128] = "TERM="; 602 char *p, *q; 603 char **ep; 604 605 ep = env; 606 if (TT && *TT) { 607 (void)strlcat(termbuf, TT, sizeof(termbuf)); 608 *ep++ = termbuf; 609 } 610 if ((p = EV) != NULL) { 611 q = p; 612 while ((q = strchr(q, ',')) != NULL) { 613 *q++ = '\0'; 614 *ep++ = p; 615 p = q; 616 } 617 if (*p) 618 *ep++ = p; 619 } 620 *ep = (char *)0; 621 } 622 623 /* 624 * This speed select mechanism is written for the Develcon DATASWITCH. 625 * The Develcon sends a string of the form "B{speed}\n" at a predefined 626 * baud rate. This string indicates the user's actual speed. 627 * The routine below returns the terminal type mapped from derived speed. 628 */ 629 struct portselect { 630 char *ps_baud; 631 char *ps_type; 632 } portspeeds[] = { 633 { "B110", "std.110" }, 634 { "B134", "std.134" }, 635 { "B150", "std.150" }, 636 { "B300", "std.300" }, 637 { "B600", "std.600" }, 638 { "B1200", "std.1200" }, 639 { "B2400", "std.2400" }, 640 { "B4800", "std.4800" }, 641 { "B9600", "std.9600" }, 642 { "B19200", "std.19200" }, 643 { 0 } 644 }; 645 646 char * 647 portselector(void) 648 { 649 char c, baud[20], *type = "default"; 650 struct portselect *ps; 651 int len; 652 653 (void)alarm(5*60); 654 for (len = 0; len < sizeof (baud) - 1; len++) { 655 if (read(STDIN_FILENO, &c, 1) <= 0) 656 break; 657 c &= 0177; 658 if (c == '\n' || c == '\r') 659 break; 660 if (c == 'B') 661 len = 0; /* in case of leading garbage */ 662 baud[len] = c; 663 } 664 baud[len] = '\0'; 665 for (ps = portspeeds; ps->ps_baud; ps++) 666 if (strcmp(ps->ps_baud, baud) == 0) { 667 type = ps->ps_type; 668 break; 669 } 670 (void)sleep(2); /* wait for connection to complete */ 671 return (type); 672 } 673 674 /* 675 * This auto-baud speed select mechanism is written for the Micom 600 676 * portselector. Selection is done by looking at how the character '\r' 677 * is garbled at the different speeds. 678 */ 679 #include <sys/time.h> 680 681 char * 682 autobaud(void) 683 { 684 struct pollfd set[1]; 685 struct timespec timeout; 686 char c, *type = "9600-baud"; 687 688 (void)tcflush(0, TCIOFLUSH); 689 set[0].fd = STDIN_FILENO; 690 set[0].events = POLLIN; 691 if (poll(set, 1, 5000) <= 0) 692 return (type); 693 if (read(STDIN_FILENO, &c, 1) != 1) 694 return (type); 695 timeout.tv_sec = 0; 696 timeout.tv_nsec = 20000; 697 (void)nanosleep(&timeout, NULL); 698 (void)tcflush(0, TCIOFLUSH); 699 switch (c & 0377) { 700 701 case 0200: /* 300-baud */ 702 type = "300-baud"; 703 break; 704 705 case 0346: /* 1200-baud */ 706 type = "1200-baud"; 707 break; 708 709 case 015: /* 2400-baud */ 710 case 0215: 711 type = "2400-baud"; 712 break; 713 714 default: /* 4800-baud */ 715 type = "4800-baud"; 716 break; 717 718 case 0377: /* 9600-baud */ 719 type = "9600-baud"; 720 break; 721 } 722 return (type); 723 } 724