1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 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 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1980, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #endif /* not lint */ 40 #include <sys/cdefs.h> 41 #include <sys/param.h> 42 #include <sys/ioctl.h> 43 #include <sys/time.h> 44 #include <sys/resource.h> 45 #include <sys/stat.h> 46 #include <sys/ttydefaults.h> 47 #include <sys/utsname.h> 48 49 #include <ctype.h> 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <locale.h> 53 #include <libutil.h> 54 #include <setjmp.h> 55 #include <signal.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <syslog.h> 60 #include <termios.h> 61 #include <time.h> 62 #include <unistd.h> 63 64 #include "gettytab.h" 65 #include "extern.h" 66 #include "pathnames.h" 67 68 /* 69 * Set the amount of running time that getty should accumulate 70 * before deciding that something is wrong and exit. 71 */ 72 #define GETTY_TIMEOUT 60 /* seconds */ 73 74 #undef CTRL 75 #define CTRL(x) (x&037) 76 77 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ 78 79 #define PPP_FRAME 0x7e /* PPP Framing character */ 80 #define PPP_STATION 0xff /* "All Station" character */ 81 #define PPP_ESCAPE 0x7d /* Escape Character */ 82 #define PPP_CONTROL 0x03 /* PPP Control Field */ 83 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ 84 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ 85 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ 86 87 /* original mode; flags've been reset using values from <sys/ttydefaults.h> */ 88 struct termios omode; 89 /* current mode */ 90 struct termios tmode; 91 92 static int crmod, digit, lower, upper; 93 94 char hostname[MAXHOSTNAMELEN]; 95 static char name[MAXLOGNAME*3]; 96 static char ttyn[32]; 97 98 #define OBUFSIZ 128 99 100 static const char *tname; 101 102 static char *env[128]; 103 104 static char partab[] = { 105 0001,0201,0201,0001,0201,0001,0001,0201, 106 0202,0004,0003,0205,0005,0206,0201,0001, 107 0201,0001,0001,0201,0001,0201,0201,0001, 108 0001,0201,0201,0001,0201,0001,0001,0201, 109 0200,0000,0000,0200,0000,0200,0200,0000, 110 0000,0200,0200,0000,0200,0000,0000,0200, 111 0000,0200,0200,0000,0200,0000,0000,0200, 112 0200,0000,0000,0200,0000,0200,0200,0000, 113 0200,0000,0000,0200,0000,0200,0200,0000, 114 0000,0200,0200,0000,0200,0000,0000,0200, 115 0000,0200,0200,0000,0200,0000,0000,0200, 116 0200,0000,0000,0200,0000,0200,0200,0000, 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,0201 121 }; 122 123 #define ERASE tmode.c_cc[VERASE] 124 #define KILL tmode.c_cc[VKILL] 125 #define EOT tmode.c_cc[VEOF] 126 127 #define puts Gputs 128 129 static void defttymode(void); 130 static void dingdong(int); 131 static void dogettytab(void); 132 static int getname(void); 133 static void interrupt(int); 134 static void oflush(void); 135 static void prompt(void); 136 static void putchr(int); 137 static void putf(const char *); 138 static void putpad(const char *); 139 static void puts(const char *); 140 static void timeoverrun(int); 141 static char *get_line(int); 142 static void setttymode(int); 143 static int opentty(const char *, int); 144 145 static jmp_buf timeout; 146 147 static void 148 dingdong(int signo __unused) 149 { 150 alarm(0); 151 longjmp(timeout, 1); 152 } 153 154 static jmp_buf intrupt; 155 156 static void 157 interrupt(int signo __unused) 158 { 159 longjmp(intrupt, 1); 160 } 161 162 /* 163 * Action to take when getty is running too long. 164 */ 165 static void 166 timeoverrun(int signo __unused) 167 { 168 169 syslog(LOG_ERR, "getty exiting due to excessive running time"); 170 exit(1); 171 } 172 173 int 174 main(int argc, char *argv[]) 175 { 176 int first_sleep = 1, first_time = 1; 177 struct rlimit limit; 178 int rval; 179 180 signal(SIGINT, SIG_IGN); 181 signal(SIGQUIT, SIG_IGN); 182 183 openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH); 184 gethostname(hostname, sizeof(hostname) - 1); 185 hostname[sizeof(hostname) - 1] = '\0'; 186 if (hostname[0] == '\0') 187 snprintf(hostname, sizeof(hostname), "Amnesiac"); 188 189 /* 190 * Limit running time to deal with broken or dead lines. 191 */ 192 (void)signal(SIGXCPU, timeoverrun); 193 limit.rlim_max = RLIM_INFINITY; 194 limit.rlim_cur = GETTY_TIMEOUT; 195 (void)setrlimit(RLIMIT_CPU, &limit); 196 197 gettable("default"); 198 gendefaults(); 199 tname = "default"; 200 if (argc > 1) 201 tname = argv[1]; 202 203 /* 204 * The following is a work around for vhangup interactions 205 * which cause great problems getting window systems started. 206 * If the tty line is "-", we do the old style getty presuming 207 * that the file descriptors are already set up for us. 208 * J. Gettys - MIT Project Athena. 209 */ 210 if (argc <= 2 || strcmp(argv[2], "-") == 0) { 211 char *n = ttyname(STDIN_FILENO); 212 if (n == NULL) { 213 syslog(LOG_ERR, "ttyname: %m"); 214 exit(1); 215 } 216 snprintf(ttyn, sizeof(ttyn), "%s", n); 217 } else { 218 snprintf(ttyn, sizeof(ttyn), "%s%s", _PATH_DEV, argv[2]); 219 if (strcmp(argv[0], "+") != 0) { 220 chown(ttyn, 0, 0); 221 chmod(ttyn, 0600); 222 revoke(ttyn); 223 224 /* 225 * Do the first scan through gettytab. 226 * Terminal mode parameters will be wrong until 227 * defttymode() called, but they're irrelevant for 228 * the initial setup of the terminal device. 229 */ 230 dogettytab(); 231 232 /* 233 * Init or answer modem sequence has been specified. 234 */ 235 if (IC || AC) { 236 if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) 237 exit(1); 238 defttymode(); 239 setttymode(1); 240 } 241 242 if (IC) { 243 if (getty_chat(IC, CT, DC) > 0) { 244 syslog(LOG_ERR, "modem init problem on %s", ttyn); 245 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 246 exit(1); 247 } 248 } 249 250 if (AC) { 251 fd_set rfds; 252 struct timeval to; 253 int i; 254 255 FD_ZERO(&rfds); 256 FD_SET(0, &rfds); 257 to.tv_sec = RT; 258 to.tv_usec = 0; 259 i = select(32, &rfds, NULL, NULL, RT ? &to : NULL); 260 if (i < 0) { 261 syslog(LOG_ERR, "select %s: %m", ttyn); 262 } else if (i == 0) { 263 syslog(LOG_NOTICE, "recycle tty %s", ttyn); 264 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 265 exit(0); /* recycle for init */ 266 } 267 i = getty_chat(AC, CT, DC); 268 if (i > 0) { 269 syslog(LOG_ERR, "modem answer problem on %s", ttyn); 270 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 271 exit(1); 272 } 273 } else { /* maybe blocking open */ 274 if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 ))) 275 exit(1); 276 } 277 } 278 } 279 280 defttymode(); 281 for (;;) { 282 283 /* 284 * if a delay was specified then sleep for that 285 * number of seconds before writing the initial prompt 286 */ 287 if (first_sleep && DE) { 288 sleep(DE); 289 /* remove any noise */ 290 (void)tcflush(STDIN_FILENO, TCIOFLUSH); 291 } 292 first_sleep = 0; 293 294 setttymode(0); 295 if (AB) { 296 tname = autobaud(); 297 dogettytab(); 298 continue; 299 } 300 if (PS) { 301 tname = portselector(); 302 dogettytab(); 303 continue; 304 } 305 if (CL && *CL) 306 putpad(CL); 307 edithost(HE); 308 309 /* if this is the first time through this, and an 310 issue file has been given, then send it */ 311 if (first_time && IF) { 312 int fd; 313 314 if ((fd = open(IF, O_RDONLY)) != -1) { 315 char * cp; 316 317 while ((cp = get_line(fd)) != NULL) { 318 putf(cp); 319 } 320 close(fd); 321 } 322 } 323 first_time = 0; 324 325 if (IMP && *IMP && !(PL && PP)) 326 system(IMP); 327 if (IM && *IM && !(PL && PP)) 328 putf(IM); 329 if (setjmp(timeout)) { 330 cfsetispeed(&tmode, B0); 331 cfsetospeed(&tmode, B0); 332 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 333 exit(1); 334 } 335 if (TO) { 336 signal(SIGALRM, dingdong); 337 alarm(TO); 338 } 339 340 rval = 0; 341 if (AL) { 342 const char *p = AL; 343 char *q = name; 344 345 while (*p && q < &name[sizeof name - 1]) { 346 if (isupper(*p)) 347 upper = 1; 348 else if (islower(*p)) 349 lower = 1; 350 else if (isdigit(*p)) 351 digit = 1; 352 *q++ = *p++; 353 } 354 } else if (!(PL && PP)) 355 rval = getname(); 356 if (rval == 2 || (PL && PP)) { 357 oflush(); 358 alarm(0); 359 limit.rlim_max = RLIM_INFINITY; 360 limit.rlim_cur = RLIM_INFINITY; 361 (void)setrlimit(RLIMIT_CPU, &limit); 362 execle(PP, "ppplogin", ttyn, (char *) 0, env); 363 syslog(LOG_ERR, "%s: %m", PP); 364 exit(1); 365 } else if (rval || AL) { 366 int i; 367 368 oflush(); 369 alarm(0); 370 signal(SIGALRM, SIG_DFL); 371 if (name[0] == '\0') 372 continue; 373 if (name[0] == '-') { 374 puts("user names may not start with '-'."); 375 continue; 376 } 377 if (!(upper || lower || digit)) { 378 if (AL) { 379 syslog(LOG_ERR, 380 "invalid auto-login name: %s", AL); 381 exit(1); 382 } else 383 continue; 384 } 385 set_flags(2); 386 if (crmod) { 387 tmode.c_iflag |= ICRNL; 388 tmode.c_oflag |= ONLCR; 389 } 390 #if REALLY_OLD_TTYS 391 if (upper || UC) 392 tmode.sg_flags |= LCASE; 393 if (lower || LC) 394 tmode.sg_flags &= ~LCASE; 395 #endif 396 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 397 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); 398 exit(1); 399 } 400 signal(SIGINT, SIG_DFL); 401 for (i = 0; environ[i] != (char *)0; i++) 402 env[i] = environ[i]; 403 makeenv(&env[i]); 404 405 limit.rlim_max = RLIM_INFINITY; 406 limit.rlim_cur = RLIM_INFINITY; 407 (void)setrlimit(RLIMIT_CPU, &limit); 408 execle(LO, "login", AL ? "-fp" : "-p", name, 409 (char *) 0, env); 410 syslog(LOG_ERR, "%s: %m", LO); 411 exit(1); 412 } 413 alarm(0); 414 signal(SIGALRM, SIG_DFL); 415 signal(SIGINT, SIG_IGN); 416 if (NX && *NX) { 417 tname = NX; 418 dogettytab(); 419 } 420 } 421 } 422 423 static int 424 opentty(const char *tty, int flags) 425 { 426 int failopenlogged = 0, i, saved_errno; 427 428 while ((i = open(tty, flags)) == -1) 429 { 430 saved_errno = errno; 431 if (!failopenlogged) { 432 syslog(LOG_ERR, "open %s: %m", tty); 433 failopenlogged = 1; 434 } 435 if (saved_errno == ENOENT) 436 return 0; 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 static char outbuf[OBUFSIZ]; 668 static 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 get_line(int fd) 709 { 710 size_t 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 time_t t; 735 char db[100]; 736 const char *slash; 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 case '%': 788 putchr('%'); 789 break; 790 } 791 cp++; 792 } 793 } 794 795 /* 796 * Read a gettytab database entry and perform necessary quirks. 797 */ 798 static void 799 dogettytab(void) 800 { 801 802 /* Read the database entry. */ 803 gettable(tname); 804 805 /* 806 * Avoid inheriting the parity values from the default entry 807 * if any of them is set in the current entry. 808 * Mixing different parity settings is unreasonable. 809 */ 810 if (OPset || EPset || APset || NPset) 811 OPset = EPset = APset = NPset = 1; 812 813 /* Fill in default values for unset capabilities. */ 814 setdefaults(); 815 } 816