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