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 35 static 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 /*static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";*/ 42 static char rcsid[] = "$Id: main.c,v 1.9 1996/05/05 19:01:10 joerg Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/ioctl.h> 48 #include <sys/resource.h> 49 #include <sys/ttydefaults.h> 50 #include <sys/utsname.h> 51 #include <errno.h> 52 #include <signal.h> 53 #include <fcntl.h> 54 #include <time.h> 55 #include <ctype.h> 56 #include <fcntl.h> 57 #include <libutil.h> 58 #include <locale.h> 59 #include <setjmp.h> 60 #include <signal.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <syslog.h> 64 #include <termios.h> 65 #include <time.h> 66 #include <unistd.h> 67 68 #include "gettytab.h" 69 #include "pathnames.h" 70 #include "extern.h" 71 72 /* 73 * Set the amount of running time that getty should accumulate 74 * before deciding that something is wrong and exit. 75 */ 76 #define GETTY_TIMEOUT 60 /* seconds */ 77 78 #undef CTRL 79 #define CTRL(x) (x&037) 80 81 struct termios tmode, omode; 82 83 int crmod, digit, lower, upper; 84 85 char hostname[MAXHOSTNAMELEN]; 86 struct utsname kerninfo; 87 char name[16]; 88 char dev[] = _PATH_DEV; 89 char ttyn[32]; 90 91 #define OBUFSIZ 128 92 #define TABBUFSIZ 512 93 94 char defent[TABBUFSIZ]; 95 char tabent[TABBUFSIZ]; 96 97 char *env[128]; 98 99 char partab[] = { 100 0001,0201,0201,0001,0201,0001,0001,0201, 101 0202,0004,0003,0205,0005,0206,0201,0001, 102 0201,0001,0001,0201,0001,0201,0201,0001, 103 0001,0201,0201,0001,0201,0001,0001,0201, 104 0200,0000,0000,0200,0000,0200,0200,0000, 105 0000,0200,0200,0000,0200,0000,0000,0200, 106 0000,0200,0200,0000,0200,0000,0000,0200, 107 0200,0000,0000,0200,0000,0200,0200,0000, 108 0200,0000,0000,0200,0000,0200,0200,0000, 109 0000,0200,0200,0000,0200,0000,0000,0200, 110 0000,0200,0200,0000,0200,0000,0000,0200, 111 0200,0000,0000,0200,0000,0200,0200,0000, 112 0000,0200,0200,0000,0200,0000,0000,0200, 113 0200,0000,0000,0200,0000,0200,0200,0000, 114 0200,0000,0000,0200,0000,0200,0200,0000, 115 0000,0200,0200,0000,0200,0000,0000,0201 116 }; 117 118 #define ERASE tmode.c_cc[VERASE] 119 #define KILL tmode.c_cc[VKILL] 120 #define EOT tmode.c_cc[VEOF] 121 122 jmp_buf timeout; 123 124 static void dingdong __P((int)); 125 static int getname __P((void)); 126 static void interrupt __P((int)); 127 static void oflush __P((void)); 128 static void prompt __P((void)); 129 static void putchr __P((int)); 130 static void putf __P((const char *)); 131 static void putpad __P((const char *)); 132 static void puts __P((const char *)); 133 static void timeoverrun __P((int)); 134 135 int main __P((int, char **)); 136 137 static void 138 dingdong(signo) 139 int signo; 140 { 141 alarm(0); 142 longjmp(timeout, 1); 143 } 144 145 jmp_buf intrupt; 146 147 static void 148 interrupt(signo) 149 int signo; 150 { 151 longjmp(intrupt, 1); 152 } 153 154 /* 155 * Action to take when getty is running too long. 156 */ 157 static void 158 timeoverrun(signo) 159 int signo; 160 { 161 162 syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 163 exit(1); 164 } 165 166 int 167 main(argc, argv) 168 int argc; 169 char **argv; 170 { 171 extern char **environ; 172 const char *tname; 173 int repcnt = 0, failopenlogged = 0; 174 struct rlimit limit; 175 176 signal(SIGINT, SIG_IGN); 177 signal(SIGQUIT, SIG_IGN); 178 179 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); 180 gethostname(hostname, sizeof(hostname)); 181 if (hostname[0] == '\0') 182 strcpy(hostname, "Amnesiac"); 183 184 /* 185 * Limit running time to deal with broken or dead lines. 186 */ 187 (void)signal(SIGXCPU, timeoverrun); 188 limit.rlim_max = RLIM_INFINITY; 189 limit.rlim_cur = GETTY_TIMEOUT; 190 (void)setrlimit(RLIMIT_CPU, &limit); 191 192 /* 193 * The following is a work around for vhangup interactions 194 * which cause great problems getting window systems started. 195 * If the tty line is "-", we do the old style getty presuming 196 * that the file descriptors are already set up for us. 197 * J. Gettys - MIT Project Athena. 198 */ 199 if (argc <= 2 || strcmp(argv[2], "-") == 0) 200 strcpy(ttyn, ttyname(0)); 201 else { 202 int i; 203 204 strcpy(ttyn, dev); 205 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 206 if (strcmp(argv[0], "+") != 0) { 207 chown(ttyn, 0, 0); 208 chmod(ttyn, 0600); 209 revoke(ttyn); 210 while ((i = open(ttyn, O_RDWR)) == -1) { 211 if ((repcnt % 10 == 0) && 212 (errno != ENXIO || !failopenlogged)) { 213 syslog(LOG_ERR, "%s: %m", ttyn); 214 closelog(); 215 failopenlogged = 1; 216 } 217 repcnt++; 218 sleep(60); 219 } 220 login_tty(i); 221 } 222 } 223 224 /* Start with default tty settings */ 225 if (tcgetattr(0, &tmode) < 0) { 226 syslog(LOG_ERR, "%s: %m", ttyn); 227 exit(1); 228 } 229 /* 230 * Don't rely on the driver too much, and initialize crucial 231 * things according to <sys/ttydefaults.h>. Avoid clobbering 232 * the c_cc[] settings however, the console drivers might wish 233 * to leave their idea of the preferred VERASE key value 234 * there. 235 */ 236 tmode.c_iflag = TTYDEF_IFLAG; 237 tmode.c_oflag = TTYDEF_OFLAG; 238 tmode.c_lflag = TTYDEF_LFLAG; 239 tmode.c_cflag = TTYDEF_CFLAG; 240 omode = tmode; 241 242 gettable("default", defent); 243 gendefaults(); 244 tname = "default"; 245 if (argc > 1) 246 tname = argv[1]; 247 for (;;) { 248 int off = 0; 249 250 gettable(tname, tabent); 251 if (OPset || EPset || APset) 252 APset++, OPset++, EPset++; 253 setdefaults(); 254 off = 0; 255 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 256 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 257 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 258 259 if (IS) 260 cfsetispeed(&tmode, speed(IS)); 261 else if (SP) 262 cfsetispeed(&tmode, speed(SP)); 263 if (OS) 264 cfsetospeed(&tmode, speed(OS)); 265 else if (SP) 266 cfsetospeed(&tmode, speed(SP)); 267 setflags(0); 268 setchars(); 269 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 270 syslog(LOG_ERR, "%s: %m", ttyn); 271 exit(1); 272 } 273 if (AB) { 274 tname = autobaud(); 275 continue; 276 } 277 if (PS) { 278 tname = portselector(); 279 continue; 280 } 281 if (CL && *CL) 282 putpad(CL); 283 edithost(HE); 284 if (IM && *IM) 285 putf(IM); 286 if (setjmp(timeout)) { 287 cfsetispeed(&tmode, B0); 288 cfsetospeed(&tmode, B0); 289 (void)tcsetattr(0, TCSANOW, &tmode); 290 exit(1); 291 } 292 if (TO) { 293 signal(SIGALRM, dingdong); 294 alarm(TO); 295 } 296 if (getname()) { 297 register int i; 298 299 oflush(); 300 alarm(0); 301 signal(SIGALRM, SIG_DFL); 302 if (name[0] == '-') { 303 puts("user names may not start with '-'."); 304 continue; 305 } 306 if (!(upper || lower || digit)) 307 continue; 308 setflags(2); 309 if (crmod) { 310 tmode.c_iflag |= ICRNL; 311 tmode.c_oflag |= ONLCR; 312 } 313 #if REALLY_OLD_TTYS 314 if (upper || UC) 315 tmode.sg_flags |= LCASE; 316 if (lower || LC) 317 tmode.sg_flags &= ~LCASE; 318 #endif 319 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 320 syslog(LOG_ERR, "%s: %m", ttyn); 321 exit(1); 322 } 323 signal(SIGINT, SIG_DFL); 324 for (i = 0; environ[i] != (char *)0; i++) 325 env[i] = environ[i]; 326 makeenv(&env[i]); 327 328 limit.rlim_max = RLIM_INFINITY; 329 limit.rlim_cur = RLIM_INFINITY; 330 (void)setrlimit(RLIMIT_CPU, &limit); 331 execle(LO, "login", "-p", name, (char *) 0, env); 332 syslog(LOG_ERR, "%s: %m", LO); 333 exit(1); 334 } 335 alarm(0); 336 signal(SIGALRM, SIG_DFL); 337 signal(SIGINT, SIG_IGN); 338 if (NX && *NX) 339 tname = NX; 340 } 341 } 342 343 static int 344 getname() 345 { 346 register int c; 347 register char *np; 348 char cs; 349 350 /* 351 * Interrupt may happen if we use CBREAK mode 352 */ 353 if (setjmp(intrupt)) { 354 signal(SIGINT, SIG_IGN); 355 return (0); 356 } 357 signal(SIGINT, interrupt); 358 setflags(1); 359 prompt(); 360 oflush(); 361 if (PF > 0) { 362 sleep(PF); 363 PF = 0; 364 } 365 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 366 syslog(LOG_ERR, "%s: %m", ttyn); 367 exit(1); 368 } 369 crmod = digit = lower = upper = 0; 370 np = name; 371 for (;;) { 372 oflush(); 373 if (read(STDIN_FILENO, &cs, 1) <= 0) 374 exit(0); 375 if ((c = cs&0177) == 0) 376 return (0); 377 if (c == EOT || c == CTRL('d')) 378 exit(1); 379 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 380 putf("\r\n"); 381 break; 382 } 383 if (islower(c)) 384 lower = 1; 385 else if (isupper(c)) 386 upper = 1; 387 else if (c == ERASE || c == '\b' || c == 0177) { 388 if (np > name) { 389 np--; 390 if (cfgetospeed(&tmode) >= 1200) 391 puts("\b \b"); 392 else 393 putchr(cs); 394 } 395 continue; 396 } else if (c == KILL || c == CTRL('u')) { 397 putchr('\r'); 398 if (cfgetospeed(&tmode) < 1200) 399 putchr('\n'); 400 /* this is the way they do it down under ... */ 401 else if (np > name) 402 puts(" \r"); 403 prompt(); 404 np = name; 405 continue; 406 } else if (isdigit(c)) 407 digit++; 408 if (IG && (c <= ' ' || c > 0176)) 409 continue; 410 *np++ = c; 411 putchr(cs); 412 } 413 signal(SIGINT, SIG_IGN); 414 *np = 0; 415 if (c == '\r') 416 crmod = 1; 417 if ((upper && !lower && !LC) || UC) 418 for (np = name; *np; np++) 419 if (isupper(*np)) 420 *np = tolower(*np); 421 return (1); 422 } 423 424 static void 425 putpad(s) 426 register const char *s; 427 { 428 register pad = 0; 429 speed_t ospeed = cfgetospeed(&tmode); 430 431 if (isdigit(*s)) { 432 while (isdigit(*s)) { 433 pad *= 10; 434 pad += *s++ - '0'; 435 } 436 pad *= 10; 437 if (*s == '.' && isdigit(s[1])) { 438 pad += s[1] - '0'; 439 s += 2; 440 } 441 } 442 443 puts(s); 444 /* 445 * If no delay needed, or output speed is 446 * not comprehensible, then don't try to delay. 447 */ 448 if (pad == 0 || ospeed <= 0) 449 return; 450 451 /* 452 * Round up by a half a character frame, and then do the delay. 453 * Too bad there are no user program accessible programmed delays. 454 * Transmitting pad characters slows many terminals down and also 455 * loads the system. 456 */ 457 pad = (pad * ospeed + 50000) / 100000; 458 while (pad--) 459 putchr(*PC); 460 } 461 462 static void 463 puts(s) 464 register const char *s; 465 { 466 while (*s) 467 putchr(*s++); 468 } 469 470 char outbuf[OBUFSIZ]; 471 int obufcnt = 0; 472 473 static void 474 putchr(cc) 475 int cc; 476 { 477 char c; 478 479 c = cc; 480 if (!NP) { 481 c |= partab[c&0177] & 0200; 482 if (OP) 483 c ^= 0200; 484 } 485 if (!UB) { 486 outbuf[obufcnt++] = c; 487 if (obufcnt >= OBUFSIZ) 488 oflush(); 489 } else 490 write(STDOUT_FILENO, &c, 1); 491 } 492 493 static void 494 oflush() 495 { 496 if (obufcnt) 497 write(STDOUT_FILENO, outbuf, obufcnt); 498 obufcnt = 0; 499 } 500 501 static void 502 prompt() 503 { 504 505 putf(LM); 506 if (CO) 507 putchr('\n'); 508 } 509 510 static void 511 putf(cp) 512 register const char *cp; 513 { 514 extern char editedhost[]; 515 time_t t; 516 char *slash, db[100]; 517 518 while (*cp) { 519 if (*cp != '%') { 520 putchr(*cp++); 521 continue; 522 } 523 switch (*++cp) { 524 525 case 't': 526 slash = strrchr(ttyn, '/'); 527 if (slash == (char *) 0) 528 puts(ttyn); 529 else 530 puts(&slash[1]); 531 break; 532 533 case 'h': 534 puts(editedhost); 535 break; 536 537 case 'd': { 538 t = (time_t)0; 539 (void)time(&t); 540 if (Lo) 541 (void)setlocale(LC_TIME, Lo); 542 (void)strftime(db, sizeof(db), "%+", localtime(&t)); 543 puts(db); 544 break; 545 546 case 's': 547 puts(kerninfo.sysname); 548 break; 549 550 case 'm': 551 puts(kerninfo.machine); 552 break; 553 554 case 'r': 555 puts(kerninfo.release); 556 break; 557 558 case 'v': 559 puts(kerninfo.version); 560 break; 561 } 562 563 case '%': 564 putchr('%'); 565 break; 566 } 567 cp++; 568 } 569 } 570