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