1 /*- 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)main.c 5.16 (Berkeley) 3/27/91"; 42 #endif /* not lint */ 43 44 #define USE_OLD_TTY 45 46 #include <sys/param.h> 47 #include <sys/stat.h> 48 #include <signal.h> 49 #include <fcntl.h> 50 #include <sgtty.h> 51 #include <time.h> 52 #include <ctype.h> 53 #include <setjmp.h> 54 #include <syslog.h> 55 #include <unistd.h> 56 #include <ctype.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include "gettytab.h" 60 #include "pathnames.h" 61 62 struct sgttyb tmode = { 63 0, 0, CERASE, CKILL, 0 64 }; 65 struct tchars tc = { 66 CINTR, CQUIT, CSTART, 67 CSTOP, CEOF, CBRK, 68 }; 69 struct ltchars ltc = { 70 CSUSP, CDSUSP, CRPRNT, 71 CFLUSH, CWERASE, CLNEXT 72 }; 73 74 int crmod, digit, lower, upper; 75 76 char hostname[MAXHOSTNAMELEN]; 77 char name[16]; 78 char dev[] = _PATH_DEV; 79 char ttyn[32]; 80 char *portselector(); 81 char *ttyname(); 82 83 #define OBUFSIZ 128 84 #define TABBUFSIZ 512 85 86 char defent[TABBUFSIZ]; 87 char defstrs[TABBUFSIZ]; 88 char tabent[TABBUFSIZ]; 89 char tabstrs[TABBUFSIZ]; 90 91 char *env[128]; 92 93 char partab[] = { 94 0001,0201,0201,0001,0201,0001,0001,0201, 95 0202,0004,0003,0205,0005,0206,0201,0001, 96 0201,0001,0001,0201,0001,0201,0201,0001, 97 0001,0201,0201,0001,0201,0001,0001,0201, 98 0200,0000,0000,0200,0000,0200,0200,0000, 99 0000,0200,0200,0000,0200,0000,0000,0200, 100 0000,0200,0200,0000,0200,0000,0000,0200, 101 0200,0000,0000,0200,0000,0200,0200,0000, 102 0200,0000,0000,0200,0000,0200,0200,0000, 103 0000,0200,0200,0000,0200,0000,0000,0200, 104 0000,0200,0200,0000,0200,0000,0000,0200, 105 0200,0000,0000,0200,0000,0200,0200,0000, 106 0000,0200,0200,0000,0200,0000,0000,0200, 107 0200,0000,0000,0200,0000,0200,0200,0000, 108 0200,0000,0000,0200,0000,0200,0200,0000, 109 0000,0200,0200,0000,0200,0000,0000,0201 110 }; 111 112 #define ERASE tmode.sg_erase 113 #define KILL tmode.sg_kill 114 #define EOT tc.t_eofc 115 116 jmp_buf timeout; 117 118 static void 119 dingdong() 120 { 121 122 alarm(0); 123 signal(SIGALRM, SIG_DFL); 124 longjmp(timeout, 1); 125 } 126 127 jmp_buf intrupt; 128 129 static void 130 interrupt() 131 { 132 133 signal(SIGINT, interrupt); 134 longjmp(intrupt, 1); 135 } 136 137 main(argc, argv) 138 int argc; 139 char **argv; 140 { 141 extern char **environ; 142 char *tname; 143 int repcnt = 0; 144 145 signal(SIGINT, SIG_IGN); 146 signal(SIGQUIT, SIG_IGN); 147 148 openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH); 149 gethostname(hostname, sizeof(hostname)); 150 if (hostname[0] == '\0') 151 strcpy(hostname, "Amnesiac"); 152 /* 153 * The following is a work around for vhangup interactions 154 * which cause great problems getting window systems started. 155 * If the tty line is "-", we do the old style getty presuming 156 * that the file descriptors are already set up for us. 157 * J. Gettys - MIT Project Athena. 158 */ 159 if (argc <= 2 || strcmp(argv[2], "-") == 0) 160 strcpy(ttyn, ttyname(0)); 161 else { 162 int i; 163 164 strcpy(ttyn, dev); 165 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 166 if (strcmp(argv[0], "+") != 0) { 167 chown(ttyn, 0, 0); 168 chmod(ttyn, 0600); 169 revoke(ttyn); 170 while ((i = open(ttyn, O_RDWR)) == -1) { 171 if (repcnt % 10 == 0) { 172 syslog(LOG_ERR, "%s: %m", ttyn); 173 closelog(); 174 } 175 repcnt++; 176 sleep(60); 177 } 178 login_tty(i); 179 } 180 } 181 182 gettable("default", defent, defstrs); 183 gendefaults(); 184 tname = "default"; 185 if (argc > 1) 186 tname = argv[1]; 187 for (;;) { 188 int off = 0; 189 int flushboth = 0; 190 struct sgttyb fake; 191 192 gettable(tname, tabent, tabstrs); 193 if (OPset || EPset || APset) 194 APset++, OPset++, EPset++; 195 setdefaults(); 196 ioctl(0, TIOCFLUSH, &flushboth); /* clear out the crap */ 197 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 198 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 199 ioctl(0, TIOCGETP, &fake); /* initialize kernel termios */ 200 if (IS) 201 tmode.sg_ispeed = speed(IS); 202 else if (SP) 203 tmode.sg_ispeed = speed(SP); 204 if (OS) 205 tmode.sg_ospeed = speed(OS); 206 else if (SP) 207 tmode.sg_ospeed = speed(SP); 208 set_tmode(0); 209 setchars(); 210 ioctl(0, TIOCSETC, &tc); 211 if (HC) 212 ioctl(0, TIOCHPCL, 0); 213 if (AB) { 214 extern char *autobaud(); 215 216 tname = autobaud(); 217 continue; 218 } 219 if (PS) { 220 tname = portselector(); 221 continue; 222 } 223 if (CL && *CL) 224 putpad(CL); 225 edithost(HE); 226 if (IM && *IM) 227 putf(IM); 228 if (setjmp(timeout)) { 229 tmode.sg_ispeed = tmode.sg_ospeed = 0; 230 ioctl(0, TIOCSETP, &tmode); 231 exit(1); 232 } 233 if (TO) { 234 signal(SIGALRM, dingdong); 235 alarm(TO); 236 } 237 if (getname()) { 238 register int i; 239 240 alarm(0); 241 signal(SIGALRM, SIG_DFL); 242 oflush(); 243 if (name[0] == '-') { 244 puts("user names may not start with '-'."); 245 continue; 246 } 247 if (!(upper || lower || digit)) 248 continue; 249 set_tmode(2); 250 ioctl(0, TIOCSLTC, <c); 251 for (i = 0; environ[i] != (char *)0; i++) 252 env[i] = environ[i]; 253 makeenv(&env[i]); 254 255 execle(LO, "login", "-p", name, (char *) 0, env); 256 syslog(LOG_ERR, "%s: %m", LO); 257 exit(1); 258 } 259 signal(SIGINT, SIG_IGN); 260 alarm(0); 261 signal(SIGALRM, SIG_DFL); 262 if (NX && *NX) 263 tname = NX; 264 } 265 } 266 267 getname() 268 { 269 register int c; 270 register char *np; 271 char cs; 272 int flushin = 1 /*FREAD*/; 273 274 /* 275 * Interrupt may happen if we use CBREAK mode 276 */ 277 if (setjmp(intrupt)) { 278 signal(SIGINT, SIG_IGN); 279 return (0); 280 } 281 signal(SIGINT, interrupt); 282 ioctl(0, TIOCFLUSH, &flushin); /* purge any input */ 283 prompt(); 284 oflush(); 285 if (PF > 0) { 286 sleep(PF); 287 PF = 0; 288 } 289 set_tmode(1); 290 crmod = digit = lower = upper = 0; 291 np = name; 292 for (;;) { 293 oflush(); 294 if (read(STDIN_FILENO, &cs, 1) <= 0) 295 exit(0); 296 if ((c = cs&0177) == 0) 297 return (0); 298 if (c == EOT || c == 4 /*^D*/) 299 exit(1); 300 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 301 putf("\r\n"); 302 break; 303 } 304 if (islower(c)) 305 lower = 1; 306 else if (isupper(c)) 307 upper = 1; 308 else if (c == ERASE || c == '\b' || c == 0177) { 309 if (np > name) { 310 np--; 311 if (tmode.sg_ospeed >= B1200) 312 puts("\b \b"); 313 else 314 putchr(cs); 315 } 316 continue; 317 } else if (c == KILL || c == 025 /*^U*/) { 318 putchr('\r'); 319 if (tmode.sg_ospeed < B1200) 320 putchr('\n'); 321 /* this is the way they do it down under ... */ 322 else if (np > name) 323 puts(" \r"); 324 prompt(); 325 np = name; 326 continue; 327 } else if (isdigit(c)) 328 digit++; 329 if (IG && (c <= ' ' || c > 0176)) 330 continue; 331 *np++ = c; 332 putchr(cs); 333 } 334 signal(SIGINT, SIG_IGN); 335 *np = 0; 336 if (c == '\r') 337 crmod = 1; 338 if (upper && !lower && !LC || UC) 339 for (np = name; *np; np++) 340 if (isupper(*np)) 341 *np = tolower(*np); 342 return (1); 343 } 344 345 static 346 short tmspc10[] = { 347 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15 348 }; 349 350 putpad(s) 351 register char *s; 352 { 353 register pad = 0; 354 register mspc10; 355 356 if (isdigit(*s)) { 357 while (isdigit(*s)) { 358 pad *= 10; 359 pad += *s++ - '0'; 360 } 361 pad *= 10; 362 if (*s == '.' && isdigit(s[1])) { 363 pad += s[1] - '0'; 364 s += 2; 365 } 366 } 367 368 puts(s); 369 /* 370 * If no delay needed, or output speed is 371 * not comprehensible, then don't try to delay. 372 */ 373 if (pad == 0) 374 return; 375 if (tmode.sg_ospeed <= 0 || 376 tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) 377 return; 378 379 /* 380 * Round up by a half a character frame, and then do the delay. 381 * Too bad there are no user program accessible programmed delays. 382 * Transmitting pad characters slows many terminals down and also 383 * loads the system. 384 */ 385 mspc10 = tmspc10[tmode.sg_ospeed]; 386 pad += mspc10 / 2; 387 for (pad /= mspc10; pad > 0; pad--) 388 putchr(*PC); 389 } 390 391 puts(s) 392 register char *s; 393 { 394 while (*s) 395 putchr(*s++); 396 } 397 398 char outbuf[OBUFSIZ]; 399 int obufcnt = 0; 400 401 putchr(cc) 402 { 403 char c; 404 405 c = cc; 406 if (!NP) { 407 c |= partab[c&0177] & 0200; 408 if (OP) 409 c ^= 0200; 410 } 411 if (!UB) { 412 outbuf[obufcnt++] = c; 413 if (obufcnt >= OBUFSIZ) 414 oflush(); 415 } else 416 write(STDOUT_FILENO, &c, 1); 417 } 418 419 oflush() 420 { 421 if (obufcnt) 422 write(STDOUT_FILENO, outbuf, obufcnt); 423 obufcnt = 0; 424 } 425 426 prompt() 427 { 428 429 putf(LM); 430 if (CO) 431 putchr('\n'); 432 } 433 434 putf(cp) 435 register char *cp; 436 { 437 extern char editedhost[]; 438 time_t t; 439 char *slash, db[100]; 440 441 while (*cp) { 442 if (*cp != '%') { 443 putchr(*cp++); 444 continue; 445 } 446 switch (*++cp) { 447 448 case 't': 449 slash = rindex(ttyn, '/'); 450 if (slash == (char *) 0) 451 puts(ttyn); 452 else 453 puts(&slash[1]); 454 break; 455 456 case 'h': 457 puts(editedhost); 458 break; 459 460 case 'd': { 461 static char fmt[] = "%l:% %p on %A, %d %B %Y"; 462 463 fmt[4] = 'M'; /* I *hate* SCCS... */ 464 (void)time(&t); 465 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 466 puts(db); 467 break; 468 } 469 470 case '%': 471 putchr('%'); 472 break; 473 } 474 cp++; 475 } 476 } 477 478 /* 479 * The conversions from sgttyb to termios make LITOUT and PASS8 affect 480 * the parity. So every TIOCSETP ioctl has to be paired with a TIOCLSET 481 * ioctl (at least if LITOUT or PASS8 has changed, and PASS8 may vary 482 * with 'n'). 483 */ 484 set_tmode(n) 485 int n; 486 { 487 long allflags; 488 489 allflags = setflags(n); 490 tmode.sg_flags = allflags & 0xffff; 491 allflags >>= 16; 492 if (n == 2) { 493 if (crmod || NL) 494 tmode.sg_flags |= CRMOD; 495 if (upper || UC) 496 tmode.sg_flags |= LCASE; 497 if (lower || LC) 498 tmode.sg_flags &= ~LCASE; 499 } 500 ioctl(0, TIOCSETP, &tmode); 501 ioctl(0, TIOCLSET, &allflags); 502 } 503