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