1 /* $NetBSD: main.c,v 1.18 1996/07/31 20:40:34 thorpej 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.18 1996/07/31 20:40:34 thorpej 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 /* 213 * Delay the open so DTR stays down long enough to be detected. 214 */ 215 sleep(2); 216 while ((i = open(ttyn, O_RDWR)) == -1) { 217 if ((repcnt % 10 == 0) && 218 (errno != ENXIO || !failopenlogged)) { 219 syslog(LOG_ERR, "%s: %m", ttyn); 220 closelog(); 221 failopenlogged = 1; 222 } 223 repcnt++; 224 sleep(60); 225 } 226 login_tty(i); 227 } 228 } 229 230 /* Start with default tty settings */ 231 if (tcgetattr(0, &tmode) < 0) { 232 syslog(LOG_ERR, "%s: %m", ttyn); 233 exit(1); 234 } 235 omode = tmode; 236 237 gettable("default", defent); 238 gendefaults(); 239 tname = "default"; 240 if (argc > 1) 241 tname = argv[1]; 242 for (;;) { 243 int off; 244 245 gettable(tname, tabent); 246 if (OPset || EPset || APset) 247 APset++, OPset++, EPset++; 248 setdefaults(); 249 off = 0; 250 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 251 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 252 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 253 254 if (IS) 255 cfsetispeed(&tmode, IS); 256 else if (SP) 257 cfsetispeed(&tmode, SP); 258 if (OS) 259 cfsetospeed(&tmode, OS); 260 else if (SP) 261 cfsetospeed(&tmode, SP); 262 setflags(0); 263 setchars(); 264 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 265 syslog(LOG_ERR, "%s: %m", ttyn); 266 exit(1); 267 } 268 if (AB) { 269 extern char *autobaud(); 270 271 tname = autobaud(); 272 continue; 273 } 274 if (PS) { 275 tname = portselector(); 276 continue; 277 } 278 if (CL && *CL) 279 putpad(CL); 280 edithost(HE); 281 if (IM && *IM) 282 putf(IM); 283 if (setjmp(timeout)) { 284 tmode.c_ispeed = tmode.c_ospeed = 0; 285 (void)tcsetattr(0, TCSANOW, &tmode); 286 exit(1); 287 } 288 if (TO) { 289 signal(SIGALRM, dingdong); 290 alarm(TO); 291 } 292 if (getname()) { 293 register int i; 294 295 oflush(); 296 alarm(0); 297 signal(SIGALRM, SIG_DFL); 298 if (name[0] == '-') { 299 puts("user names may not start with '-'."); 300 continue; 301 } 302 if (!(upper || lower || digit)) 303 continue; 304 setflags(2); 305 if (crmod) { 306 tmode.c_iflag |= ICRNL; 307 tmode.c_oflag |= ONLCR; 308 } 309 #if XXX 310 if (upper || UC) 311 tmode.sg_flags |= LCASE; 312 if (lower || LC) 313 tmode.sg_flags &= ~LCASE; 314 #endif 315 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 316 syslog(LOG_ERR, "%s: %m", ttyn); 317 exit(1); 318 } 319 signal(SIGINT, SIG_DFL); 320 for (i = 0; environ[i] != (char *)0; i++) 321 env[i] = environ[i]; 322 makeenv(&env[i]); 323 324 limit.rlim_max = RLIM_INFINITY; 325 limit.rlim_cur = RLIM_INFINITY; 326 (void)setrlimit(RLIMIT_CPU, &limit); 327 execle(LO, "login", "-p", "--", name, (char *)0, env); 328 syslog(LOG_ERR, "%s: %m", LO); 329 exit(1); 330 } 331 alarm(0); 332 signal(SIGALRM, SIG_DFL); 333 signal(SIGINT, SIG_IGN); 334 if (NX && *NX) 335 tname = NX; 336 } 337 } 338 339 static int 340 getname() 341 { 342 register int c; 343 register char *np; 344 char cs; 345 346 /* 347 * Interrupt may happen if we use CBREAK mode 348 */ 349 if (setjmp(intrupt)) { 350 signal(SIGINT, SIG_IGN); 351 return (0); 352 } 353 signal(SIGINT, interrupt); 354 setflags(1); 355 prompt(); 356 if (PF > 0) { 357 oflush(); 358 sleep(PF); 359 PF = 0; 360 } 361 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 362 syslog(LOG_ERR, "%s: %m", ttyn); 363 exit(1); 364 } 365 crmod = digit = lower = upper = 0; 366 np = name; 367 for (;;) { 368 oflush(); 369 if (read(STDIN_FILENO, &cs, 1) <= 0) 370 exit(0); 371 if ((c = cs&0177) == 0) 372 return (0); 373 if (c == EOT) 374 exit(1); 375 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 376 putf("\r\n"); 377 break; 378 } 379 if (islower(c)) 380 lower = 1; 381 else if (isupper(c)) 382 upper = 1; 383 else if (c == ERASE || c == '#' || c == '\b') { 384 if (np > name) { 385 np--; 386 if (cfgetospeed(&tmode) >= 1200) 387 puts("\b \b"); 388 else 389 putchr(cs); 390 } 391 continue; 392 } else if (c == KILL || c == '@') { 393 putchr(cs); 394 putchr('\r'); 395 if (cfgetospeed(&tmode) < 1200) 396 putchr('\n'); 397 /* this is the way they do it down under ... */ 398 else if (np > name) 399 puts(" \r"); 400 prompt(); 401 np = name; 402 continue; 403 } else if (isdigit(c)) 404 digit++; 405 if (IG && (c <= ' ' || c > 0176)) 406 continue; 407 *np++ = c; 408 putchr(cs); 409 } 410 signal(SIGINT, SIG_IGN); 411 *np = 0; 412 if (c == '\r') 413 crmod = 1; 414 if (upper && !lower && !LC || UC) 415 for (np = name; *np; np++) 416 if (isupper(*np)) 417 *np = tolower(*np); 418 return (1); 419 } 420 421 static void 422 putpad(s) 423 register char *s; 424 { 425 register pad = 0; 426 speed_t ospeed = cfgetospeed(&tmode); 427 428 if (isdigit(*s)) { 429 while (isdigit(*s)) { 430 pad *= 10; 431 pad += *s++ - '0'; 432 } 433 pad *= 10; 434 if (*s == '.' && isdigit(s[1])) { 435 pad += s[1] - '0'; 436 s += 2; 437 } 438 } 439 440 puts(s); 441 /* 442 * If no delay needed, or output speed is 443 * not comprehensible, then don't try to delay. 444 */ 445 if (pad == 0 || ospeed <= 0) 446 return; 447 448 /* 449 * Round up by a half a character frame, and then do the delay. 450 * Too bad there are no user program accessible programmed delays. 451 * Transmitting pad characters slows many terminals down and also 452 * loads the system. 453 */ 454 pad = (pad * ospeed + 50000) / 100000; 455 while (pad--) 456 putchr(*PC); 457 } 458 459 static void 460 puts(s) 461 register char *s; 462 { 463 while (*s) 464 putchr(*s++); 465 } 466 467 char outbuf[OBUFSIZ]; 468 int obufcnt = 0; 469 470 static void 471 putchr(cc) 472 int cc; 473 { 474 char c; 475 476 c = cc; 477 if (!NP) { 478 c |= partab[c&0177] & 0200; 479 if (OP) 480 c ^= 0200; 481 } 482 if (!UB) { 483 outbuf[obufcnt++] = c; 484 if (obufcnt >= OBUFSIZ) 485 oflush(); 486 } else 487 write(STDOUT_FILENO, &c, 1); 488 } 489 490 static void 491 oflush() 492 { 493 if (obufcnt) 494 write(STDOUT_FILENO, outbuf, obufcnt); 495 obufcnt = 0; 496 } 497 498 static void 499 prompt() 500 { 501 502 putf(LM); 503 if (CO) 504 putchr('\n'); 505 } 506 507 static void 508 putf(cp) 509 register char *cp; 510 { 511 extern char editedhost[]; 512 time_t t; 513 char *slash, db[100]; 514 515 while (*cp) { 516 if (*cp != '%') { 517 putchr(*cp++); 518 continue; 519 } 520 switch (*++cp) { 521 522 case 't': 523 slash = strrchr(ttyn, '/'); 524 if (slash == (char *) 0) 525 puts(ttyn); 526 else 527 puts(&slash[1]); 528 break; 529 530 case 'h': 531 puts(editedhost); 532 break; 533 534 case 'd': { 535 static char fmt[] = "%l:% %p on %A, %d %B %Y"; 536 537 fmt[4] = 'M'; /* I *hate* SCCS... */ 538 (void)time(&t); 539 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 540 puts(db); 541 break; 542 543 case 's': 544 puts(kerninfo.sysname); 545 break; 546 547 case 'm': 548 puts(kerninfo.machine); 549 break; 550 551 case 'r': 552 puts(kerninfo.release); 553 break; 554 555 case 'v': 556 puts(kerninfo.version); 557 break; 558 } 559 560 case '%': 561 putchr('%'); 562 break; 563 } 564 cp++; 565 } 566 } 567