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