1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/20/93"; 16 #endif /* not lint */ 17 18 #define USE_OLD_TTY 19 20 #include <sys/param.h> 21 #include <sys/stat.h> 22 #include <sys/resource.h> 23 24 #include <ctype.h> 25 #include <ctype.h> 26 #include <fcntl.h> 27 #include <setjmp.h> 28 #include <sgtty.h> 29 #include <signal.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <time.h> 34 #include <unistd.h> 35 36 #include "gettytab.h" 37 #include "pathnames.h" 38 #include "extern.h" 39 40 /* 41 * Set the amount of running time that getty should accumulate 42 * before deciding that something is wrong and exit. 43 */ 44 #define GETTY_TIMEOUT 60 /* seconds */ 45 46 struct sgttyb tmode = { 47 0, 0, CERASE, CKILL, 0 48 }; 49 struct tchars tc = { 50 CINTR, CQUIT, CSTART, 51 CSTOP, CEOF, CBRK, 52 }; 53 struct ltchars ltc = { 54 CSUSP, CDSUSP, CRPRNT, 55 CFLUSH, CWERASE, CLNEXT 56 }; 57 58 int crmod, digit, lower, upper; 59 60 char hostname[MAXHOSTNAMELEN]; 61 char name[16]; 62 char dev[] = _PATH_DEV; 63 char ttyn[32]; 64 char *portselector(); 65 char *ttyname(); 66 67 #define OBUFSIZ 128 68 #define TABBUFSIZ 512 69 70 char defent[TABBUFSIZ]; 71 char tabent[TABBUFSIZ]; 72 73 char *env[128]; 74 75 char partab[] = { 76 0001,0201,0201,0001,0201,0001,0001,0201, 77 0202,0004,0003,0205,0005,0206,0201,0001, 78 0201,0001,0001,0201,0001,0201,0201,0001, 79 0001,0201,0201,0001,0201,0001,0001,0201, 80 0200,0000,0000,0200,0000,0200,0200,0000, 81 0000,0200,0200,0000,0200,0000,0000,0200, 82 0000,0200,0200,0000,0200,0000,0000,0200, 83 0200,0000,0000,0200,0000,0200,0200,0000, 84 0200,0000,0000,0200,0000,0200,0200,0000, 85 0000,0200,0200,0000,0200,0000,0000,0200, 86 0000,0200,0200,0000,0200,0000,0000,0200, 87 0200,0000,0000,0200,0000,0200,0200,0000, 88 0000,0200,0200,0000,0200,0000,0000,0200, 89 0200,0000,0000,0200,0000,0200,0200,0000, 90 0200,0000,0000,0200,0000,0200,0200,0000, 91 0000,0200,0200,0000,0200,0000,0000,0201 92 }; 93 94 #define ERASE tmode.sg_erase 95 #define KILL tmode.sg_kill 96 #define EOT tc.t_eofc 97 98 jmp_buf timeout; 99 100 static void 101 dingdong() 102 { 103 104 alarm(0); 105 signal(SIGALRM, SIG_DFL); 106 longjmp(timeout, 1); 107 } 108 109 jmp_buf intrupt; 110 111 static void 112 interrupt() 113 { 114 115 signal(SIGINT, interrupt); 116 longjmp(intrupt, 1); 117 } 118 119 /* 120 * Action to take when getty is running too long. 121 */ 122 void 123 timeoverrun(signo) 124 int signo; 125 { 126 127 syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 128 exit(1); 129 } 130 131 static int getname __P((void)); 132 static void oflush __P((void)); 133 static void prompt __P((void)); 134 static void putchr __P((int)); 135 static void putf __P((char *)); 136 static void putpad __P((char *)); 137 static void puts __P((char *)); 138 139 int 140 main(argc, argv) 141 int argc; 142 char *argv[]; 143 { 144 extern char **environ; 145 char *tname; 146 long allflags; 147 int repcnt = 0; 148 struct rlimit limit; 149 150 signal(SIGINT, SIG_IGN); 151 /* 152 signal(SIGQUIT, SIG_DFL); 153 */ 154 openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH); 155 gethostname(hostname, sizeof(hostname)); 156 if (hostname[0] == '\0') 157 strcpy(hostname, "Amnesiac"); 158 159 /* 160 * Limit running time to deal with broken or dead lines. 161 */ 162 (void)signal(SIGXCPU, timeoverrun); 163 limit.rlim_max = RLIM_INFINITY; 164 limit.rlim_cur = GETTY_TIMEOUT; 165 (void)setrlimit(RLIMIT_CPU, &limit); 166 167 /* 168 * The following is a work around for vhangup interactions 169 * which cause great problems getting window systems started. 170 * If the tty line is "-", we do the old style getty presuming 171 * that the file descriptors are already set up for us. 172 * J. Gettys - MIT Project Athena. 173 */ 174 if (argc <= 2 || strcmp(argv[2], "-") == 0) 175 strcpy(ttyn, ttyname(0)); 176 else { 177 int i; 178 179 strcpy(ttyn, dev); 180 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 181 if (strcmp(argv[0], "+") != 0) { 182 chown(ttyn, 0, 0); 183 chmod(ttyn, 0600); 184 revoke(ttyn); 185 /* 186 * Delay the open so DTR stays down long enough to be detected. 187 */ 188 sleep(2); 189 while ((i = open(ttyn, O_RDWR)) == -1) { 190 if (repcnt % 10 == 0) { 191 syslog(LOG_ERR, "%s: %m", ttyn); 192 closelog(); 193 } 194 repcnt++; 195 sleep(60); 196 } 197 login_tty(i); 198 } 199 } 200 201 gettable("default", defent); 202 gendefaults(); 203 tname = "default"; 204 if (argc > 1) 205 tname = argv[1]; 206 for (;;) { 207 int off; 208 209 gettable(tname, tabent); 210 if (OPset || EPset || APset) 211 APset++, OPset++, EPset++; 212 setdefaults(); 213 off = 0; 214 ioctl(0, TIOCFLUSH, &off); /* clear out the crap */ 215 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 216 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 217 if (IS) 218 tmode.sg_ispeed = speed(IS); 219 else if (SP) 220 tmode.sg_ispeed = speed(SP); 221 if (OS) 222 tmode.sg_ospeed = speed(OS); 223 else if (SP) 224 tmode.sg_ospeed = speed(SP); 225 tmode.sg_flags = setflags(0); 226 ioctl(0, TIOCSETP, &tmode); 227 setchars(); 228 ioctl(0, TIOCSETC, &tc); 229 if (HC) 230 ioctl(0, TIOCHPCL, 0); 231 if (AB) { 232 extern char *autobaud(); 233 234 tname = autobaud(); 235 continue; 236 } 237 if (PS) { 238 tname = portselector(); 239 continue; 240 } 241 if (CL && *CL) 242 putpad(CL); 243 edithost(HE); 244 if (IM && *IM) 245 putf(IM); 246 if (setjmp(timeout)) { 247 tmode.sg_ispeed = tmode.sg_ospeed = 0; 248 ioctl(0, TIOCSETP, &tmode); 249 exit(1); 250 } 251 if (TO) { 252 signal(SIGALRM, dingdong); 253 alarm(TO); 254 } 255 if (getname()) { 256 register int i; 257 258 oflush(); 259 alarm(0); 260 signal(SIGALRM, SIG_DFL); 261 if (name[0] == '-') { 262 puts("user names may not start with '-'."); 263 continue; 264 } 265 if (!(upper || lower || digit)) 266 continue; 267 allflags = setflags(2); 268 tmode.sg_flags = allflags & 0xffff; 269 allflags >>= 16; 270 if (crmod || NL) 271 tmode.sg_flags |= CRMOD; 272 if (upper || UC) 273 tmode.sg_flags |= LCASE; 274 if (lower || LC) 275 tmode.sg_flags &= ~LCASE; 276 ioctl(0, TIOCSETP, &tmode); 277 ioctl(0, TIOCSLTC, <c); 278 ioctl(0, TIOCLSET, &allflags); 279 signal(SIGINT, SIG_DFL); 280 for (i = 0; environ[i] != (char *)0; i++) 281 env[i] = environ[i]; 282 makeenv(&env[i]); 283 284 /* 285 * this is what login was doing anyway. 286 * soon we rewrite getty completely. 287 */ 288 set_ttydefaults(0); 289 limit.rlim_max = RLIM_INFINITY; 290 limit.rlim_cur = RLIM_INFINITY; 291 (void)setrlimit(RLIMIT_CPU, &limit); 292 execle(LO, "login", "-p", name, (char *) 0, env); 293 syslog(LOG_ERR, "%s: %m", LO); 294 exit(1); 295 } 296 alarm(0); 297 signal(SIGALRM, SIG_DFL); 298 signal(SIGINT, SIG_IGN); 299 if (NX && *NX) 300 tname = NX; 301 } 302 } 303 304 static int 305 getname() 306 { 307 register int c; 308 register char *np; 309 char cs; 310 311 /* 312 * Interrupt may happen if we use CBREAK mode 313 */ 314 if (setjmp(intrupt)) { 315 signal(SIGINT, SIG_IGN); 316 return (0); 317 } 318 signal(SIGINT, interrupt); 319 tmode.sg_flags = setflags(0); 320 ioctl(0, TIOCSETP, &tmode); 321 tmode.sg_flags = setflags(1); 322 prompt(); 323 if (PF > 0) { 324 oflush(); 325 sleep(PF); 326 PF = 0; 327 } 328 ioctl(0, TIOCSETP, &tmode); 329 crmod = digit = lower = upper = 0; 330 np = name; 331 for (;;) { 332 oflush(); 333 if (read(STDIN_FILENO, &cs, 1) <= 0) 334 exit(0); 335 if ((c = cs&0177) == 0) 336 return (0); 337 if (c == EOT) 338 exit(1); 339 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 340 putf("\r\n"); 341 break; 342 } 343 if (islower(c)) 344 lower = 1; 345 else if (isupper(c)) 346 upper = 1; 347 else if (c == ERASE || c == '#' || c == '\b') { 348 if (np > name) { 349 np--; 350 if (tmode.sg_ospeed >= B1200) 351 puts("\b \b"); 352 else 353 putchr(cs); 354 } 355 continue; 356 } else if (c == KILL || c == '@') { 357 putchr(cs); 358 putchr('\r'); 359 if (tmode.sg_ospeed < B1200) 360 putchr('\n'); 361 /* this is the way they do it down under ... */ 362 else if (np > name) 363 puts(" \r"); 364 prompt(); 365 np = name; 366 continue; 367 } else if (isdigit(c)) 368 digit++; 369 if (IG && (c <= ' ' || c > 0176)) 370 continue; 371 *np++ = c; 372 putchr(cs); 373 } 374 signal(SIGINT, SIG_IGN); 375 *np = 0; 376 if (c == '\r') 377 crmod = 1; 378 if (upper && !lower && !LC || UC) 379 for (np = name; *np; np++) 380 if (isupper(*np)) 381 *np = tolower(*np); 382 return (1); 383 } 384 385 static 386 short tmspc10[] = { 387 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15 388 }; 389 390 static void 391 putpad(s) 392 register char *s; 393 { 394 register pad = 0; 395 register mspc10; 396 397 if (isdigit(*s)) { 398 while (isdigit(*s)) { 399 pad *= 10; 400 pad += *s++ - '0'; 401 } 402 pad *= 10; 403 if (*s == '.' && isdigit(s[1])) { 404 pad += s[1] - '0'; 405 s += 2; 406 } 407 } 408 409 puts(s); 410 /* 411 * If no delay needed, or output speed is 412 * not comprehensible, then don't try to delay. 413 */ 414 if (pad == 0) 415 return; 416 if (tmode.sg_ospeed <= 0 || 417 tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) 418 return; 419 420 /* 421 * Round up by a half a character frame, and then do the delay. 422 * Too bad there are no user program accessible programmed delays. 423 * Transmitting pad characters slows many terminals down and also 424 * loads the system. 425 */ 426 mspc10 = tmspc10[tmode.sg_ospeed]; 427 pad += mspc10 / 2; 428 for (pad /= mspc10; pad > 0; pad--) 429 putchr(*PC); 430 } 431 432 static void 433 puts(s) 434 register char *s; 435 { 436 while (*s) 437 putchr(*s++); 438 } 439 440 char outbuf[OBUFSIZ]; 441 int obufcnt = 0; 442 443 static void 444 putchr(cc) 445 int cc; 446 { 447 char c; 448 449 c = cc; 450 if (!NP) { 451 c |= partab[c&0177] & 0200; 452 if (OP) 453 c ^= 0200; 454 } 455 if (!UB) { 456 outbuf[obufcnt++] = c; 457 if (obufcnt >= OBUFSIZ) 458 oflush(); 459 } else 460 write(STDOUT_FILENO, &c, 1); 461 } 462 463 static void 464 oflush() 465 { 466 if (obufcnt) 467 write(STDOUT_FILENO, outbuf, obufcnt); 468 obufcnt = 0; 469 } 470 471 static void 472 prompt() 473 { 474 475 putf(LM); 476 if (CO) 477 putchr('\n'); 478 } 479 480 static void 481 putf(cp) 482 register char *cp; 483 { 484 extern char editedhost[]; 485 time_t t; 486 char *slash, db[100]; 487 488 while (*cp) { 489 if (*cp != '%') { 490 putchr(*cp++); 491 continue; 492 } 493 switch (*++cp) { 494 495 case 't': 496 slash = strrchr(ttyn, '/'); 497 if (slash == (char *) 0) 498 puts(ttyn); 499 else 500 puts(&slash[1]); 501 break; 502 503 case 'h': 504 puts(editedhost); 505 break; 506 507 case 'd': { 508 static char fmt[] = "%l:% %P on %A, %d %B %Y"; 509 510 fmt[4] = 'M'; /* I *hate* SCCS... */ 511 (void)time(&t); 512 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 513 puts(db); 514 break; 515 } 516 517 case '%': 518 putchr('%'); 519 break; 520 } 521 cp++; 522 } 523 } 524