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