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