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