146043Sbostic /*- 246043Sbostic * Copyright (c) 1980 The Regents of the University of California. 346043Sbostic * All rights reserved. 446043Sbostic * 546043Sbostic * %sccs.include.redist.c% 619054Sdist */ 719054Sdist 813795Ssam #ifndef lint 919054Sdist char copyright[] = 1046043Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 1119054Sdist All rights reserved.\n"; 1246043Sbostic #endif /* not lint */ 1313795Ssam 1419054Sdist #ifndef lint 15*61459Smckusick static char sccsid[] = "@(#)main.c 5.21 (Berkeley) 06/04/93"; 1646043Sbostic #endif /* not lint */ 1719054Sdist 1846043Sbostic #define USE_OLD_TTY 1913795Ssam 2042459Smarc #include <sys/param.h> 2146670Sbostic #include <sys/stat.h> 22*61459Smckusick #include <sys/resource.h> 2360091Sbostic 2460091Sbostic #include <ctype.h> 2560091Sbostic #include <ctype.h> 2646670Sbostic #include <fcntl.h> 2760091Sbostic #include <setjmp.h> 2813795Ssam #include <sgtty.h> 2960091Sbostic #include <signal.h> 3060091Sbostic #include <stdlib.h> 3160091Sbostic #include <string.h> 3260091Sbostic #include <syslog.h> 3346670Sbostic #include <time.h> 3446043Sbostic #include <unistd.h> 3560091Sbostic 3613795Ssam #include "gettytab.h" 3742459Smarc #include "pathnames.h" 3860091Sbostic #include "extern.h" 3913795Ssam 40*61459Smckusick /* 41*61459Smckusick * Set the amount of running time that getty should accumulate 42*61459Smckusick * before deciding that something is wrong and exit. 43*61459Smckusick */ 44*61459Smckusick #define GETTY_TIMEOUT 60 /* seconds */ 45*61459Smckusick 4613795Ssam struct sgttyb tmode = { 4713795Ssam 0, 0, CERASE, CKILL, 0 4813795Ssam }; 4913795Ssam struct tchars tc = { 5013795Ssam CINTR, CQUIT, CSTART, 5113795Ssam CSTOP, CEOF, CBRK, 5213795Ssam }; 5313795Ssam struct ltchars ltc = { 5413795Ssam CSUSP, CDSUSP, CRPRNT, 5513795Ssam CFLUSH, CWERASE, CLNEXT 5613795Ssam }; 5713795Ssam 5846043Sbostic int crmod, digit, lower, upper; 5913795Ssam 6042459Smarc char hostname[MAXHOSTNAMELEN]; 6113795Ssam char name[16]; 6242459Smarc char dev[] = _PATH_DEV; 6318543Sralph char ttyn[32]; 6413795Ssam char *portselector(); 6518543Sralph char *ttyname(); 6613795Ssam 6713828Skre #define OBUFSIZ 128 6813795Ssam #define TABBUFSIZ 512 6913795Ssam 7013795Ssam char defent[TABBUFSIZ]; 7113795Ssam char tabent[TABBUFSIZ]; 7213795Ssam 7313795Ssam char *env[128]; 7413795Ssam 7513795Ssam char partab[] = { 7613795Ssam 0001,0201,0201,0001,0201,0001,0001,0201, 7713795Ssam 0202,0004,0003,0205,0005,0206,0201,0001, 7813795Ssam 0201,0001,0001,0201,0001,0201,0201,0001, 7913795Ssam 0001,0201,0201,0001,0201,0001,0001,0201, 8013795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 8113795Ssam 0000,0200,0200,0000,0200,0000,0000,0200, 8213795Ssam 0000,0200,0200,0000,0200,0000,0000,0200, 8313795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 8413795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 8513795Ssam 0000,0200,0200,0000,0200,0000,0000,0200, 8613795Ssam 0000,0200,0200,0000,0200,0000,0000,0200, 8713795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 8813795Ssam 0000,0200,0200,0000,0200,0000,0000,0200, 8913795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 9013795Ssam 0200,0000,0000,0200,0000,0200,0200,0000, 9113795Ssam 0000,0200,0200,0000,0200,0000,0000,0201 9213795Ssam }; 9313795Ssam 9413795Ssam #define ERASE tmode.sg_erase 9513795Ssam #define KILL tmode.sg_kill 9613795Ssam #define EOT tc.t_eofc 9713795Ssam 9813795Ssam jmp_buf timeout; 9913795Ssam 10046670Sbostic static void 10113795Ssam dingdong() 10213795Ssam { 10313795Ssam 10413795Ssam alarm(0); 10513795Ssam signal(SIGALRM, SIG_DFL); 10613795Ssam longjmp(timeout, 1); 10713795Ssam } 10813795Ssam 10913828Skre jmp_buf intrupt; 11013828Skre 11146670Sbostic static void 11213828Skre interrupt() 11313828Skre { 11413828Skre 11513828Skre signal(SIGINT, interrupt); 11613828Skre longjmp(intrupt, 1); 11713828Skre } 11813828Skre 119*61459Smckusick /* 120*61459Smckusick * Action to take when getty is running too long. 121*61459Smckusick */ 122*61459Smckusick void 123*61459Smckusick timeoverrun() 124*61459Smckusick { 125*61459Smckusick 126*61459Smckusick syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 127*61459Smckusick exit(1); 128*61459Smckusick } 129*61459Smckusick 13060091Sbostic static int getname __P((void)); 13160091Sbostic static void oflush __P((void)); 13260091Sbostic static void prompt __P((void)); 13360091Sbostic static void putchr __P((int)); 13460091Sbostic static void putf __P((char *)); 13560091Sbostic static void putpad __P((char *)); 13660091Sbostic static void puts __P((char *)); 13760091Sbostic 13860091Sbostic int 13913795Ssam main(argc, argv) 14046043Sbostic int argc; 14160091Sbostic char *argv[]; 14213795Ssam { 14360091Sbostic extern char **environ; 14413795Ssam char *tname; 14513795Ssam long allflags; 14618543Sralph int repcnt = 0; 147*61459Smckusick struct rlimit limit; 14813795Ssam 14913828Skre signal(SIGINT, SIG_IGN); 15013795Ssam /* 15113795Ssam signal(SIGQUIT, SIG_DFL); 15213795Ssam */ 15324890Seric openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH); 15413795Ssam gethostname(hostname, sizeof(hostname)); 15513795Ssam if (hostname[0] == '\0') 15613795Ssam strcpy(hostname, "Amnesiac"); 157*61459Smckusick 15818543Sralph /* 159*61459Smckusick * Limit running time to deal with broken or dead lines. 160*61459Smckusick */ 161*61459Smckusick signal(SIGXCPU, timeoverrun); 162*61459Smckusick limit.rlim_max = RLIM_INFINITY; 163*61459Smckusick limit.rlim_cur = GETTY_TIMEOUT; 164*61459Smckusick setrlimit(RLIMIT_CPU, &limit); 165*61459Smckusick 166*61459Smckusick /* 16718543Sralph * The following is a work around for vhangup interactions 16818543Sralph * which cause great problems getting window systems started. 16918543Sralph * If the tty line is "-", we do the old style getty presuming 17018543Sralph * that the file descriptors are already set up for us. 17118543Sralph * J. Gettys - MIT Project Athena. 17218543Sralph */ 17318543Sralph if (argc <= 2 || strcmp(argv[2], "-") == 0) 17425954Sbloom strcpy(ttyn, ttyname(0)); 17518543Sralph else { 17644567Smarc int i; 17744567Smarc 17825954Sbloom strcpy(ttyn, dev); 17925954Sbloom strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 18025954Sbloom if (strcmp(argv[0], "+") != 0) { 18118543Sralph chown(ttyn, 0, 0); 18244567Smarc chmod(ttyn, 0600); 18344567Smarc revoke(ttyn); 18425553Smckusick /* 18525553Smckusick * Delay the open so DTR stays down long enough to be detected. 18625553Smckusick */ 18725553Smckusick sleep(2); 18844567Smarc while ((i = open(ttyn, O_RDWR)) == -1) { 18918543Sralph if (repcnt % 10 == 0) { 19024895Seric syslog(LOG_ERR, "%s: %m", ttyn); 19118543Sralph closelog(); 19218543Sralph } 19318543Sralph repcnt++; 19418543Sralph sleep(60); 19518543Sralph } 19644567Smarc login_tty(i); 19725954Sbloom } 19818543Sralph } 19918543Sralph 20060499Selan gettable("default", defent); 20113795Ssam gendefaults(); 20213795Ssam tname = "default"; 20313795Ssam if (argc > 1) 20413795Ssam tname = argv[1]; 20513795Ssam for (;;) { 20653076Sbostic int off; 20713795Ssam 20860499Selan gettable(tname, tabent); 20913828Skre if (OPset || EPset || APset) 21013828Skre APset++, OPset++, EPset++; 21113795Ssam setdefaults(); 21253076Sbostic off = 0; 21353076Sbostic ioctl(0, TIOCFLUSH, &off); /* clear out the crap */ 21432209Sbostic ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 21546043Sbostic ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 21613795Ssam if (IS) 21713795Ssam tmode.sg_ispeed = speed(IS); 21813795Ssam else if (SP) 21913795Ssam tmode.sg_ispeed = speed(SP); 22013795Ssam if (OS) 22113795Ssam tmode.sg_ospeed = speed(OS); 22213795Ssam else if (SP) 22313795Ssam tmode.sg_ospeed = speed(SP); 22413795Ssam tmode.sg_flags = setflags(0); 22513795Ssam ioctl(0, TIOCSETP, &tmode); 22613795Ssam setchars(); 22713795Ssam ioctl(0, TIOCSETC, &tc); 22813795Ssam if (HC) 22913795Ssam ioctl(0, TIOCHPCL, 0); 23018543Sralph if (AB) { 23118543Sralph extern char *autobaud(); 23218543Sralph 23318543Sralph tname = autobaud(); 23418543Sralph continue; 23518543Sralph } 23613795Ssam if (PS) { 23713795Ssam tname = portselector(); 23813795Ssam continue; 23913795Ssam } 24013795Ssam if (CL && *CL) 24113795Ssam putpad(CL); 24213795Ssam edithost(HE); 24313795Ssam if (IM && *IM) 24413795Ssam putf(IM); 24513795Ssam if (setjmp(timeout)) { 24613795Ssam tmode.sg_ispeed = tmode.sg_ospeed = 0; 24713795Ssam ioctl(0, TIOCSETP, &tmode); 24813795Ssam exit(1); 24913795Ssam } 25013795Ssam if (TO) { 25113795Ssam signal(SIGALRM, dingdong); 25213795Ssam alarm(TO); 25313795Ssam } 25413795Ssam if (getname()) { 25518543Sralph register int i; 25618543Sralph 25718543Sralph oflush(); 25813795Ssam alarm(0); 25913795Ssam signal(SIGALRM, SIG_DFL); 26032308Sbostic if (name[0] == '-') { 26142459Smarc puts("user names may not start with '-'."); 26232308Sbostic continue; 26332308Sbostic } 26413831Ssam if (!(upper || lower || digit)) 26513795Ssam continue; 26613795Ssam allflags = setflags(2); 26713795Ssam tmode.sg_flags = allflags & 0xffff; 26813795Ssam allflags >>= 16; 26913795Ssam if (crmod || NL) 27013795Ssam tmode.sg_flags |= CRMOD; 27113795Ssam if (upper || UC) 27213795Ssam tmode.sg_flags |= LCASE; 27313795Ssam if (lower || LC) 27413795Ssam tmode.sg_flags &= ~LCASE; 27513795Ssam ioctl(0, TIOCSETP, &tmode); 27613795Ssam ioctl(0, TIOCSLTC, <c); 27713795Ssam ioctl(0, TIOCLSET, &allflags); 27813828Skre signal(SIGINT, SIG_DFL); 27918543Sralph for (i = 0; environ[i] != (char *)0; i++) 28018543Sralph env[i] = environ[i]; 28118543Sralph makeenv(&env[i]); 28244640Smarc 28344640Smarc /* 28444640Smarc * this is what login was doing anyway. 28544640Smarc * soon we rewrite getty completely. 28644640Smarc */ 28744640Smarc set_ttydefaults(0); 28818543Sralph execle(LO, "login", "-p", name, (char *) 0, env); 28932209Sbostic syslog(LOG_ERR, "%s: %m", LO); 29013795Ssam exit(1); 29113795Ssam } 29213795Ssam alarm(0); 29313795Ssam signal(SIGALRM, SIG_DFL); 29413828Skre signal(SIGINT, SIG_IGN); 29513795Ssam if (NX && *NX) 29613795Ssam tname = NX; 29713795Ssam } 29813795Ssam } 29913795Ssam 30060091Sbostic static int 30113795Ssam getname() 30213795Ssam { 30346043Sbostic register int c; 30413795Ssam register char *np; 30513795Ssam char cs; 30613795Ssam 30713828Skre /* 30813831Ssam * Interrupt may happen if we use CBREAK mode 30913828Skre */ 31013828Skre if (setjmp(intrupt)) { 31113828Skre signal(SIGINT, SIG_IGN); 31213828Skre return (0); 31313828Skre } 31413828Skre signal(SIGINT, interrupt); 31513795Ssam tmode.sg_flags = setflags(0); 31613795Ssam ioctl(0, TIOCSETP, &tmode); 31713795Ssam tmode.sg_flags = setflags(1); 31813795Ssam prompt(); 31913885Ssam if (PF > 0) { 32014322Ssam oflush(); 32113885Ssam sleep(PF); 32213885Ssam PF = 0; 32313885Ssam } 32413795Ssam ioctl(0, TIOCSETP, &tmode); 32546043Sbostic crmod = digit = lower = upper = 0; 32613795Ssam np = name; 32713795Ssam for (;;) { 32813828Skre oflush(); 32946043Sbostic if (read(STDIN_FILENO, &cs, 1) <= 0) 33013795Ssam exit(0); 33113795Ssam if ((c = cs&0177) == 0) 33213795Ssam return (0); 33313831Ssam if (c == EOT) 33413795Ssam exit(1); 33518543Sralph if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 33618543Sralph putf("\r\n"); 33713795Ssam break; 33818543Sralph } 33942459Smarc if (islower(c)) 34046043Sbostic lower = 1; 34142459Smarc else if (isupper(c)) 34246043Sbostic upper = 1; 34318543Sralph else if (c == ERASE || c == '#' || c == '\b') { 34413795Ssam if (np > name) { 34513795Ssam np--; 34613795Ssam if (tmode.sg_ospeed >= B1200) 34713795Ssam puts("\b \b"); 34813795Ssam else 34913795Ssam putchr(cs); 35013795Ssam } 35113795Ssam continue; 35213831Ssam } else if (c == KILL || c == '@') { 35313795Ssam putchr(cs); 35413795Ssam putchr('\r'); 35513795Ssam if (tmode.sg_ospeed < B1200) 35613795Ssam putchr('\n'); 35713795Ssam /* this is the way they do it down under ... */ 35813795Ssam else if (np > name) 35913795Ssam puts(" \r"); 36013795Ssam prompt(); 36113795Ssam np = name; 36213795Ssam continue; 36342459Smarc } else if (isdigit(c)) 36413795Ssam digit++; 36518543Sralph if (IG && (c <= ' ' || c > 0176)) 36613795Ssam continue; 36713795Ssam *np++ = c; 36813795Ssam putchr(cs); 36913795Ssam } 37013828Skre signal(SIGINT, SIG_IGN); 37113795Ssam *np = 0; 37213795Ssam if (c == '\r') 37346043Sbostic crmod = 1; 37413795Ssam if (upper && !lower && !LC || UC) 37513795Ssam for (np = name; *np; np++) 37613795Ssam if (isupper(*np)) 37713795Ssam *np = tolower(*np); 37813795Ssam return (1); 37913795Ssam } 38013795Ssam 38113795Ssam static 38213795Ssam short tmspc10[] = { 38313795Ssam 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15 38413795Ssam }; 38513795Ssam 38660091Sbostic static void 38713795Ssam putpad(s) 38813795Ssam register char *s; 38913795Ssam { 39013795Ssam register pad = 0; 39113795Ssam register mspc10; 39213795Ssam 39313795Ssam if (isdigit(*s)) { 39413795Ssam while (isdigit(*s)) { 39513795Ssam pad *= 10; 39613795Ssam pad += *s++ - '0'; 39713795Ssam } 39813795Ssam pad *= 10; 39913795Ssam if (*s == '.' && isdigit(s[1])) { 40013795Ssam pad += s[1] - '0'; 40113795Ssam s += 2; 40213795Ssam } 40313795Ssam } 40413795Ssam 40513795Ssam puts(s); 40613795Ssam /* 40713795Ssam * If no delay needed, or output speed is 40813795Ssam * not comprehensible, then don't try to delay. 40913795Ssam */ 41013795Ssam if (pad == 0) 41113795Ssam return; 41213795Ssam if (tmode.sg_ospeed <= 0 || 41313795Ssam tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) 41413795Ssam return; 41513795Ssam 41613795Ssam /* 41746043Sbostic * Round up by a half a character frame, and then do the delay. 41813795Ssam * Too bad there are no user program accessible programmed delays. 41946043Sbostic * Transmitting pad characters slows many terminals down and also 42046043Sbostic * loads the system. 42113795Ssam */ 42213795Ssam mspc10 = tmspc10[tmode.sg_ospeed]; 42313795Ssam pad += mspc10 / 2; 42413795Ssam for (pad /= mspc10; pad > 0; pad--) 42513795Ssam putchr(*PC); 42613795Ssam } 42713795Ssam 42860091Sbostic static void 42913795Ssam puts(s) 43013795Ssam register char *s; 43113795Ssam { 43213795Ssam while (*s) 43313795Ssam putchr(*s++); 43413795Ssam } 43513795Ssam 43613828Skre char outbuf[OBUFSIZ]; 43713828Skre int obufcnt = 0; 43813828Skre 43960091Sbostic static void 44013795Ssam putchr(cc) 44160091Sbostic int cc; 44213795Ssam { 44313795Ssam char c; 44413795Ssam 44513795Ssam c = cc; 44647664Swilliam if (!NP) { 44747664Swilliam c |= partab[c&0177] & 0200; 44847664Swilliam if (OP) 44947664Swilliam c ^= 0200; 45047664Swilliam } 45113828Skre if (!UB) { 45213828Skre outbuf[obufcnt++] = c; 45313828Skre if (obufcnt >= OBUFSIZ) 45413828Skre oflush(); 45513828Skre } else 45646043Sbostic write(STDOUT_FILENO, &c, 1); 45713795Ssam } 45813795Ssam 45960091Sbostic static void 46013828Skre oflush() 46113828Skre { 46213828Skre if (obufcnt) 46346043Sbostic write(STDOUT_FILENO, outbuf, obufcnt); 46413828Skre obufcnt = 0; 46513828Skre } 46613828Skre 46760091Sbostic static void 46813795Ssam prompt() 46913795Ssam { 47013795Ssam 47113795Ssam putf(LM); 47213795Ssam if (CO) 47313795Ssam putchr('\n'); 47413795Ssam } 47513795Ssam 47660091Sbostic static void 47713795Ssam putf(cp) 47813795Ssam register char *cp; 47913795Ssam { 48013795Ssam extern char editedhost[]; 48146043Sbostic time_t t; 48246670Sbostic char *slash, db[100]; 48313795Ssam 48413795Ssam while (*cp) { 48513795Ssam if (*cp != '%') { 48613795Ssam putchr(*cp++); 48713795Ssam continue; 48813795Ssam } 48913795Ssam switch (*++cp) { 49013795Ssam 49118543Sralph case 't': 49260091Sbostic slash = strrchr(ttyn, '/'); 49318543Sralph if (slash == (char *) 0) 49418543Sralph puts(ttyn); 49518543Sralph else 49618543Sralph puts(&slash[1]); 49718543Sralph break; 49818543Sralph 49913795Ssam case 'h': 50013795Ssam puts(editedhost); 50113795Ssam break; 50213795Ssam 50346670Sbostic case 'd': { 50446967Sbostic static char fmt[] = "%l:% %P on %A, %d %B %Y"; 50546670Sbostic 50646670Sbostic fmt[4] = 'M'; /* I *hate* SCCS... */ 50746043Sbostic (void)time(&t); 50846670Sbostic (void)strftime(db, sizeof(db), fmt, localtime(&t)); 50946043Sbostic puts(db); 51015713Sralph break; 51146670Sbostic } 51215713Sralph 51313795Ssam case '%': 51413795Ssam putchr('%'); 51513795Ssam break; 51613795Ssam } 51713795Ssam cp++; 51813795Ssam } 51913795Ssam } 520