Home | History | Annotate | Line # | Download | only in getty
main.c revision 1.18
      1 /*	$NetBSD: main.c,v 1.18 1996/07/31 20:40:34 thorpej 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.18 1996/07/31 20:40:34 thorpej 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 	    strcpy(ttyn, ttyname(0));
    203 	else {
    204 	    int i;
    205 
    206 	    strcpy(ttyn, dev);
    207 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
    208 	    if (strcmp(argv[0], "+") != 0) {
    209 		chown(ttyn, 0, 0);
    210 		chmod(ttyn, 0600);
    211 		revoke(ttyn);
    212 		/*
    213 		 * Delay the open so DTR stays down long enough to be detected.
    214 		 */
    215 		sleep(2);
    216 		while ((i = open(ttyn, O_RDWR)) == -1) {
    217 			if ((repcnt % 10 == 0) &&
    218 			    (errno != ENXIO || !failopenlogged)) {
    219 				syslog(LOG_ERR, "%s: %m", ttyn);
    220 				closelog();
    221 				failopenlogged = 1;
    222 			}
    223 			repcnt++;
    224 			sleep(60);
    225 		}
    226 		login_tty(i);
    227 	    }
    228 	}
    229 
    230 	/* Start with default tty settings */
    231 	if (tcgetattr(0, &tmode) < 0) {
    232 		syslog(LOG_ERR, "%s: %m", ttyn);
    233 		exit(1);
    234 	}
    235 	omode = tmode;
    236 
    237 	gettable("default", defent);
    238 	gendefaults();
    239 	tname = "default";
    240 	if (argc > 1)
    241 		tname = argv[1];
    242 	for (;;) {
    243 		int off;
    244 
    245 		gettable(tname, tabent);
    246 		if (OPset || EPset || APset)
    247 			APset++, OPset++, EPset++;
    248 		setdefaults();
    249 		off = 0;
    250 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
    251 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
    252 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
    253 
    254 		if (IS)
    255 			cfsetispeed(&tmode, IS);
    256 		else if (SP)
    257 			cfsetispeed(&tmode, SP);
    258 		if (OS)
    259 			cfsetospeed(&tmode, OS);
    260 		else if (SP)
    261 			cfsetospeed(&tmode, SP);
    262 		setflags(0);
    263 		setchars();
    264 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    265 			syslog(LOG_ERR, "%s: %m", ttyn);
    266 			exit(1);
    267 		}
    268 		if (AB) {
    269 			extern char *autobaud();
    270 
    271 			tname = autobaud();
    272 			continue;
    273 		}
    274 		if (PS) {
    275 			tname = portselector();
    276 			continue;
    277 		}
    278 		if (CL && *CL)
    279 			putpad(CL);
    280 		edithost(HE);
    281 		if (IM && *IM)
    282 			putf(IM);
    283 		if (setjmp(timeout)) {
    284 			tmode.c_ispeed = tmode.c_ospeed = 0;
    285 			(void)tcsetattr(0, TCSANOW, &tmode);
    286 			exit(1);
    287 		}
    288 		if (TO) {
    289 			signal(SIGALRM, dingdong);
    290 			alarm(TO);
    291 		}
    292 		if (getname()) {
    293 			register int i;
    294 
    295 			oflush();
    296 			alarm(0);
    297 			signal(SIGALRM, SIG_DFL);
    298 			if (name[0] == '-') {
    299 				puts("user names may not start with '-'.");
    300 				continue;
    301 			}
    302 			if (!(upper || lower || digit))
    303 				continue;
    304 			setflags(2);
    305 			if (crmod) {
    306 				tmode.c_iflag |= ICRNL;
    307 				tmode.c_oflag |= ONLCR;
    308 			}
    309 #if XXX
    310 			if (upper || UC)
    311 				tmode.sg_flags |= LCASE;
    312 			if (lower || LC)
    313 				tmode.sg_flags &= ~LCASE;
    314 #endif
    315 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    316 				syslog(LOG_ERR, "%s: %m", ttyn);
    317 				exit(1);
    318 			}
    319 			signal(SIGINT, SIG_DFL);
    320 			for (i = 0; environ[i] != (char *)0; i++)
    321 				env[i] = environ[i];
    322 			makeenv(&env[i]);
    323 
    324 			limit.rlim_max = RLIM_INFINITY;
    325 			limit.rlim_cur = RLIM_INFINITY;
    326 			(void)setrlimit(RLIMIT_CPU, &limit);
    327 			execle(LO, "login", "-p", "--", name, (char *)0, env);
    328 			syslog(LOG_ERR, "%s: %m", LO);
    329 			exit(1);
    330 		}
    331 		alarm(0);
    332 		signal(SIGALRM, SIG_DFL);
    333 		signal(SIGINT, SIG_IGN);
    334 		if (NX && *NX)
    335 			tname = NX;
    336 	}
    337 }
    338 
    339 static int
    340 getname()
    341 {
    342 	register int c;
    343 	register char *np;
    344 	char cs;
    345 
    346 	/*
    347 	 * Interrupt may happen if we use CBREAK mode
    348 	 */
    349 	if (setjmp(intrupt)) {
    350 		signal(SIGINT, SIG_IGN);
    351 		return (0);
    352 	}
    353 	signal(SIGINT, interrupt);
    354 	setflags(1);
    355 	prompt();
    356 	if (PF > 0) {
    357 		oflush();
    358 		sleep(PF);
    359 		PF = 0;
    360 	}
    361 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    362 		syslog(LOG_ERR, "%s: %m", ttyn);
    363 		exit(1);
    364 	}
    365 	crmod = digit = lower = upper = 0;
    366 	np = name;
    367 	for (;;) {
    368 		oflush();
    369 		if (read(STDIN_FILENO, &cs, 1) <= 0)
    370 			exit(0);
    371 		if ((c = cs&0177) == 0)
    372 			return (0);
    373 		if (c == EOT)
    374 			exit(1);
    375 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
    376 			putf("\r\n");
    377 			break;
    378 		}
    379 		if (islower(c))
    380 			lower = 1;
    381 		else if (isupper(c))
    382 			upper = 1;
    383 		else if (c == ERASE || c == '#' || c == '\b') {
    384 			if (np > name) {
    385 				np--;
    386 				if (cfgetospeed(&tmode) >= 1200)
    387 					puts("\b \b");
    388 				else
    389 					putchr(cs);
    390 			}
    391 			continue;
    392 		} else if (c == KILL || c == '@') {
    393 			putchr(cs);
    394 			putchr('\r');
    395 			if (cfgetospeed(&tmode) < 1200)
    396 				putchr('\n');
    397 			/* this is the way they do it down under ... */
    398 			else if (np > name)
    399 				puts("                                     \r");
    400 			prompt();
    401 			np = name;
    402 			continue;
    403 		} else if (isdigit(c))
    404 			digit++;
    405 		if (IG && (c <= ' ' || c > 0176))
    406 			continue;
    407 		*np++ = c;
    408 		putchr(cs);
    409 	}
    410 	signal(SIGINT, SIG_IGN);
    411 	*np = 0;
    412 	if (c == '\r')
    413 		crmod = 1;
    414 	if (upper && !lower && !LC || UC)
    415 		for (np = name; *np; np++)
    416 			if (isupper(*np))
    417 				*np = tolower(*np);
    418 	return (1);
    419 }
    420 
    421 static void
    422 putpad(s)
    423 	register char *s;
    424 {
    425 	register pad = 0;
    426 	speed_t ospeed = cfgetospeed(&tmode);
    427 
    428 	if (isdigit(*s)) {
    429 		while (isdigit(*s)) {
    430 			pad *= 10;
    431 			pad += *s++ - '0';
    432 		}
    433 		pad *= 10;
    434 		if (*s == '.' && isdigit(s[1])) {
    435 			pad += s[1] - '0';
    436 			s += 2;
    437 		}
    438 	}
    439 
    440 	puts(s);
    441 	/*
    442 	 * If no delay needed, or output speed is
    443 	 * not comprehensible, then don't try to delay.
    444 	 */
    445 	if (pad == 0 || ospeed <= 0)
    446 		return;
    447 
    448 	/*
    449 	 * Round up by a half a character frame, and then do the delay.
    450 	 * Too bad there are no user program accessible programmed delays.
    451 	 * Transmitting pad characters slows many terminals down and also
    452 	 * loads the system.
    453 	 */
    454 	pad = (pad * ospeed + 50000) / 100000;
    455 	while (pad--)
    456 		putchr(*PC);
    457 }
    458 
    459 static void
    460 puts(s)
    461 	register char *s;
    462 {
    463 	while (*s)
    464 		putchr(*s++);
    465 }
    466 
    467 char	outbuf[OBUFSIZ];
    468 int	obufcnt = 0;
    469 
    470 static void
    471 putchr(cc)
    472 	int cc;
    473 {
    474 	char c;
    475 
    476 	c = cc;
    477 	if (!NP) {
    478 		c |= partab[c&0177] & 0200;
    479 		if (OP)
    480 			c ^= 0200;
    481 	}
    482 	if (!UB) {
    483 		outbuf[obufcnt++] = c;
    484 		if (obufcnt >= OBUFSIZ)
    485 			oflush();
    486 	} else
    487 		write(STDOUT_FILENO, &c, 1);
    488 }
    489 
    490 static void
    491 oflush()
    492 {
    493 	if (obufcnt)
    494 		write(STDOUT_FILENO, outbuf, obufcnt);
    495 	obufcnt = 0;
    496 }
    497 
    498 static void
    499 prompt()
    500 {
    501 
    502 	putf(LM);
    503 	if (CO)
    504 		putchr('\n');
    505 }
    506 
    507 static void
    508 putf(cp)
    509 	register char *cp;
    510 {
    511 	extern char editedhost[];
    512 	time_t t;
    513 	char *slash, db[100];
    514 
    515 	while (*cp) {
    516 		if (*cp != '%') {
    517 			putchr(*cp++);
    518 			continue;
    519 		}
    520 		switch (*++cp) {
    521 
    522 		case 't':
    523 			slash = strrchr(ttyn, '/');
    524 			if (slash == (char *) 0)
    525 				puts(ttyn);
    526 			else
    527 				puts(&slash[1]);
    528 			break;
    529 
    530 		case 'h':
    531 			puts(editedhost);
    532 			break;
    533 
    534 		case 'd': {
    535 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
    536 
    537 			fmt[4] = 'M';		/* I *hate* SCCS... */
    538 			(void)time(&t);
    539 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
    540 			puts(db);
    541 			break;
    542 
    543 		case 's':
    544 			puts(kerninfo.sysname);
    545 			break;
    546 
    547 		case 'm':
    548 			puts(kerninfo.machine);
    549 			break;
    550 
    551 		case 'r':
    552 			puts(kerninfo.release);
    553 			break;
    554 
    555 		case 'v':
    556 			puts(kerninfo.version);
    557 			break;
    558 		}
    559 
    560 		case '%':
    561 			putchr('%');
    562 			break;
    563 		}
    564 		cp++;
    565 	}
    566 }
    567