1 /*- 2 * Copyright (c) 1980, 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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 static const char copyright[] = 32 "@(#) Copyright (c) 1980, 1993\n\ 33 The Regents of the University of California. All rights reserved.\n"; 34 #endif /* not lint */ 35 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)from: main.c 8.1 (Berkeley) 6/20/93"; 39 #endif 40 #endif /* not lint */ 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/param.h> 45 #include <sys/ioctl.h> 46 #include <sys/time.h> 47 #include <sys/resource.h> 48 #include <sys/stat.h> 49 #include <sys/ttydefaults.h> 50 #include <sys/utsname.h> 51 52 #include <ctype.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <locale.h> 56 #include <libutil.h> 57 #include <setjmp.h> 58 #include <signal.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <syslog.h> 62 #include <termios.h> 63 #include <time.h> 64 #include <unistd.h> 65 66 #include "gettytab.h" 67 #include "extern.h" 68 #include "pathnames.h" 69 70 /* 71 * Set the amount of running time that getty should accumulate 72 * before deciding that something is wrong and exit. 73 */ 74 #define GETTY_TIMEOUT 60 /* seconds */ 75 76 #undef CTRL 77 #define CTRL(x) (x&037) 78 79 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ 80 81 #define PPP_FRAME 0x7e /* PPP Framing character */ 82 #define PPP_STATION 0xff /* "All Station" character */ 83 #define PPP_ESCAPE 0x7d /* Escape Character */ 84 #define PPP_CONTROL 0x03 /* PPP Control Field */ 85 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ 86 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ 87 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ 88 89 /* original mode; flags've been reset using values from <sys/ttydefaults.h> */ 90 struct termios omode; 91 /* current mode */ 92 struct termios tmode; 93 94 int crmod, digit, lower, upper; 95 96 char hostname[MAXHOSTNAMELEN]; 97 char name[MAXLOGNAME*3]; 98 char dev[] = _PATH_DEV; 99 char ttyn[32]; 100 101 #define OBUFSIZ 128 102 #define TABBUFSIZ 512 103 104 char defent[TABBUFSIZ]; 105 char tabent[TABBUFSIZ]; 106 const char *tname; 107 108 char *env[128]; 109 110 char partab[] = { 111 0001,0201,0201,0001,0201,0001,0001,0201, 112 0202,0004,0003,0205,0005,0206,0201,0001, 113 0201,0001,0001,0201,0001,0201,0201,0001, 114 0001,0201,0201,0001,0201,0001,0001,0201, 115 0200,0000,0000,0200,0000,0200,0200,0000, 116 0000,0200,0200,0000,0200,0000,0000,0200, 117 0000,0200,0200,0000,0200,0000,0000,0200, 118 0200,0000,0000,0200,0000,0200,0200,0000, 119 0200,0000,0000,0200,0000,0200,0200,0000, 120 0000,0200,0200,0000,0200,0000,0000,0200, 121 0000,0200,0200,0000,0200,0000,0000,0200, 122 0200,0000,0000,0200,0000,0200,0200,0000, 123 0000,0200,0200,0000,0200,0000,0000,0200, 124 0200,0000,0000,0200,0000,0200,0200,0000, 125 0200,0000,0000,0200,0000,0200,0200,0000, 126 0000,0200,0200,0000,0200,0000,0000,0201 127 }; 128 129 #define ERASE tmode.c_cc[VERASE] 130 #define KILL tmode.c_cc[VKILL] 131 #define EOT tmode.c_cc[VEOF] 132 133 #define puts Gputs 134 135 static void defttymode(void); 136 static void dingdong(int); 137 static void dogettytab(void); 138 static int getname(void); 139 static void interrupt(int); 140 static void oflush(void); 141 static void prompt(void); 142 static void putchr(int); 143 static void putf(const char *); 144 static void putpad(const char *); 145 static void puts(const char *); 146 static void timeoverrun(int); 147 static char *getline(int); 148 static void setttymode(int); 149 static int opentty(const char *, int); 150 151 jmp_buf timeout; 152 153 static void 154 dingdong(int signo __unused) 155 { 156 alarm(0); 157 longjmp(timeout, 1); 158 } 159 160 jmp_buf intrupt; 161 162 static void 163 interrupt(int signo __unused) 164 { 165 longjmp(intrupt, 1); 166 } 167 168 /* 169 * Action to take when getty is running too long. 170 */ 171 static void 172 timeoverrun(int signo __unused) 173 { 174 175 syslog(LOG_ERR, "getty exiting due to excessive running time"); 176 exit(1); 177 } 178 179 int 180 main(int argc, char *argv[]) 181 { 182 extern char **environ; 183 int first_sleep = 1, first_time = 1; 184 struct rlimit limit; 185 int rval; 186 187 signal(SIGINT, SIG_IGN); 188 signal(SIGQUIT, SIG_IGN); 189 190 openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH); 191 gethostname(hostname, sizeof(hostname) - 1); 192 hostname[sizeof(hostname) - 1] = '\0'; 193 if (hostname[0] == '\0') 194 strcpy(hostname, "Amnesiac"); 195 196 /* 197 * Limit running time to deal with broken or dead lines. 198 */ 199 (void)signal(SIGXCPU, timeoverrun); 200 limit.rlim_max = RLIM_INFINITY; 201 limit.rlim_cur = GETTY_TIMEOUT; 202 (void)setrlimit(RLIMIT_CPU, &limit); 203 204 gettable("default", defent); 205 gendefaults(); 206 tname = "default"; 207 if (argc > 1) 208 tname = argv[1]; 209 210 /* 211 * The following is a work around for vhangup interactions 212 * which cause great problems getting window systems started. 213 * If the tty line is "-", we do the old style getty presuming 214 * that the file descriptors are already set up for us. 215 * J. Gettys - MIT Project Athena. 216 */ 217 if (argc <= 2 || strcmp(argv[2], "-") == 0) 218 strcpy(ttyn, ttyname(STDIN_FILENO)); 219 else { 220 strcpy(ttyn, dev); 221 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 222 if (strcmp(argv[0], "+") != 0) { 223 chown(ttyn, 0, 0); 224 chmod(ttyn, 0600); 225 revoke(ttyn); 226 227 /* 228 * Do the first scan through gettytab. 229 * Terminal mode parameters will be wrong until 230 * defttymode() called, but they're irrelevant for 231 * the initial setup of the terminal device. 232 */ 233 dogettytab(); 234 235 /* 236 * Init or answer modem sequence has been specified. 237 */ 238 if (IC || AC) { 239 if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) 240 exit(1); 241 defttymode(); 242 setttymode(1); 243 } 244 245 if (IC) { 246 if (getty_chat(IC, CT, DC) > 0) { 247 syslog(LOG_ERR, "modem init problem on %s", ttyn); 248 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 249 exit(1); 250 } 251 } 252 253 if (AC) { 254 int i, rfds; 255 struct timeval to; 256 257 rfds = 1 << 0; /* FD_SET */ 258 to.tv_sec = RT; 259 to.tv_usec = 0; 260 i = select(32, (fd_set*)&rfds, (fd_set*)NULL, 261 (fd_set*)NULL, RT ? &to : NULL); 262 if (i < 0) { 263 syslog(LOG_ERR, "select %s: %m", ttyn); 264 } else if (i == 0) { 265 syslog(LOG_NOTICE, "recycle tty %s", ttyn); 266 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 267 exit(0); /* recycle for init */ 268 } 269 i = getty_chat(AC, CT, DC); 270 if (i > 0) { 271 syslog(LOG_ERR, "modem answer problem on %s", ttyn); 272 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 273 exit(1); 274 } 275 } else { /* maybe blocking open */ 276 if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 ))) 277 exit(1); 278 } 279 } 280 } 281 282 defttymode(); 283 for (;;) { 284 285 /* 286 * if a delay was specified then sleep for that 287 * number of seconds before writing the initial prompt 288 */ 289 if (first_sleep && DE) { 290 sleep(DE); 291 /* remove any noise */ 292 (void)tcflush(STDIN_FILENO, TCIOFLUSH); 293 } 294 first_sleep = 0; 295 296 setttymode(0); 297 if (AB) { 298 tname = autobaud(); 299 dogettytab(); 300 continue; 301 } 302 if (PS) { 303 tname = portselector(); 304 dogettytab(); 305 continue; 306 } 307 if (CL && *CL) 308 putpad(CL); 309 edithost(HE); 310 311 /* if this is the first time through this, and an 312 issue file has been given, then send it */ 313 if (first_time && IF) { 314 int fd; 315 316 if ((fd = open(IF, O_RDONLY)) != -1) { 317 char * cp; 318 319 while ((cp = getline(fd)) != NULL) { 320 putf(cp); 321 } 322 close(fd); 323 } 324 } 325 first_time = 0; 326 327 if (IMP && *IMP && !(PL && PP)) 328 system(IMP); 329 if (IM && *IM && !(PL && PP)) 330 putf(IM); 331 if (setjmp(timeout)) { 332 cfsetispeed(&tmode, B0); 333 cfsetospeed(&tmode, B0); 334 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 335 exit(1); 336 } 337 if (TO) { 338 signal(SIGALRM, dingdong); 339 alarm(TO); 340 } 341 342 rval = 0; 343 if (AL) { 344 const char *p = AL; 345 char *q = name; 346 347 while (*p && q < &name[sizeof name - 1]) { 348 if (isupper(*p)) 349 upper = 1; 350 else if (islower(*p)) 351 lower = 1; 352 else if (isdigit(*p)) 353 digit = 1; 354 *q++ = *p++; 355 } 356 } else if (!(PL && PP)) 357 rval = getname(); 358 if (rval == 2 || (PL && PP)) { 359 oflush(); 360 alarm(0); 361 limit.rlim_max = RLIM_INFINITY; 362 limit.rlim_cur = RLIM_INFINITY; 363 (void)setrlimit(RLIMIT_CPU, &limit); 364 execle(PP, "ppplogin", ttyn, (char *) 0, env); 365 syslog(LOG_ERR, "%s: %m", PP); 366 exit(1); 367 } else if (rval || AL) { 368 int i; 369 370 oflush(); 371 alarm(0); 372 signal(SIGALRM, SIG_DFL); 373 if (name[0] == '\0') 374 continue; 375 if (name[0] == '-') { 376 puts("user names may not start with '-'."); 377 continue; 378 } 379 if (!(upper || lower || digit)) { 380 if (AL) { 381 syslog(LOG_ERR, 382 "invalid auto-login name: %s", AL); 383 exit(1); 384 } else 385 continue; 386 } 387 set_flags(2); 388 if (crmod) { 389 tmode.c_iflag |= ICRNL; 390 tmode.c_oflag |= ONLCR; 391 } 392 #if REALLY_OLD_TTYS 393 if (upper || UC) 394 tmode.sg_flags |= LCASE; 395 if (lower || LC) 396 tmode.sg_flags &= ~LCASE; 397 #endif 398 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 399 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); 400 exit(1); 401 } 402 signal(SIGINT, SIG_DFL); 403 for (i = 0; environ[i] != (char *)0; i++) 404 env[i] = environ[i]; 405 makeenv(&env[i]); 406 407 limit.rlim_max = RLIM_INFINITY; 408 limit.rlim_cur = RLIM_INFINITY; 409 (void)setrlimit(RLIMIT_CPU, &limit); 410 execle(LO, "login", AL ? "-fp" : "-p", name, 411 (char *) 0, env); 412 syslog(LOG_ERR, "%s: %m", LO); 413 exit(1); 414 } 415 alarm(0); 416 signal(SIGALRM, SIG_DFL); 417 signal(SIGINT, SIG_IGN); 418 if (NX && *NX) { 419 tname = NX; 420 dogettytab(); 421 } 422 } 423 } 424 425 static int 426 opentty(const char *tty, int flags) 427 { 428 int i; 429 int failopenlogged = 0; 430 431 while ((i = open(tty, flags)) == -1) 432 { 433 if (!failopenlogged) { 434 syslog(LOG_ERR, "open %s: %m", tty); 435 failopenlogged = 1; 436 } 437 sleep(60); 438 } 439 if (login_tty(i) < 0) { 440 if (daemon(0,0) < 0) { 441 syslog(LOG_ERR,"daemon: %m"); 442 close(i); 443 return 0; 444 } 445 if (login_tty(i) < 0) { 446 syslog(LOG_ERR, "login_tty %s: %m", tty); 447 close(i); 448 return 0; 449 } 450 } 451 return 1; 452 } 453 454 static void 455 defttymode(void) 456 { 457 struct termios def; 458 459 /* Start with default tty settings. */ 460 if (tcgetattr(STDIN_FILENO, &tmode) < 0) { 461 syslog(LOG_ERR, "tcgetattr %s: %m", ttyn); 462 exit(1); 463 } 464 omode = tmode; /* fill c_cc for dogettytab() */ 465 dogettytab(); 466 /* 467 * Don't rely on the driver too much, and initialize crucial 468 * things according to <sys/ttydefaults.h>. Avoid clobbering 469 * the c_cc[] settings however, the console drivers might wish 470 * to leave their idea of the preferred VERASE key value 471 * there. 472 */ 473 cfmakesane(&def); 474 tmode.c_iflag = def.c_iflag; 475 tmode.c_oflag = def.c_oflag; 476 tmode.c_lflag = def.c_lflag; 477 tmode.c_cflag = def.c_cflag; 478 if (NC) 479 tmode.c_cflag |= CLOCAL; 480 omode = tmode; 481 } 482 483 static void 484 setttymode(int raw) 485 { 486 int off = 0; 487 488 (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */ 489 ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */ 490 ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */ 491 492 if (IS) 493 cfsetispeed(&tmode, speed(IS)); 494 else if (SP) 495 cfsetispeed(&tmode, speed(SP)); 496 if (OS) 497 cfsetospeed(&tmode, speed(OS)); 498 else if (SP) 499 cfsetospeed(&tmode, speed(SP)); 500 set_flags(0); 501 setchars(); 502 if (raw) 503 cfmakeraw(&tmode); 504 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 505 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); 506 exit(1); 507 } 508 } 509 510 511 static int 512 getname(void) 513 { 514 int c; 515 char *np; 516 unsigned char cs; 517 int ppp_state = 0; 518 int ppp_connection = 0; 519 520 /* 521 * Interrupt may happen if we use CBREAK mode 522 */ 523 if (setjmp(intrupt)) { 524 signal(SIGINT, SIG_IGN); 525 return (0); 526 } 527 signal(SIGINT, interrupt); 528 set_flags(1); 529 prompt(); 530 oflush(); 531 if (PF > 0) { 532 sleep(PF); 533 PF = 0; 534 } 535 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 536 syslog(LOG_ERR, "%s: %m", ttyn); 537 exit(1); 538 } 539 crmod = digit = lower = upper = 0; 540 np = name; 541 for (;;) { 542 oflush(); 543 if (read(STDIN_FILENO, &cs, 1) <= 0) 544 exit(0); 545 if ((c = cs&0177) == 0) 546 return (0); 547 548 /* PPP detection state machine.. 549 Look for sequences: 550 PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 551 PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 552 See RFC1662. 553 Derived from code from Michael Hancock, <michaelh@cet.co.jp> 554 and Erik 'PPP' Olson, <eriko@wrq.com> 555 */ 556 557 if (PP && (cs == PPP_FRAME)) { 558 ppp_state = 1; 559 } else if (ppp_state == 1 && cs == PPP_STATION) { 560 ppp_state = 2; 561 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 562 ppp_state = 3; 563 } else if ((ppp_state == 2 && cs == PPP_CONTROL) 564 || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 565 ppp_state = 4; 566 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 567 ppp_state = 5; 568 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 569 ppp_connection = 1; 570 break; 571 } else { 572 ppp_state = 0; 573 } 574 575 if (c == EOT || c == CTRL('d')) 576 exit(0); 577 if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) { 578 putf("\r\n"); 579 break; 580 } 581 if (islower(c)) 582 lower = 1; 583 else if (isupper(c)) 584 upper = 1; 585 else if (c == ERASE || c == '\b' || c == 0177) { 586 if (np > name) { 587 np--; 588 if (cfgetospeed(&tmode) >= 1200) 589 puts("\b \b"); 590 else 591 putchr(cs); 592 } 593 continue; 594 } else if (c == KILL || c == CTRL('u')) { 595 putchr('\r'); 596 if (cfgetospeed(&tmode) < 1200) 597 putchr('\n'); 598 /* this is the way they do it down under ... */ 599 else if (np > name) 600 puts(" \r"); 601 prompt(); 602 digit = lower = upper = 0; 603 np = name; 604 continue; 605 } else if (isdigit(c)) 606 digit = 1; 607 if (IG && (c <= ' ' || c > 0176)) 608 continue; 609 *np++ = c; 610 putchr(cs); 611 } 612 signal(SIGINT, SIG_IGN); 613 *np = 0; 614 if (c == '\r') 615 crmod = 1; 616 if ((upper && !lower && !LC) || UC) 617 for (np = name; *np; np++) 618 if (isupper(*np)) 619 *np = tolower(*np); 620 return (1 + ppp_connection); 621 } 622 623 static void 624 putpad(const char *s) 625 { 626 int pad = 0; 627 speed_t ospeed = cfgetospeed(&tmode); 628 629 if (isdigit(*s)) { 630 while (isdigit(*s)) { 631 pad *= 10; 632 pad += *s++ - '0'; 633 } 634 pad *= 10; 635 if (*s == '.' && isdigit(s[1])) { 636 pad += s[1] - '0'; 637 s += 2; 638 } 639 } 640 641 puts(s); 642 /* 643 * If no delay needed, or output speed is 644 * not comprehensible, then don't try to delay. 645 */ 646 if (pad == 0 || ospeed <= 0) 647 return; 648 649 /* 650 * Round up by a half a character frame, and then do the delay. 651 * Too bad there are no user program accessible programmed delays. 652 * Transmitting pad characters slows many terminals down and also 653 * loads the system. 654 */ 655 pad = (pad * ospeed + 50000) / 100000; 656 while (pad--) 657 putchr(*PC); 658 } 659 660 static void 661 puts(const char *s) 662 { 663 while (*s) 664 putchr(*s++); 665 } 666 667 char outbuf[OBUFSIZ]; 668 int obufcnt = 0; 669 670 static void 671 putchr(int cc) 672 { 673 char c; 674 675 c = cc; 676 if (!NP) { 677 c |= partab[c&0177] & 0200; 678 if (OP) 679 c ^= 0200; 680 } 681 if (!UB) { 682 outbuf[obufcnt++] = c; 683 if (obufcnt >= OBUFSIZ) 684 oflush(); 685 } else 686 write(STDOUT_FILENO, &c, 1); 687 } 688 689 static void 690 oflush(void) 691 { 692 if (obufcnt) 693 write(STDOUT_FILENO, outbuf, obufcnt); 694 obufcnt = 0; 695 } 696 697 static void 698 prompt(void) 699 { 700 701 putf(LM); 702 if (CO) 703 putchr('\n'); 704 } 705 706 707 static char * 708 getline(int fd) 709 { 710 int i = 0; 711 static char linebuf[512]; 712 713 /* 714 * This is certainly slow, but it avoids having to include 715 * stdio.h unnecessarily. Issue files should be small anyway. 716 */ 717 while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) { 718 if (linebuf[i] == '\n') { 719 /* Don't rely on newline mode, assume raw */ 720 linebuf[i++] = '\r'; 721 linebuf[i++] = '\n'; 722 linebuf[i] = '\0'; 723 return linebuf; 724 } 725 ++i; 726 } 727 linebuf[i] = '\0'; 728 return i ? linebuf : 0; 729 } 730 731 static void 732 putf(const char *cp) 733 { 734 extern char editedhost[]; 735 time_t t; 736 char *slash, db[100]; 737 738 static struct utsname kerninfo; 739 740 if (!*kerninfo.sysname) 741 uname(&kerninfo); 742 743 while (*cp) { 744 if (*cp != '%') { 745 putchr(*cp++); 746 continue; 747 } 748 switch (*++cp) { 749 750 case 't': 751 slash = strrchr(ttyn, '/'); 752 if (slash == (char *) 0) 753 puts(ttyn); 754 else 755 puts(&slash[1]); 756 break; 757 758 case 'h': 759 puts(editedhost); 760 break; 761 762 case 'd': { 763 t = (time_t)0; 764 (void)time(&t); 765 if (Lo) 766 (void)setlocale(LC_TIME, Lo); 767 (void)strftime(db, sizeof(db), DF, localtime(&t)); 768 puts(db); 769 break; 770 771 case 's': 772 puts(kerninfo.sysname); 773 break; 774 775 case 'm': 776 puts(kerninfo.machine); 777 break; 778 779 case 'r': 780 puts(kerninfo.release); 781 break; 782 783 case 'v': 784 puts(kerninfo.version); 785 break; 786 } 787 788 case '%': 789 putchr('%'); 790 break; 791 } 792 cp++; 793 } 794 } 795 796 /* 797 * Read a gettytab database entry and perform necessary quirks. 798 */ 799 static void 800 dogettytab(void) 801 { 802 803 /* Read the database entry. */ 804 gettable(tname, tabent); 805 806 /* 807 * Avoid inheriting the parity values from the default entry 808 * if any of them is set in the current entry. 809 * Mixing different parity settings is unreasonable. 810 */ 811 if (OPset || EPset || APset || NPset) 812 OPset = EPset = APset = NPset = 1; 813 814 /* Fill in default values for unset capabilities. */ 815 setdefaults(); 816 } 817