Home | History | Annotate | Line # | Download | only in getty
main.c revision 1.20
      1 /*	$NetBSD: main.c,v 1.20 1997/04/29 21:01:54 tls Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #ifndef lint
     37 static char copyright[] =
     38 "@(#) Copyright (c) 1980, 1993\n\
     39 	The Regents of the University of California.  All rights reserved.\n";
     40 #endif /* not lint */
     41 
     42 #ifndef lint
     43 #if 0
     44 static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";
     45 #else
     46 static char rcsid[] = "$NetBSD: main.c,v 1.20 1997/04/29 21:01:54 tls Exp $";
     47 #endif
     48 #endif /* not lint */
     49 
     50 #include <sys/param.h>
     51 #include <sys/stat.h>
     52 #include <termios.h>
     53 #include <sys/ioctl.h>
     54 #include <sys/resource.h>
     55 #include <sys/utsname.h>
     56 #include <errno.h>
     57 #include <signal.h>
     58 #include <fcntl.h>
     59 #include <time.h>
     60 #include <ctype.h>
     61 #include <fcntl.h>
     62 #include <setjmp.h>
     63 #include <signal.h>
     64 #include <stdlib.h>
     65 #include <string.h>
     66 #include <syslog.h>
     67 #include <time.h>
     68 #include <unistd.h>
     69 #include <util.h>
     70 
     71 #include "gettytab.h"
     72 #include "pathnames.h"
     73 #include "extern.h"
     74 
     75 /*
     76  * Set the amount of running time that getty should accumulate
     77  * before deciding that something is wrong and exit.
     78  */
     79 #define GETTY_TIMEOUT	60 /* seconds */
     80 
     81 struct termios tmode, omode;
     82 
     83 int crmod, digit, lower, upper;
     84 
     85 char	hostname[MAXHOSTNAMELEN];
     86 struct	utsname kerninfo;
     87 char	name[16];
     88 char	dev[] = _PATH_DEV;
     89 char	ttyn[32];
     90 char	*portselector();
     91 char	*ttyname();
     92 
     93 #define	OBUFSIZ		128
     94 #define	TABBUFSIZ	512
     95 
     96 char	defent[TABBUFSIZ];
     97 char	tabent[TABBUFSIZ];
     98 
     99 char	*env[128];
    100 
    101 char partab[] = {
    102 	0001,0201,0201,0001,0201,0001,0001,0201,
    103 	0202,0004,0003,0205,0005,0206,0201,0001,
    104 	0201,0001,0001,0201,0001,0201,0201,0001,
    105 	0001,0201,0201,0001,0201,0001,0001,0201,
    106 	0200,0000,0000,0200,0000,0200,0200,0000,
    107 	0000,0200,0200,0000,0200,0000,0000,0200,
    108 	0000,0200,0200,0000,0200,0000,0000,0200,
    109 	0200,0000,0000,0200,0000,0200,0200,0000,
    110 	0200,0000,0000,0200,0000,0200,0200,0000,
    111 	0000,0200,0200,0000,0200,0000,0000,0200,
    112 	0000,0200,0200,0000,0200,0000,0000,0200,
    113 	0200,0000,0000,0200,0000,0200,0200,0000,
    114 	0000,0200,0200,0000,0200,0000,0000,0200,
    115 	0200,0000,0000,0200,0000,0200,0200,0000,
    116 	0200,0000,0000,0200,0000,0200,0200,0000,
    117 	0000,0200,0200,0000,0200,0000,0000,0201
    118 };
    119 
    120 #define	ERASE	tmode.c_cc[VERASE]
    121 #define	KILL	tmode.c_cc[VKILL]
    122 #define	EOT	tmode.c_cc[VEOF]
    123 
    124 jmp_buf timeout;
    125 
    126 static void
    127 dingdong()
    128 {
    129 
    130 	alarm(0);
    131 	signal(SIGALRM, SIG_DFL);
    132 	longjmp(timeout, 1);
    133 }
    134 
    135 jmp_buf	intrupt;
    136 
    137 static void
    138 interrupt()
    139 {
    140 
    141 	signal(SIGINT, interrupt);
    142 	longjmp(intrupt, 1);
    143 }
    144 
    145 /*
    146  * Action to take when getty is running too long.
    147  */
    148 void
    149 timeoverrun(signo)
    150 	int signo;
    151 {
    152 
    153 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
    154 	exit(1);
    155 }
    156 
    157 static int	getname __P((void));
    158 static void	oflush __P((void));
    159 static void	prompt __P((void));
    160 static void	putchr __P((int));
    161 static void	putf __P((char *));
    162 static void	putpad __P((char *));
    163 static void	puts __P((char *));
    164 
    165 int
    166 main(argc, argv)
    167 	int argc;
    168 	char *argv[];
    169 {
    170 	extern char **environ;
    171 	char *tname;
    172 	long allflags;
    173 	int repcnt = 0, failopenlogged = 0;
    174 	struct rlimit limit;
    175 
    176 	signal(SIGINT, SIG_IGN);
    177 /*
    178 	signal(SIGQUIT, SIG_DFL);
    179 */
    180 	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
    181 	gethostname(hostname, sizeof(hostname));
    182 	if (hostname[0] == '\0')
    183 		strcpy(hostname, "Amnesiac");
    184 	uname(&kerninfo);
    185 
    186 	/*
    187 	 * Limit running time to deal with broken or dead lines.
    188 	 */
    189 	(void)signal(SIGXCPU, timeoverrun);
    190 	limit.rlim_max = RLIM_INFINITY;
    191 	limit.rlim_cur = GETTY_TIMEOUT;
    192 	(void)setrlimit(RLIMIT_CPU, &limit);
    193 
    194 	/*
    195 	 * The following is a work around for vhangup interactions
    196 	 * which cause great problems getting window systems started.
    197 	 * If the tty line is "-", we do the old style getty presuming
    198 	 * that the file descriptors are already set up for us.
    199 	 * J. Gettys - MIT Project Athena.
    200 	 */
    201 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
    202 	    strncpy(ttyn, ttyname(0), 32);
    203 	    ttyn[31] = (char)NULL;
    204 	}
    205 	else {
    206 	    int i;
    207 
    208 	    strcpy(ttyn, dev);
    209 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
    210 	    if (strcmp(argv[0], "+") != 0) {
    211 		chown(ttyn, 0, 0);
    212 		chmod(ttyn, 0600);
    213 		revoke(ttyn);
    214 		if (ttyaction(ttyn, "getty", "root"))
    215 			syslog(LOG_ERR,"%s: ttyaction failed", ttyn);
    216 		/*
    217 		 * Delay the open so DTR stays down long enough to be detected.
    218 		 */
    219 		sleep(2);
    220 		while ((i = open(ttyn, O_RDWR)) == -1) {
    221 			if ((repcnt % 10 == 0) &&
    222 			    (errno != ENXIO || !failopenlogged)) {
    223 				syslog(LOG_ERR, "%s: %m", ttyn);
    224 				closelog();
    225 				failopenlogged = 1;
    226 			}
    227 			repcnt++;
    228 			sleep(60);
    229 		}
    230 		login_tty(i);
    231 	    }
    232 	}
    233 
    234 	/* Start with default tty settings */
    235 	if (tcgetattr(0, &tmode) < 0) {
    236 		syslog(LOG_ERR, "%s: %m", ttyn);
    237 		exit(1);
    238 	}
    239 	omode = tmode;
    240 
    241 	gettable("default", defent);
    242 	gendefaults();
    243 	tname = "default";
    244 	if (argc > 1)
    245 		tname = argv[1];
    246 	for (;;) {
    247 		int off;
    248 
    249 		gettable(tname, tabent);
    250 		if (OPset || EPset || APset)
    251 			APset++, OPset++, EPset++;
    252 		setdefaults();
    253 		off = 0;
    254 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
    255 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
    256 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
    257 
    258 		if (IS)
    259 			cfsetispeed(&tmode, IS);
    260 		else if (SP)
    261 			cfsetispeed(&tmode, SP);
    262 		if (OS)
    263 			cfsetospeed(&tmode, OS);
    264 		else if (SP)
    265 			cfsetospeed(&tmode, SP);
    266 		setflags(0);
    267 		setchars();
    268 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    269 			syslog(LOG_ERR, "%s: %m", ttyn);
    270 			exit(1);
    271 		}
    272 		if (AB) {
    273 			extern char *autobaud();
    274 
    275 			tname = autobaud();
    276 			continue;
    277 		}
    278 		if (PS) {
    279 			tname = portselector();
    280 			continue;
    281 		}
    282 		if (CL && *CL)
    283 			putpad(CL);
    284 		edithost(HE);
    285 		if (IM && *IM)
    286 			putf(IM);
    287 		if (setjmp(timeout)) {
    288 			tmode.c_ispeed = tmode.c_ospeed = 0;
    289 			(void)tcsetattr(0, TCSANOW, &tmode);
    290 			exit(1);
    291 		}
    292 		if (TO) {
    293 			signal(SIGALRM, dingdong);
    294 			alarm(TO);
    295 		}
    296 		if (getname()) {
    297 			register int i;
    298 
    299 			oflush();
    300 			alarm(0);
    301 			signal(SIGALRM, SIG_DFL);
    302 			if (name[0] == '-') {
    303 				puts("user names may not start with '-'.");
    304 				continue;
    305 			}
    306 			if (!(upper || lower || digit))
    307 				continue;
    308 			setflags(2);
    309 			if (crmod) {
    310 				tmode.c_iflag |= ICRNL;
    311 				tmode.c_oflag |= ONLCR;
    312 			}
    313 #if XXX
    314 			if (upper || UC)
    315 				tmode.sg_flags |= LCASE;
    316 			if (lower || LC)
    317 				tmode.sg_flags &= ~LCASE;
    318 #endif
    319 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    320 				syslog(LOG_ERR, "%s: %m", ttyn);
    321 				exit(1);
    322 			}
    323 			signal(SIGINT, SIG_DFL);
    324 			for (i = 0; environ[i] != (char *)0; i++)
    325 				env[i] = environ[i];
    326 			makeenv(&env[i]);
    327 
    328 			limit.rlim_max = RLIM_INFINITY;
    329 			limit.rlim_cur = RLIM_INFINITY;
    330 			(void)setrlimit(RLIMIT_CPU, &limit);
    331 			execle(LO, "login", "-p", "--", name, (char *)0, env);
    332 			syslog(LOG_ERR, "%s: %m", LO);
    333 			exit(1);
    334 		}
    335 		alarm(0);
    336 		signal(SIGALRM, SIG_DFL);
    337 		signal(SIGINT, SIG_IGN);
    338 		if (NX && *NX)
    339 			tname = NX;
    340 	}
    341 }
    342 
    343 static int
    344 getname()
    345 {
    346 	register int c;
    347 	register char *np;
    348 	char cs;
    349 
    350 	/*
    351 	 * Interrupt may happen if we use CBREAK mode
    352 	 */
    353 	if (setjmp(intrupt)) {
    354 		signal(SIGINT, SIG_IGN);
    355 		return (0);
    356 	}
    357 	signal(SIGINT, interrupt);
    358 	setflags(1);
    359 	prompt();
    360 	if (PF > 0) {
    361 		oflush();
    362 		sleep(PF);
    363 		PF = 0;
    364 	}
    365 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    366 		syslog(LOG_ERR, "%s: %m", ttyn);
    367 		exit(1);
    368 	}
    369 	crmod = digit = lower = upper = 0;
    370 	np = name;
    371 	for (;;) {
    372 		oflush();
    373 		if (read(STDIN_FILENO, &cs, 1) <= 0)
    374 			exit(0);
    375 		if ((c = cs&0177) == 0)
    376 			return (0);
    377 		if (c == EOT)
    378 			exit(1);
    379 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
    380 			putf("\r\n");
    381 			break;
    382 		}
    383 		if (islower(c))
    384 			lower = 1;
    385 		else if (isupper(c))
    386 			upper = 1;
    387 		else if (c == ERASE || c == '#' || c == '\b') {
    388 			if (np > name) {
    389 				np--;
    390 				if (cfgetospeed(&tmode) >= 1200)
    391 					puts("\b \b");
    392 				else
    393 					putchr(cs);
    394 			}
    395 			continue;
    396 		} else if (c == KILL || c == '@') {
    397 			putchr(cs);
    398 			putchr('\r');
    399 			if (cfgetospeed(&tmode) < 1200)
    400 				putchr('\n');
    401 			/* this is the way they do it down under ... */
    402 			else if (np > name)
    403 				puts("                                     \r");
    404 			prompt();
    405 			np = name;
    406 			continue;
    407 		} else if (isdigit(c))
    408 			digit++;
    409 		if (IG && (c <= ' ' || c > 0176))
    410 			continue;
    411 		*np++ = c;
    412 		putchr(cs);
    413 	}
    414 	signal(SIGINT, SIG_IGN);
    415 	*np = 0;
    416 	if (c == '\r')
    417 		crmod = 1;
    418 	if (upper && !lower && !LC || UC)
    419 		for (np = name; *np; np++)
    420 			if (isupper(*np))
    421 				*np = tolower(*np);
    422 	return (1);
    423 }
    424 
    425 static void
    426 putpad(s)
    427 	register char *s;
    428 {
    429 	register pad = 0;
    430 	speed_t ospeed = cfgetospeed(&tmode);
    431 
    432 	if (isdigit(*s)) {
    433 		while (isdigit(*s)) {
    434 			pad *= 10;
    435 			pad += *s++ - '0';
    436 		}
    437 		pad *= 10;
    438 		if (*s == '.' && isdigit(s[1])) {
    439 			pad += s[1] - '0';
    440 			s += 2;
    441 		}
    442 	}
    443 
    444 	puts(s);
    445 	/*
    446 	 * If no delay needed, or output speed is
    447 	 * not comprehensible, then don't try to delay.
    448 	 */
    449 	if (pad == 0 || ospeed <= 0)
    450 		return;
    451 
    452 	/*
    453 	 * Round up by a half a character frame, and then do the delay.
    454 	 * Too bad there are no user program accessible programmed delays.
    455 	 * Transmitting pad characters slows many terminals down and also
    456 	 * loads the system.
    457 	 */
    458 	pad = (pad * ospeed + 50000) / 100000;
    459 	while (pad--)
    460 		putchr(*PC);
    461 }
    462 
    463 static void
    464 puts(s)
    465 	register char *s;
    466 {
    467 	while (*s)
    468 		putchr(*s++);
    469 }
    470 
    471 char	outbuf[OBUFSIZ];
    472 int	obufcnt = 0;
    473 
    474 static void
    475 putchr(cc)
    476 	int cc;
    477 {
    478 	char c;
    479 
    480 	c = cc;
    481 	if (!NP) {
    482 		c |= partab[c&0177] & 0200;
    483 		if (OP)
    484 			c ^= 0200;
    485 	}
    486 	if (!UB) {
    487 		outbuf[obufcnt++] = c;
    488 		if (obufcnt >= OBUFSIZ)
    489 			oflush();
    490 	} else
    491 		write(STDOUT_FILENO, &c, 1);
    492 }
    493 
    494 static void
    495 oflush()
    496 {
    497 	if (obufcnt)
    498 		write(STDOUT_FILENO, outbuf, obufcnt);
    499 	obufcnt = 0;
    500 }
    501 
    502 static void
    503 prompt()
    504 {
    505 
    506 	putf(LM);
    507 	if (CO)
    508 		putchr('\n');
    509 }
    510 
    511 static void
    512 putf(cp)
    513 	register char *cp;
    514 {
    515 	extern char editedhost[];
    516 	time_t t;
    517 	char *slash, db[100];
    518 
    519 	while (*cp) {
    520 		if (*cp != '%') {
    521 			putchr(*cp++);
    522 			continue;
    523 		}
    524 		switch (*++cp) {
    525 
    526 		case 't':
    527 			slash = strrchr(ttyn, '/');
    528 			if (slash == (char *) 0)
    529 				puts(ttyn);
    530 			else
    531 				puts(&slash[1]);
    532 			break;
    533 
    534 		case 'h':
    535 			puts(editedhost);
    536 			break;
    537 
    538 		case 'd': {
    539 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
    540 
    541 			fmt[4] = 'M';		/* I *hate* SCCS... */
    542 			(void)time(&t);
    543 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
    544 			puts(db);
    545 			break;
    546 
    547 		case 's':
    548 			puts(kerninfo.sysname);
    549 			break;
    550 
    551 		case 'm':
    552 			puts(kerninfo.machine);
    553 			break;
    554 
    555 		case 'r':
    556 			puts(kerninfo.release);
    557 			break;
    558 
    559 		case 'v':
    560 			puts(kerninfo.version);
    561 			break;
    562 		}
    563 
    564 		case '%':
    565 			putchr('%');
    566 			break;
    567 		}
    568 		cp++;
    569 	}
    570 }
    571