xref: /csrg-svn/old/init/init.c (revision 16452)
112682Ssam #ifndef lint
2*16452Sroot static	char *sccsid = "@(#)init.c	4.13 (Berkeley) 05/07/84";
312682Ssam #endif
412682Ssam 
51029Sbill #include <signal.h>
61029Sbill #include <sys/types.h>
71029Sbill #include <utmp.h>
81029Sbill #include <setjmp.h>
91403Sbill #include <sys/reboot.h>
102821Swnj #include <errno.h>
1113021Ssam #include <sys/file.h>
12*16452Sroot #include <ttyent.h>
131029Sbill 
141029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
15*16452Sroot #define	TTYSIZ	16
161029Sbill #define	TABSIZ	100
171029Sbill #define	ALL	p = &itab[0]; p < &itab[TABSIZ]; p++
181029Sbill #define	EVER	;;
191029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
201029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
2113021Ssam #define	mask(s)	(1 << ((s)-1))
221029Sbill 
231029Sbill char	shell[]	= "/bin/sh";
241403Sbill char	getty[]	 = "/etc/getty";
251029Sbill char	minus[]	= "-";
261029Sbill char	runc[]	= "/etc/rc";
271029Sbill char	utmp[]	= "/etc/utmp";
281029Sbill char	wtmpf[]	= "/usr/adm/wtmp";
291029Sbill char	ctty[]	= "/dev/console";
301029Sbill char	dev[]	= "/dev/";
311029Sbill 
321029Sbill struct utmp wtmp;
331029Sbill struct	tab
341029Sbill {
351029Sbill 	char	line[LINSIZ];
36*16452Sroot 	char	comn[TTYSIZ];
371029Sbill 	char	xflag;
381029Sbill 	int	pid;
395971Sroot 	time_t	gettytime;
405971Sroot 	int	gettycnt;
411029Sbill } itab[TABSIZ];
421029Sbill 
431029Sbill int	fi;
441029Sbill int	mergflag;
451029Sbill char	tty[20];
461429Sbill jmp_buf	sjbuf, shutpass;
472821Swnj time_t	time0;
481029Sbill 
491029Sbill int	reset();
502821Swnj int	idle();
511029Sbill char	*strcpy(), *strcat();
521029Sbill long	lseek();
531029Sbill 
5413021Ssam struct	sigvec rvec = { reset, mask(SIGHUP), 0 };
5513021Ssam 
5613021Ssam #ifdef vax
571029Sbill main()
581029Sbill {
591403Sbill 	register int r11;		/* passed thru from boot */
6013021Ssam #else
619869Spugs main(argc, argv)
629869Spugs 	char **argv;
639869Spugs {
6413021Ssam #endif
651403Sbill 	int howto, oldhowto;
661403Sbill 
672821Swnj 	time0 = time(0);
6813021Ssam #ifdef vax
691403Sbill 	howto = r11;
7013021Ssam #else
719869Spugs 	if (argc > 1 && argv[1][0] == '-') {
729869Spugs 		char *cp;
739869Spugs 
749869Spugs 		howto = 0;
759869Spugs 		cp = &argv[1][1];
769869Spugs 		while (*cp) switch (*cp++) {
779869Spugs 		case 'a':
789869Spugs 			howto |= RB_ASKNAME;
799869Spugs 			break;
809869Spugs 		case 's':
819869Spugs 			howto |= RB_SINGLE;
829869Spugs 			break;
839869Spugs 		}
849869Spugs 	} else {
859869Spugs 		howto = RB_SINGLE;
869869Spugs 	}
8713021Ssam #endif
8813021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
892821Swnj 	signal(SIGTSTP, idle);
901029Sbill 	signal(SIGSTOP, SIG_IGN);
911029Sbill 	signal(SIGTTIN, SIG_IGN);
921029Sbill 	signal(SIGTTOU, SIG_IGN);
9313021Ssam 	(void) setjmp(sjbuf);
9413021Ssam 	for (EVER) {
951403Sbill 		oldhowto = howto;
961403Sbill 		howto = RB_SINGLE;
971429Sbill 		if (setjmp(shutpass) == 0)
981429Sbill 			shutdown();
991403Sbill 		if (oldhowto & RB_SINGLE)
1001403Sbill 			single();
1011403Sbill 		if (runcom(oldhowto) == 0)
1021403Sbill 			continue;
1031029Sbill 		merge();
1041029Sbill 		multiple();
1051029Sbill 	}
1061029Sbill }
1071029Sbill 
1081429Sbill int	shutreset();
1091429Sbill 
1101029Sbill shutdown()
1111029Sbill {
1121029Sbill 	register i;
1131029Sbill 	register struct tab *p;
1141029Sbill 
1151029Sbill 	close(creat(utmp, 0644));
1161029Sbill 	signal(SIGHUP, SIG_IGN);
11713021Ssam 	for (ALL) {
1181029Sbill 		term(p);
1191029Sbill 		p->line[0] = 0;
1201029Sbill 	}
1211429Sbill 	signal(SIGALRM, shutreset);
1221429Sbill 	alarm(30);
12313021Ssam 	for (i = 0; i < 5; i++)
1241029Sbill 		kill(-1, SIGKILL);
12513021Ssam 	while (wait((int *)0) != -1)
1261029Sbill 		;
1271029Sbill 	alarm(0);
1281429Sbill 	shutend();
1291429Sbill }
1301429Sbill 
1311429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
1321429Sbill 
1331429Sbill shutreset()
1341429Sbill {
1351429Sbill 	int status;
1361429Sbill 
1371429Sbill 	if (fork() == 0) {
1381429Sbill 		int ct = open(ctty, 1);
1391429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1401429Sbill 		sleep(5);
1411429Sbill 		exit(1);
1421429Sbill 	}
1431429Sbill 	sleep(5);
1441429Sbill 	shutend();
1451429Sbill 	longjmp(shutpass, 1);
1461429Sbill }
1471429Sbill 
1481429Sbill shutend()
1491429Sbill {
1502821Swnj 	register i, f;
1511429Sbill 
1522821Swnj 	acct(0);
1531029Sbill 	signal(SIGALRM, SIG_DFL);
15413021Ssam 	for (i = 0; i < 10; i++)
1551029Sbill 		close(i);
15613021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1572821Swnj 	if (f >= 0) {
1582821Swnj 		SCPYN(wtmp.ut_line, "~");
1592821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
16012682Ssam 		SCPYN(wtmp.ut_host, "");
1612821Swnj 		time(&wtmp.ut_time);
1622821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1632821Swnj 		close(f);
1642821Swnj 	}
16513021Ssam 	return (1);
1661029Sbill }
1671029Sbill 
1681029Sbill single()
1691029Sbill {
1701029Sbill 	register pid;
1712821Swnj 	register xpid;
1722821Swnj 	extern	errno;
1731029Sbill 
17413021Ssam 	do {
17513021Ssam 		pid = fork();
17613021Ssam 		if (pid == 0) {
17713021Ssam 			signal(SIGTERM, SIG_DFL);
17813021Ssam 			signal(SIGHUP, SIG_DFL);
17913021Ssam 			signal(SIGALRM, SIG_DFL);
180*16452Sroot 			signal(SIGTSTP, SIG_IGN);
18113021Ssam 			(void) open(ctty, O_RDWR);
18213021Ssam 			dup2(0, 1);
18313021Ssam 			dup2(0, 2);
18413021Ssam 			execl(shell, minus, (char *)0);
18513021Ssam 			exit(0);
18613021Ssam 		}
18713021Ssam 		while ((xpid = wait((int *)0)) != pid)
18813021Ssam 			if (xpid == -1 && errno == ECHILD)
18913021Ssam 				break;
19013021Ssam 	} while (xpid == -1);
1911029Sbill }
1921029Sbill 
1931403Sbill runcom(oldhowto)
1941403Sbill 	int oldhowto;
1951029Sbill {
1961029Sbill 	register pid, f;
1971403Sbill 	int status;
1981029Sbill 
1991029Sbill 	pid = fork();
20013021Ssam 	if (pid == 0) {
20113021Ssam 		(void) open("/", O_RDONLY);
20213021Ssam 		dup2(0, 1);
20313021Ssam 		dup2(0, 2);
2041403Sbill 		if (oldhowto & RB_SINGLE)
2051403Sbill 			execl(shell, shell, runc, (char *)0);
2061403Sbill 		else
2071403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2081403Sbill 		exit(1);
2091029Sbill 	}
21013021Ssam 	while (wait(&status) != pid)
2111029Sbill 		;
21213021Ssam 	if (status)
21313021Ssam 		return (0);
21413021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2151029Sbill 	if (f >= 0) {
2161029Sbill 		SCPYN(wtmp.ut_line, "~");
2171029Sbill 		SCPYN(wtmp.ut_name, "reboot");
21812682Ssam 		SCPYN(wtmp.ut_host, "");
2192821Swnj 		if (time0) {
2202821Swnj 			wtmp.ut_time = time0;
2212821Swnj 			time0 = 0;
2222821Swnj 		} else
2232821Swnj 			time(&wtmp.ut_time);
2241029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2251029Sbill 		close(f);
2261029Sbill 	}
22713021Ssam 	return (1);
2281029Sbill }
2291029Sbill 
23013021Ssam struct	sigvec	mvec = { merge, mask(SIGTERM), 0 };
23113021Ssam /*
23213021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
23313021Ssam  * which indicate ttys has changed, and SIGTERM's which
23413021Ssam  * are used to shutdown the system.
23513021Ssam  */
2361029Sbill multiple()
2371029Sbill {
2381029Sbill 	register struct tab *p;
2391029Sbill 	register pid;
2401029Sbill 
24113021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
24213021Ssam 	for (EVER) {
2431029Sbill 		pid = wait((int *)0);
24413021Ssam 		if (pid == -1)
2451029Sbill 			return;
24613021Ssam 		for (ALL)
24713021Ssam 			if (p->pid == pid || p->pid == -1) {
2481029Sbill 				rmut(p);
2491029Sbill 				dfork(p);
2501029Sbill 			}
2511029Sbill 	}
2521029Sbill }
2531029Sbill 
25413021Ssam /*
25513021Ssam  * Merge current contents of ttys file
25613021Ssam  * into in-core table of configured tty lines.
25713021Ssam  * Entered as signal handler for SIGHUP.
25813021Ssam  */
25913021Ssam #define	FOUND	1
26013021Ssam #define	CHANGE	2
26113021Ssam 
26213021Ssam merge()
26313021Ssam {
26413021Ssam 	register struct tab *p;
265*16452Sroot 	register struct ttyent *t;
26613021Ssam 
26713021Ssam 	for (ALL)
26813021Ssam 		p->xflag = 0;
269*16452Sroot 	setttyent();
270*16452Sroot 	while (t = getttyent()) {
271*16452Sroot 		if ((t->ty_status & TTY_ON) == 0)
272*16452Sroot 			continue;
273*16452Sroot 		strcpy(tty, dev);
274*16452Sroot 		strcat(tty, t->ty_name);
275*16452Sroot 		if (access(tty, R_OK|W_OK) < 0)
276*16452Sroot 			continue;
27713021Ssam 		for (ALL) {
278*16452Sroot 			if (SCMPN(p->line, t->ty_name))
27913021Ssam 				continue;
28013021Ssam 			p->xflag |= FOUND;
281*16452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
28213021Ssam 				p->xflag |= CHANGE;
283*16452Sroot 				SCPYN(p->comn, t->ty_getty);
28413021Ssam 			}
28513021Ssam 			goto contin1;
28613021Ssam 		}
28713021Ssam 		for (ALL) {
28813021Ssam 			if (p->line[0] != 0)
28913021Ssam 				continue;
290*16452Sroot 			SCPYN(p->line, t->ty_name);
29113021Ssam 			p->xflag |= FOUND|CHANGE;
292*16452Sroot 			SCPYN(p->comn, t->ty_getty);
29313021Ssam 			goto contin1;
29413021Ssam 		}
29513021Ssam 	contin1:
29613021Ssam 		;
29713021Ssam 	}
298*16452Sroot 	endttyent();
29913021Ssam 	for (ALL) {
30013021Ssam 		if ((p->xflag&FOUND) == 0) {
30113021Ssam 			term(p);
30213021Ssam 			p->line[0] = 0;
30313021Ssam 		}
30413021Ssam 		if (p->xflag&CHANGE) {
30513021Ssam 			term(p);
30613021Ssam 			dfork(p);
30713021Ssam 		}
30813021Ssam 	}
30913021Ssam }
31013021Ssam 
3111029Sbill term(p)
31213021Ssam 	register struct tab *p;
3131029Sbill {
3141029Sbill 
31513021Ssam 	if (p->pid != 0) {
3161029Sbill 		rmut(p);
3171029Sbill 		kill(p->pid, SIGKILL);
3181029Sbill 	}
3191029Sbill 	p->pid = 0;
3201029Sbill }
3211029Sbill 
3226816Ssam #include <sys/ioctl.h>
3236816Ssam 
3241029Sbill dfork(p)
32513021Ssam 	struct tab *p;
3261029Sbill {
3271029Sbill 	register pid;
3285971Sroot 	time_t t;
3295971Sroot 	int dowait = 0;
3309579Spugs 	extern char *sys_errlist[];
3311029Sbill 
3325971Sroot 	time(&t);
3335971Sroot 	p->gettycnt++;
3345971Sroot 	if ((t - p->gettytime) >= 60) {
3355971Sroot 		p->gettytime = t;
3365971Sroot 		p->gettycnt = 1;
3375971Sroot 	} else {
3385971Sroot 		if (p->gettycnt >= 5) {
3395971Sroot 			dowait = 1;
3405971Sroot 			p->gettytime = t;
3415971Sroot 			p->gettycnt = 1;
3425971Sroot 		}
3435971Sroot 	}
3441029Sbill 	pid = fork();
34513021Ssam 	if (pid == 0) {
3466816Ssam 		int oerrno, f;
3476816Ssam 		extern int errno;
3486816Ssam 
3496816Ssam 		signal(SIGTERM, SIG_DFL);
3506816Ssam 		signal(SIGHUP, SIG_IGN);
3519579Spugs 		strcpy(tty, dev);
3529579Spugs 		strncat(tty, p->line, LINSIZ);
3535971Sroot 		if (dowait) {
35413021Ssam 			f = open("/dev/console", O_WRONLY);
3555971Sroot 			write(f, "init: ", 6);
3565971Sroot 			write(f, tty, strlen(tty));
3575971Sroot 			write(f, ": getty failing, sleeping\n\r", 27);
3585971Sroot 			close(f);
3595971Sroot 			sleep(30);
36013021Ssam 			if ((f = open("/dev/tty", O_RDWR)) >= 0) {
3616816Ssam 				ioctl(f, TIOCNOTTY, 0);
3626816Ssam 				close(f);
3636816Ssam 			}
3645971Sroot 		}
3651029Sbill 		chown(tty, 0, 0);
3661029Sbill 		chmod(tty, 0622);
36713021Ssam 		if (open(tty, O_RDWR) < 0) {
3683608Swnj 			int repcnt = 0;
3693608Swnj 			do {
3706816Ssam 				oerrno = errno;
3713608Swnj 				if (repcnt % 10 == 0) {
37213021Ssam 					f = open("/dev/console", O_WRONLY);
3733608Swnj 					write(f, "init: ", 6);
3749579Spugs 					write(f, tty, strlen(tty));
3759579Spugs 					write(f, ": ", 2);
3769579Spugs 					write(f, sys_errlist[oerrno],
3779579Spugs 						strlen(sys_errlist[oerrno]));
3789579Spugs 					write(f, "\n", 1);
3793608Swnj 					close(f);
3806816Ssam 					if ((f = open("/dev/tty", 2)) >= 0) {
3816816Ssam 						ioctl(f, TIOCNOTTY, 0);
3826816Ssam 						close(f);
3836816Ssam 					}
3843608Swnj 				}
3853608Swnj 				repcnt++;
3863608Swnj 				sleep(60);
38713021Ssam 			} while (open(tty, O_RDWR) < 0);
3883608Swnj 			exit(0);	/* have wrong control tty, start over */
3893608Swnj 		}
3901029Sbill 		vhangup();
3911029Sbill 		signal(SIGHUP, SIG_DFL);
39213021Ssam 		(void) open(tty, O_RDWR);
3931029Sbill 		close(0);
3941029Sbill 		dup(1);
3951029Sbill 		dup(0);
396*16452Sroot 		strncpy(tty, p->comn, sizeof(p->comn));
397*16452Sroot 		tty[sizeof(p->comn)] = 0;
3981029Sbill 		execl(getty, minus, tty, (char *)0);
3991029Sbill 		exit(0);
4001029Sbill 	}
4011029Sbill 	p->pid = pid;
4021029Sbill }
4031029Sbill 
40413021Ssam /*
40513021Ssam  * Remove utmp entry.
40613021Ssam  */
4071029Sbill rmut(p)
40813021Ssam 	register struct tab *p;
4091029Sbill {
4101029Sbill 	register f;
4113608Swnj 	int found = 0;
4121029Sbill 
41313021Ssam 	f = open(utmp, O_RDWR);
41413021Ssam 	if (f >= 0) {
41513021Ssam 		while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
4163608Swnj 			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
4171029Sbill 				continue;
4181029Sbill 			lseek(f, -(long)sizeof(wtmp), 1);
4191029Sbill 			SCPYN(wtmp.ut_name, "");
42012682Ssam 			SCPYN(wtmp.ut_host, "");
4211029Sbill 			time(&wtmp.ut_time);
4221029Sbill 			write(f, (char *)&wtmp, sizeof(wtmp));
4233608Swnj 			found++;
4241029Sbill 		}
4251029Sbill 		close(f);
4261029Sbill 	}
4273608Swnj 	if (found) {
42813021Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
4293608Swnj 		if (f >= 0) {
4303608Swnj 			SCPYN(wtmp.ut_line, p->line);
4313608Swnj 			SCPYN(wtmp.ut_name, "");
43212682Ssam 			SCPYN(wtmp.ut_host, "");
4333608Swnj 			time(&wtmp.ut_time);
4343608Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4353608Swnj 			close(f);
4363608Swnj 		}
4371029Sbill 	}
4381029Sbill }
4391029Sbill 
4401029Sbill reset()
4411029Sbill {
44213021Ssam 
4431029Sbill 	longjmp(sjbuf, 1);
4441029Sbill }
4452821Swnj 
44613021Ssam jmp_buf	idlebuf;
44713021Ssam 
44813021Ssam idlehup()
44913021Ssam {
45013021Ssam 
45113021Ssam 	longjmp(idlebuf, 1);
45213021Ssam }
45313021Ssam 
4542821Swnj idle()
4552821Swnj {
4562821Swnj 	register struct tab *p;
4572821Swnj 	register pid;
4582821Swnj 
45913021Ssam 	signal(SIGHUP, idlehup);
4602821Swnj 	for (;;) {
46113021Ssam 		if (setjmp(idlebuf))
46213021Ssam 			return;
4632821Swnj 		pid = wait((int *) 0);
46413021Ssam 		if (pid == -1) {
46513021Ssam 			sigpause(0);
46613021Ssam 			continue;
4672821Swnj 		}
46813021Ssam 		for (ALL)
46913021Ssam 			if (p->pid == pid) {
47013021Ssam 				rmut(p);
47113021Ssam 				p->pid = -1;
47213021Ssam 			}
4732821Swnj 	}
4742821Swnj }
475