xref: /csrg-svn/old/init/init.c (revision 37284)
121135Sdist /*
228801Skarels  * Copyright (c) 1980,1986 Regents of the University of California.
321135Sdist  * All rights reserved.  The Berkeley software License Agreement
421135Sdist  * specifies the terms and conditions for redistribution.
521135Sdist  */
621135Sdist 
712682Ssam #ifndef lint
8*37284Sbostic static char sccsid[] = "@(#)init.c	5.14 (Berkeley) 04/02/89";
921135Sdist #endif not lint
1012682Ssam 
111029Sbill #include <sys/types.h>
12*37284Sbostic #include <sys/file.h>
13*37284Sbostic #include <sys/signal.h>
14*37284Sbostic #include <sys/reboot.h>
15*37284Sbostic #include <sys/syslog.h>
16*37284Sbostic #include <sys/stat.h>
171029Sbill #include <setjmp.h>
1835606Sbostic #include <utmp.h>
192821Swnj #include <errno.h>
2016452Sroot #include <ttyent.h>
21*37284Sbostic #include "pathnames.h"
221029Sbill 
2324494Skarels #define	CMDSIZ	200	/* max string length for getty or window command*/
2423147Sbloom #define	ALL	p = itab; p ; p = p->next
251029Sbill #define	EVER	;;
261029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
271029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
281029Sbill 
29*37284Sbostic char	shell[]	= _PATH_BSHELL;
301029Sbill char	minus[]	= "-";
31*37284Sbostic char	runc[]	= _PATH_RC;
32*37284Sbostic char	utmpf[]	= _PATH_UTMP;
33*37284Sbostic char	ctty[]	= _PATH_CONSOLE;
341029Sbill 
351029Sbill struct	tab
361029Sbill {
3735670Sbostic 	char	line[UT_LINESIZE];
3818542Sralph 	char	comn[CMDSIZ];
391029Sbill 	char	xflag;
401029Sbill 	int	pid;
4118542Sralph 	int	wpid;		/* window system pid for SIGHUP	*/
4218542Sralph 	char	wcmd[CMDSIZ];	/* command to start window system process */
435971Sroot 	time_t	gettytime;
445971Sroot 	int	gettycnt;
4522181Skarels 	time_t	windtime;
4622181Skarels 	int	windcnt;
4723147Sbloom 	struct	tab *next;
4823147Sbloom } *itab;
491029Sbill 
501029Sbill int	fi;
511029Sbill int	mergflag;
521029Sbill char	tty[20];
531429Sbill jmp_buf	sjbuf, shutpass;
541029Sbill 
551029Sbill int	reset();
562821Swnj int	idle();
571029Sbill char	*strcpy(), *strcat();
581029Sbill long	lseek();
591029Sbill 
6018542Sralph struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
6113021Ssam 
6223147Sbloom 
6329836Ssam #if defined(vax) || defined(tahoe)
641029Sbill main()
651029Sbill {
6629836Ssam #if defined(tahoe)
6729836Ssam 	register int r12;		/* make sure r11 gets bootflags */
6829836Ssam #endif
691403Sbill 	register int r11;		/* passed thru from boot */
7013021Ssam #else
719869Spugs main(argc, argv)
729869Spugs 	char **argv;
739869Spugs {
7413021Ssam #endif
751403Sbill 	int howto, oldhowto;
761403Sbill 
7729836Ssam #if defined(vax) || defined(tahoe)
781403Sbill 	howto = r11;
7913021Ssam #else
809869Spugs 	if (argc > 1 && argv[1][0] == '-') {
819869Spugs 		char *cp;
829869Spugs 
839869Spugs 		howto = 0;
849869Spugs 		cp = &argv[1][1];
859869Spugs 		while (*cp) switch (*cp++) {
869869Spugs 		case 'a':
879869Spugs 			howto |= RB_ASKNAME;
889869Spugs 			break;
899869Spugs 		case 's':
909869Spugs 			howto |= RB_SINGLE;
919869Spugs 			break;
929869Spugs 		}
939869Spugs 	} else {
949869Spugs 		howto = RB_SINGLE;
959869Spugs 	}
9613021Ssam #endif
9724854Seric 	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
9813021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
992821Swnj 	signal(SIGTSTP, idle);
1001029Sbill 	signal(SIGSTOP, SIG_IGN);
1011029Sbill 	signal(SIGTTIN, SIG_IGN);
1021029Sbill 	signal(SIGTTOU, SIG_IGN);
10313021Ssam 	(void) setjmp(sjbuf);
10413021Ssam 	for (EVER) {
1051403Sbill 		oldhowto = howto;
1061403Sbill 		howto = RB_SINGLE;
1071429Sbill 		if (setjmp(shutpass) == 0)
1081429Sbill 			shutdown();
1091403Sbill 		if (oldhowto & RB_SINGLE)
1101403Sbill 			single();
1111403Sbill 		if (runcom(oldhowto) == 0)
1121403Sbill 			continue;
1131029Sbill 		merge();
1141029Sbill 		multiple();
1151029Sbill 	}
1161029Sbill }
1171029Sbill 
1181429Sbill int	shutreset();
1191429Sbill 
1201029Sbill shutdown()
1211029Sbill {
1221029Sbill 	register i;
12323147Sbloom 	register struct tab *p, *p1;
1241029Sbill 
12523147Sbloom 	close(creat(utmpf, 0644));
1261029Sbill 	signal(SIGHUP, SIG_IGN);
12723147Sbloom 	for (p = itab; p ; ) {
1281029Sbill 		term(p);
12923147Sbloom 		p1 = p->next;
13023147Sbloom 		free(p);
13123147Sbloom 		p = p1;
1321029Sbill 	}
13323147Sbloom 	itab = (struct tab *)0;
1341429Sbill 	signal(SIGALRM, shutreset);
13528801Skarels 	(void) kill(-1, SIGTERM);	/* one chance to catch it */
13628801Skarels 	sleep(5);
1371429Sbill 	alarm(30);
13813021Ssam 	for (i = 0; i < 5; i++)
1391029Sbill 		kill(-1, SIGKILL);
14013021Ssam 	while (wait((int *)0) != -1)
1411029Sbill 		;
1421029Sbill 	alarm(0);
1431429Sbill 	shutend();
1441429Sbill }
1451429Sbill 
14630516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n";
1471429Sbill 
1481429Sbill shutreset()
1491429Sbill {
1501429Sbill 	int status;
1511429Sbill 
1521429Sbill 	if (fork() == 0) {
1531429Sbill 		int ct = open(ctty, 1);
1541429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1551429Sbill 		sleep(5);
1561429Sbill 		exit(1);
1571429Sbill 	}
1581429Sbill 	sleep(5);
1591429Sbill 	shutend();
1601429Sbill 	longjmp(shutpass, 1);
1611429Sbill }
1621429Sbill 
1631429Sbill shutend()
1641429Sbill {
1652821Swnj 	register i, f;
1661429Sbill 
1672821Swnj 	acct(0);
1681029Sbill 	signal(SIGALRM, SIG_DFL);
16913021Ssam 	for (i = 0; i < 10; i++)
1701029Sbill 		close(i);
17135606Sbostic 	logwtmp("~", "shutdown", "");
1721029Sbill }
1731029Sbill 
1741029Sbill single()
1751029Sbill {
1761029Sbill 	register pid;
1772821Swnj 	register xpid;
17835606Sbostic 	extern int errno;
1791029Sbill 
18013021Ssam 	do {
18113021Ssam 		pid = fork();
18213021Ssam 		if (pid == 0) {
18313021Ssam 			signal(SIGTERM, SIG_DFL);
18413021Ssam 			signal(SIGHUP, SIG_DFL);
18513021Ssam 			signal(SIGALRM, SIG_DFL);
18616452Sroot 			signal(SIGTSTP, SIG_IGN);
18713021Ssam 			(void) open(ctty, O_RDWR);
18813021Ssam 			dup2(0, 1);
18913021Ssam 			dup2(0, 2);
19013021Ssam 			execl(shell, minus, (char *)0);
19130516Sbostic 			perror(shell);
19213021Ssam 			exit(0);
19313021Ssam 		}
19413021Ssam 		while ((xpid = wait((int *)0)) != pid)
19513021Ssam 			if (xpid == -1 && errno == ECHILD)
19613021Ssam 				break;
19713021Ssam 	} while (xpid == -1);
1981029Sbill }
1991029Sbill 
2001403Sbill runcom(oldhowto)
2011403Sbill 	int oldhowto;
2021029Sbill {
2031029Sbill 	register pid, f;
2041403Sbill 	int status;
2051029Sbill 
2061029Sbill 	pid = fork();
20713021Ssam 	if (pid == 0) {
20813021Ssam 		(void) open("/", O_RDONLY);
20913021Ssam 		dup2(0, 1);
21013021Ssam 		dup2(0, 2);
2111403Sbill 		if (oldhowto & RB_SINGLE)
2121403Sbill 			execl(shell, shell, runc, (char *)0);
2131403Sbill 		else
2141403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2151403Sbill 		exit(1);
2161029Sbill 	}
21713021Ssam 	while (wait(&status) != pid)
2181029Sbill 		;
21913021Ssam 	if (status)
22013021Ssam 		return (0);
22135606Sbostic 	logwtmp("~", "reboot", "");
22213021Ssam 	return (1);
2231029Sbill }
2241029Sbill 
22533302Sbostic int merge();
22618542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
22713021Ssam /*
22813021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
22913021Ssam  * which indicate ttys has changed, and SIGTERM's which
23013021Ssam  * are used to shutdown the system.
23113021Ssam  */
2321029Sbill multiple()
2331029Sbill {
2341029Sbill 	register struct tab *p;
2351029Sbill 	register pid;
23623147Sbloom 	int omask;
2371029Sbill 
23813021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
23913021Ssam 	for (EVER) {
2401029Sbill 		pid = wait((int *)0);
24113021Ssam 		if (pid == -1)
2421029Sbill 			return;
24330516Sbostic 		omask = sigblock(sigmask(SIGHUP));
24418542Sralph 		for (ALL) {
24518542Sralph 			/* must restart window system BEFORE emulator */
24618542Sralph 			if (p->wpid == pid || p->wpid == -1)
24718542Sralph 				wstart(p);
24813021Ssam 			if (p->pid == pid || p->pid == -1) {
24918542Sralph 				/* disown the window system */
25018542Sralph 				if (p->wpid)
25118542Sralph 					kill(p->wpid, SIGHUP);
25235445Sbostic 				cleanutmp(p);
2531029Sbill 				dfork(p);
2541029Sbill 			}
25518542Sralph 		}
25623147Sbloom 		sigsetmask(omask);
2571029Sbill 	}
2581029Sbill }
2591029Sbill 
26013021Ssam /*
26113021Ssam  * Merge current contents of ttys file
26213021Ssam  * into in-core table of configured tty lines.
26313021Ssam  * Entered as signal handler for SIGHUP.
26413021Ssam  */
26513021Ssam #define	FOUND	1
26613021Ssam #define	CHANGE	2
26718542Sralph #define WCHANGE 4
26813021Ssam 
26913021Ssam merge()
27013021Ssam {
27113021Ssam 	register struct tab *p;
27216452Sroot 	register struct ttyent *t;
27323147Sbloom 	register struct tab *p1;
27413021Ssam 
27513021Ssam 	for (ALL)
27613021Ssam 		p->xflag = 0;
27716452Sroot 	setttyent();
27816452Sroot 	while (t = getttyent()) {
27916452Sroot 		if ((t->ty_status & TTY_ON) == 0)
28016452Sroot 			continue;
28113021Ssam 		for (ALL) {
28216452Sroot 			if (SCMPN(p->line, t->ty_name))
28313021Ssam 				continue;
28413021Ssam 			p->xflag |= FOUND;
28516452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
28613021Ssam 				p->xflag |= CHANGE;
28716452Sroot 				SCPYN(p->comn, t->ty_getty);
28813021Ssam 			}
28930516Sbostic 			if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
29018542Sralph 				p->xflag |= WCHANGE|CHANGE;
29118542Sralph 				SCPYN(p->wcmd, t->ty_window);
29218542Sralph 			}
29313021Ssam 			goto contin1;
29413021Ssam 		}
29518542Sralph 
29623147Sbloom 		/*
29723147Sbloom 		 * Make space for a new one
29823147Sbloom 		 */
29923147Sbloom 		p1 = (struct tab *)calloc(1, sizeof(*p1));
30023147Sbloom 		if (!p1) {
30123147Sbloom 			syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
30213021Ssam 			goto contin1;
30313021Ssam 		}
30423147Sbloom 		/*
30523147Sbloom 		 * Put new terminal at the end of the linked list.
30623147Sbloom 		 */
30723147Sbloom 		if (itab) {
30823147Sbloom 			for (p = itab; p->next ; p = p->next)
30923147Sbloom 				;
31023147Sbloom 			p->next = p1;
31123147Sbloom 		} else
31223147Sbloom 			itab = p1;
31323147Sbloom 
31423147Sbloom 		p = p1;
31523147Sbloom 		SCPYN(p->line, t->ty_name);
31623147Sbloom 		p->xflag |= FOUND|CHANGE;
31723147Sbloom 		SCPYN(p->comn, t->ty_getty);
31830516Sbostic 		if (t->ty_window && strcmp(t->ty_window, "") != 0) {
31923147Sbloom 			p->xflag |= WCHANGE;
32023147Sbloom 			SCPYN(p->wcmd, t->ty_window);
32123147Sbloom 		}
32213021Ssam 	contin1:
32313021Ssam 		;
32413021Ssam 	}
32516452Sroot 	endttyent();
32623147Sbloom 	p1 = (struct tab *)0;
32713021Ssam 	for (ALL) {
32813021Ssam 		if ((p->xflag&FOUND) == 0) {
32913021Ssam 			term(p);
33018542Sralph 			wterm(p);
33123147Sbloom 			if (p1)
33223147Sbloom 				p1->next = p->next;
33323147Sbloom 			else
33423147Sbloom 				itab = p->next;
33523147Sbloom 			free(p);
33623147Sbloom 			p = p1 ? p1 : itab;
33723147Sbloom 		} else {
33823147Sbloom 			/* window system should be started first */
33923147Sbloom 			if (p->xflag&WCHANGE) {
34023147Sbloom 				wterm(p);
34123147Sbloom 				wstart(p);
34223147Sbloom 			}
34323147Sbloom 			if (p->xflag&CHANGE) {
34423147Sbloom 				term(p);
34523147Sbloom 				dfork(p);
34623147Sbloom 			}
34713021Ssam 		}
34823147Sbloom 		p1 = p;
34913021Ssam 	}
35013021Ssam }
35113021Ssam 
3521029Sbill term(p)
35313021Ssam 	register struct tab *p;
3541029Sbill {
3551029Sbill 
35613021Ssam 	if (p->pid != 0) {
35735445Sbostic 		cleanutmp(p);
3581029Sbill 		kill(p->pid, SIGKILL);
3591029Sbill 	}
3601029Sbill 	p->pid = 0;
36118542Sralph 	/* send SIGHUP to get rid of connections */
36218542Sralph 	if (p->wpid > 0)
36318542Sralph 		kill(p->wpid, SIGHUP);
3641029Sbill }
3651029Sbill 
3661029Sbill dfork(p)
36713021Ssam 	struct tab *p;
3681029Sbill {
3691029Sbill 	register pid;
3705971Sroot 	time_t t;
3715971Sroot 	int dowait = 0;
3721029Sbill 
3735971Sroot 	time(&t);
3745971Sroot 	p->gettycnt++;
3755971Sroot 	if ((t - p->gettytime) >= 60) {
3765971Sroot 		p->gettytime = t;
3775971Sroot 		p->gettycnt = 1;
37818542Sralph 	} else if (p->gettycnt >= 5) {
37918542Sralph 		dowait = 1;
38018542Sralph 		p->gettytime = t;
38118542Sralph 		p->gettycnt = 1;
3825971Sroot 	}
3831029Sbill 	pid = fork();
38413021Ssam 	if (pid == 0) {
3856816Ssam 		signal(SIGTERM, SIG_DFL);
3866816Ssam 		signal(SIGHUP, SIG_IGN);
38722181Skarels 		sigsetmask(0);	/* since can be called from masked code */
3885971Sroot 		if (dowait) {
38918542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
39018542Sralph 			closelog();
3915971Sroot 			sleep(30);
3925971Sroot 		}
39318542Sralph 		execit(p->comn, p->line);
3941029Sbill 		exit(0);
3951029Sbill 	}
3961029Sbill 	p->pid = pid;
3971029Sbill }
3981029Sbill 
39935445Sbostic cleanutmp(p)
40013021Ssam 	register struct tab *p;
4011029Sbill {
40235445Sbostic 	if (logout(p->line)) {
40335445Sbostic 		logwtmp(p->line);
40417582Ssam 		/*
40517582Ssam 		 * After a proper login force reset
40617582Ssam 		 * of error detection code in dfork.
40717582Ssam 		 */
40817582Ssam 		p->gettytime = 0;
40922181Skarels 		p->windtime = 0;
4101029Sbill 	}
4111029Sbill }
4121029Sbill 
4131029Sbill reset()
4141029Sbill {
41513021Ssam 
4161029Sbill 	longjmp(sjbuf, 1);
4171029Sbill }
4182821Swnj 
41913021Ssam jmp_buf	idlebuf;
42013021Ssam 
42113021Ssam idlehup()
42213021Ssam {
42313021Ssam 
42413021Ssam 	longjmp(idlebuf, 1);
42513021Ssam }
42613021Ssam 
4272821Swnj idle()
4282821Swnj {
4292821Swnj 	register struct tab *p;
4302821Swnj 	register pid;
4312821Swnj 
43213021Ssam 	signal(SIGHUP, idlehup);
43318542Sralph 	for (EVER) {
43413021Ssam 		if (setjmp(idlebuf))
43513021Ssam 			return;
4362821Swnj 		pid = wait((int *) 0);
43713021Ssam 		if (pid == -1) {
43813021Ssam 			sigpause(0);
43913021Ssam 			continue;
4402821Swnj 		}
44118542Sralph 		for (ALL) {
44218542Sralph 			/* if window system dies, mark it for restart */
44318542Sralph 			if (p->wpid == pid)
44418542Sralph 				p->wpid = -1;
44513021Ssam 			if (p->pid == pid) {
44635445Sbostic 				cleanutmp(p);
44713021Ssam 				p->pid = -1;
44813021Ssam 			}
44918542Sralph 		}
4502821Swnj 	}
4512821Swnj }
45218542Sralph 
45318542Sralph wterm(p)
45418542Sralph 	register struct tab *p;
45518542Sralph {
45618542Sralph 	if (p->wpid != 0) {
45718542Sralph 		kill(p->wpid, SIGKILL);
45818542Sralph 	}
45918542Sralph 	p->wpid = 0;
46018542Sralph }
46118542Sralph 
46218542Sralph wstart(p)
46318542Sralph 	register struct tab *p;
46418542Sralph {
46522181Skarels 	register pid;
46622181Skarels 	time_t t;
46722181Skarels 	int dowait = 0;
46818542Sralph 
46922181Skarels 	time(&t);
47022181Skarels 	p->windcnt++;
47122181Skarels 	if ((t - p->windtime) >= 60) {
47222181Skarels 		p->windtime = t;
47322181Skarels 		p->windcnt = 1;
47422181Skarels 	} else if (p->windcnt >= 5) {
47522181Skarels 		dowait = 1;
47622181Skarels 		p->windtime = t;
47722181Skarels 		p->windcnt = 1;
47822181Skarels 	}
47922181Skarels 
48022181Skarels 	pid = fork();
48122181Skarels 
48222181Skarels 	if (pid == 0) {
48318542Sralph 		signal(SIGTERM, SIG_DFL);
48422181Skarels 		signal(SIGHUP,  SIG_IGN);
48522181Skarels 		sigsetmask(0);	/* since can be called from masked code */
48622181Skarels 		if (dowait) {
48722181Skarels 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
48822181Skarels 			closelog();
48922181Skarels 			sleep(30);
49022181Skarels 		}
49118542Sralph 		execit(p->wcmd, p->line);
49218542Sralph 		exit(0);
49318542Sralph 	}
49422181Skarels 	p->wpid = pid;
49518542Sralph }
49618542Sralph 
49722181Skarels #define NARGS	20	/* must be at least 4 */
49818542Sralph #define ARGLEN	512	/* total size for all the argument strings */
49918542Sralph 
50018542Sralph execit(s, arg)
50118542Sralph 	char *s;
50218542Sralph 	char *arg;	/* last argument on line */
50318542Sralph {
50418542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
50518542Sralph 	register char *sp = s;
50618542Sralph 	register char *ap = args;
50718542Sralph 	register char c;
50818542Sralph 	register int i;
50918542Sralph 
51018542Sralph 	/*
51118542Sralph 	 * First we have to set up the argument vector.
51218542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
51318542Sralph 	 */
51418542Sralph 	for (i = 1; i < NARGS - 2; i++) {
51518542Sralph 		argv[i] = ap;
51618542Sralph 		for (EVER) {
51718542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
51818542Sralph 				*ap = '\0';
51918542Sralph 				goto done;
52018542Sralph 			}
52118542Sralph 			if (c == ' ') {
52218542Sralph 				*ap++ = '\0';
52318542Sralph 				while (*sp == ' ')
52418542Sralph 					sp++;
52518542Sralph 				if (*sp == '\0')
52618542Sralph 					goto done;
52718542Sralph 				break;
52818542Sralph 			}
52918542Sralph 			*ap++ = c;
53018542Sralph 		}
53118542Sralph 	}
53218542Sralph done:
53318542Sralph 	argv[0] = argv[1];
53418542Sralph 	argv[1] = "-";
53518542Sralph 	argv[i+1] = arg;
53618542Sralph 	argv[i+2] = 0;
53718542Sralph 	envp[0] = 0;
53818542Sralph 	execve(argv[0], &argv[1], envp);
53918542Sralph 	/* report failure of exec */
54018542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
54118542Sralph 	closelog();
54218542Sralph 	sleep(10);	/* prevent failures from eating machine */
54318542Sralph }
544