xref: /csrg-svn/old/init/init.c (revision 22181)
121135Sdist /*
221135Sdist  * Copyright (c) 1980 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*22181Skarels static char sccsid[] = "@(#)init.c	5.2 (Berkeley) 06/05/85";
921135Sdist #endif not lint
1012682Ssam 
111029Sbill #include <signal.h>
121029Sbill #include <sys/types.h>
131029Sbill #include <utmp.h>
141029Sbill #include <setjmp.h>
151403Sbill #include <sys/reboot.h>
162821Swnj #include <errno.h>
1713021Ssam #include <sys/file.h>
1816452Sroot #include <ttyent.h>
1918542Sralph #include <syslog.h>
201029Sbill 
211029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
2218542Sralph #define	CMDSIZ	70	/* max string length for getty or window command*/
231029Sbill #define	TABSIZ	100
241029Sbill #define	ALL	p = &itab[0]; p < &itab[TABSIZ]; p++
251029Sbill #define	EVER	;;
261029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
271029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
281029Sbill 
291029Sbill char	shell[]	= "/bin/sh";
301029Sbill char	minus[]	= "-";
311029Sbill char	runc[]	= "/etc/rc";
321029Sbill char	utmp[]	= "/etc/utmp";
331029Sbill char	wtmpf[]	= "/usr/adm/wtmp";
341029Sbill char	ctty[]	= "/dev/console";
351029Sbill 
361029Sbill struct utmp wtmp;
371029Sbill struct	tab
381029Sbill {
391029Sbill 	char	line[LINSIZ];
4018542Sralph 	char	comn[CMDSIZ];
411029Sbill 	char	xflag;
421029Sbill 	int	pid;
4318542Sralph 	int	wpid;		/* window system pid for SIGHUP	*/
4418542Sralph 	char	wcmd[CMDSIZ];	/* command to start window system process */
455971Sroot 	time_t	gettytime;
465971Sroot 	int	gettycnt;
47*22181Skarels 	time_t	windtime;
48*22181Skarels 	int	windcnt;
491029Sbill } itab[TABSIZ];
501029Sbill 
511029Sbill int	fi;
521029Sbill int	mergflag;
531029Sbill char	tty[20];
541429Sbill jmp_buf	sjbuf, shutpass;
552821Swnj time_t	time0;
561029Sbill 
571029Sbill int	reset();
582821Swnj int	idle();
591029Sbill char	*strcpy(), *strcat();
601029Sbill long	lseek();
611029Sbill 
6218542Sralph struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
6313021Ssam 
6413021Ssam #ifdef vax
651029Sbill main()
661029Sbill {
671403Sbill 	register int r11;		/* passed thru from boot */
6813021Ssam #else
699869Spugs main(argc, argv)
709869Spugs 	char **argv;
719869Spugs {
7213021Ssam #endif
731403Sbill 	int howto, oldhowto;
741403Sbill 
752821Swnj 	time0 = time(0);
7613021Ssam #ifdef vax
771403Sbill 	howto = r11;
7813021Ssam #else
799869Spugs 	if (argc > 1 && argv[1][0] == '-') {
809869Spugs 		char *cp;
819869Spugs 
829869Spugs 		howto = 0;
839869Spugs 		cp = &argv[1][1];
849869Spugs 		while (*cp) switch (*cp++) {
859869Spugs 		case 'a':
869869Spugs 			howto |= RB_ASKNAME;
879869Spugs 			break;
889869Spugs 		case 's':
899869Spugs 			howto |= RB_SINGLE;
909869Spugs 			break;
919869Spugs 		}
929869Spugs 	} else {
939869Spugs 		howto = RB_SINGLE;
949869Spugs 	}
9513021Ssam #endif
9618542Sralph 	openlog("init", LOG_CONS|LOG_ODELAY, 0);
9713021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
982821Swnj 	signal(SIGTSTP, idle);
991029Sbill 	signal(SIGSTOP, SIG_IGN);
1001029Sbill 	signal(SIGTTIN, SIG_IGN);
1011029Sbill 	signal(SIGTTOU, SIG_IGN);
10213021Ssam 	(void) setjmp(sjbuf);
10313021Ssam 	for (EVER) {
1041403Sbill 		oldhowto = howto;
1051403Sbill 		howto = RB_SINGLE;
1061429Sbill 		if (setjmp(shutpass) == 0)
1071429Sbill 			shutdown();
1081403Sbill 		if (oldhowto & RB_SINGLE)
1091403Sbill 			single();
1101403Sbill 		if (runcom(oldhowto) == 0)
1111403Sbill 			continue;
1121029Sbill 		merge();
1131029Sbill 		multiple();
1141029Sbill 	}
1151029Sbill }
1161029Sbill 
1171429Sbill int	shutreset();
1181429Sbill 
1191029Sbill shutdown()
1201029Sbill {
1211029Sbill 	register i;
1221029Sbill 	register struct tab *p;
1231029Sbill 
1241029Sbill 	close(creat(utmp, 0644));
1251029Sbill 	signal(SIGHUP, SIG_IGN);
12613021Ssam 	for (ALL) {
1271029Sbill 		term(p);
1281029Sbill 		p->line[0] = 0;
1291029Sbill 	}
1301429Sbill 	signal(SIGALRM, shutreset);
1311429Sbill 	alarm(30);
13213021Ssam 	for (i = 0; i < 5; i++)
1331029Sbill 		kill(-1, SIGKILL);
13413021Ssam 	while (wait((int *)0) != -1)
1351029Sbill 		;
1361029Sbill 	alarm(0);
1371429Sbill 	shutend();
1381429Sbill }
1391429Sbill 
1401429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
1411429Sbill 
1421429Sbill shutreset()
1431429Sbill {
1441429Sbill 	int status;
1451429Sbill 
1461429Sbill 	if (fork() == 0) {
1471429Sbill 		int ct = open(ctty, 1);
1481429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1491429Sbill 		sleep(5);
1501429Sbill 		exit(1);
1511429Sbill 	}
1521429Sbill 	sleep(5);
1531429Sbill 	shutend();
1541429Sbill 	longjmp(shutpass, 1);
1551429Sbill }
1561429Sbill 
1571429Sbill shutend()
1581429Sbill {
1592821Swnj 	register i, f;
1601429Sbill 
1612821Swnj 	acct(0);
1621029Sbill 	signal(SIGALRM, SIG_DFL);
16313021Ssam 	for (i = 0; i < 10; i++)
1641029Sbill 		close(i);
16513021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1662821Swnj 	if (f >= 0) {
1672821Swnj 		SCPYN(wtmp.ut_line, "~");
1682821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
16912682Ssam 		SCPYN(wtmp.ut_host, "");
1702821Swnj 		time(&wtmp.ut_time);
1712821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1722821Swnj 		close(f);
1732821Swnj 	}
17413021Ssam 	return (1);
1751029Sbill }
1761029Sbill 
1771029Sbill single()
1781029Sbill {
1791029Sbill 	register pid;
1802821Swnj 	register xpid;
1812821Swnj 	extern	errno;
1821029Sbill 
18313021Ssam 	do {
18413021Ssam 		pid = fork();
18513021Ssam 		if (pid == 0) {
18613021Ssam 			signal(SIGTERM, SIG_DFL);
18713021Ssam 			signal(SIGHUP, SIG_DFL);
18813021Ssam 			signal(SIGALRM, SIG_DFL);
18916452Sroot 			signal(SIGTSTP, SIG_IGN);
19013021Ssam 			(void) open(ctty, O_RDWR);
19113021Ssam 			dup2(0, 1);
19213021Ssam 			dup2(0, 2);
19313021Ssam 			execl(shell, minus, (char *)0);
19413021Ssam 			exit(0);
19513021Ssam 		}
19613021Ssam 		while ((xpid = wait((int *)0)) != pid)
19713021Ssam 			if (xpid == -1 && errno == ECHILD)
19813021Ssam 				break;
19913021Ssam 	} while (xpid == -1);
2001029Sbill }
2011029Sbill 
2021403Sbill runcom(oldhowto)
2031403Sbill 	int oldhowto;
2041029Sbill {
2051029Sbill 	register pid, f;
2061403Sbill 	int status;
2071029Sbill 
2081029Sbill 	pid = fork();
20913021Ssam 	if (pid == 0) {
21013021Ssam 		(void) open("/", O_RDONLY);
21113021Ssam 		dup2(0, 1);
21213021Ssam 		dup2(0, 2);
2131403Sbill 		if (oldhowto & RB_SINGLE)
2141403Sbill 			execl(shell, shell, runc, (char *)0);
2151403Sbill 		else
2161403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2171403Sbill 		exit(1);
2181029Sbill 	}
21913021Ssam 	while (wait(&status) != pid)
2201029Sbill 		;
22113021Ssam 	if (status)
22213021Ssam 		return (0);
22313021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2241029Sbill 	if (f >= 0) {
2251029Sbill 		SCPYN(wtmp.ut_line, "~");
2261029Sbill 		SCPYN(wtmp.ut_name, "reboot");
22712682Ssam 		SCPYN(wtmp.ut_host, "");
2282821Swnj 		if (time0) {
2292821Swnj 			wtmp.ut_time = time0;
2302821Swnj 			time0 = 0;
2312821Swnj 		} else
2322821Swnj 			time(&wtmp.ut_time);
2331029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2341029Sbill 		close(f);
2351029Sbill 	}
23613021Ssam 	return (1);
2371029Sbill }
2381029Sbill 
23918542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
24013021Ssam /*
24113021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
24213021Ssam  * which indicate ttys has changed, and SIGTERM's which
24313021Ssam  * are used to shutdown the system.
24413021Ssam  */
2451029Sbill multiple()
2461029Sbill {
2471029Sbill 	register struct tab *p;
2481029Sbill 	register pid;
2491029Sbill 
25013021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
25113021Ssam 	for (EVER) {
2521029Sbill 		pid = wait((int *)0);
25313021Ssam 		if (pid == -1)
2541029Sbill 			return;
25518542Sralph 		for (ALL) {
25618542Sralph 			/* must restart window system BEFORE emulator */
25718542Sralph 			if (p->wpid == pid || p->wpid == -1)
25818542Sralph 				wstart(p);
25913021Ssam 			if (p->pid == pid || p->pid == -1) {
26018542Sralph 				/* disown the window system */
26118542Sralph 				if (p->wpid)
26218542Sralph 					kill(p->wpid, SIGHUP);
2631029Sbill 				rmut(p);
2641029Sbill 				dfork(p);
2651029Sbill 			}
26618542Sralph 		}
2671029Sbill 	}
2681029Sbill }
2691029Sbill 
27013021Ssam /*
27113021Ssam  * Merge current contents of ttys file
27213021Ssam  * into in-core table of configured tty lines.
27313021Ssam  * Entered as signal handler for SIGHUP.
27413021Ssam  */
27513021Ssam #define	FOUND	1
27613021Ssam #define	CHANGE	2
27718542Sralph #define WCHANGE 4
27813021Ssam 
27913021Ssam merge()
28013021Ssam {
28113021Ssam 	register struct tab *p;
28216452Sroot 	register struct ttyent *t;
28313021Ssam 
28413021Ssam 	for (ALL)
28513021Ssam 		p->xflag = 0;
28616452Sroot 	setttyent();
28716452Sroot 	while (t = getttyent()) {
28816452Sroot 		if ((t->ty_status & TTY_ON) == 0)
28916452Sroot 			continue;
29013021Ssam 		for (ALL) {
29116452Sroot 			if (SCMPN(p->line, t->ty_name))
29213021Ssam 				continue;
29313021Ssam 			p->xflag |= FOUND;
29416452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
29513021Ssam 				p->xflag |= CHANGE;
29616452Sroot 				SCPYN(p->comn, t->ty_getty);
29713021Ssam 			}
29818542Sralph 			if (SCMPN(p->wcmd, t->ty_window)) {
29918542Sralph 				p->xflag |= WCHANGE|CHANGE;
30018542Sralph 				SCPYN(p->wcmd, t->ty_window);
30118542Sralph 			}
30213021Ssam 			goto contin1;
30313021Ssam 		}
30418542Sralph 
30513021Ssam 		for (ALL) {
30613021Ssam 			if (p->line[0] != 0)
30713021Ssam 				continue;
30816452Sroot 			SCPYN(p->line, t->ty_name);
30913021Ssam 			p->xflag |= FOUND|CHANGE;
31016452Sroot 			SCPYN(p->comn, t->ty_getty);
31118542Sralph 			if (strcmp(t->ty_window, "") != 0) {
31218542Sralph 				p->xflag |= WCHANGE;
31318542Sralph 				SCPYN(p->wcmd, t->ty_window);
31418542Sralph 			}
31513021Ssam 			goto contin1;
31613021Ssam 		}
31713021Ssam 	contin1:
31813021Ssam 		;
31913021Ssam 	}
32016452Sroot 	endttyent();
32113021Ssam 	for (ALL) {
32213021Ssam 		if ((p->xflag&FOUND) == 0) {
32313021Ssam 			term(p);
32413021Ssam 			p->line[0] = 0;
32518542Sralph 			wterm(p);
32613021Ssam 		}
32718542Sralph 		/* window system should be started first */
32818542Sralph 		if (p->xflag&WCHANGE) {
32918542Sralph 			wterm(p);
33018542Sralph 			wstart(p);
33118542Sralph 		}
33213021Ssam 		if (p->xflag&CHANGE) {
33313021Ssam 			term(p);
33413021Ssam 			dfork(p);
33513021Ssam 		}
33613021Ssam 	}
33713021Ssam }
33813021Ssam 
3391029Sbill term(p)
34013021Ssam 	register struct tab *p;
3411029Sbill {
3421029Sbill 
34313021Ssam 	if (p->pid != 0) {
3441029Sbill 		rmut(p);
3451029Sbill 		kill(p->pid, SIGKILL);
3461029Sbill 	}
3471029Sbill 	p->pid = 0;
34818542Sralph 	/* send SIGHUP to get rid of connections */
34918542Sralph 	if (p->wpid > 0)
35018542Sralph 		kill(p->wpid, SIGHUP);
3511029Sbill }
3521029Sbill 
3536816Ssam #include <sys/ioctl.h>
3546816Ssam 
3551029Sbill dfork(p)
35613021Ssam 	struct tab *p;
3571029Sbill {
3581029Sbill 	register pid;
3595971Sroot 	time_t t;
3605971Sroot 	int dowait = 0;
3611029Sbill 
3625971Sroot 	time(&t);
3635971Sroot 	p->gettycnt++;
3645971Sroot 	if ((t - p->gettytime) >= 60) {
3655971Sroot 		p->gettytime = t;
3665971Sroot 		p->gettycnt = 1;
36718542Sralph 	} else if (p->gettycnt >= 5) {
36818542Sralph 		dowait = 1;
36918542Sralph 		p->gettytime = t;
37018542Sralph 		p->gettycnt = 1;
3715971Sroot 	}
3721029Sbill 	pid = fork();
37313021Ssam 	if (pid == 0) {
3746816Ssam 		signal(SIGTERM, SIG_DFL);
3756816Ssam 		signal(SIGHUP, SIG_IGN);
376*22181Skarels 		sigsetmask(0);	/* since can be called from masked code */
3775971Sroot 		if (dowait) {
37818542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
37918542Sralph 			closelog();
3805971Sroot 			sleep(30);
3815971Sroot 		}
38218542Sralph 		execit(p->comn, p->line);
3831029Sbill 		exit(0);
3841029Sbill 	}
3851029Sbill 	p->pid = pid;
3861029Sbill }
3871029Sbill 
38813021Ssam /*
38913021Ssam  * Remove utmp entry.
39013021Ssam  */
3911029Sbill rmut(p)
39213021Ssam 	register struct tab *p;
3931029Sbill {
3941029Sbill 	register f;
3953608Swnj 	int found = 0;
3961029Sbill 
39713021Ssam 	f = open(utmp, O_RDWR);
39813021Ssam 	if (f >= 0) {
39913021Ssam 		while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
4003608Swnj 			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
4011029Sbill 				continue;
4021029Sbill 			lseek(f, -(long)sizeof(wtmp), 1);
4031029Sbill 			SCPYN(wtmp.ut_name, "");
40412682Ssam 			SCPYN(wtmp.ut_host, "");
4051029Sbill 			time(&wtmp.ut_time);
4061029Sbill 			write(f, (char *)&wtmp, sizeof(wtmp));
4073608Swnj 			found++;
4081029Sbill 		}
4091029Sbill 		close(f);
4101029Sbill 	}
4113608Swnj 	if (found) {
41213021Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
4133608Swnj 		if (f >= 0) {
4143608Swnj 			SCPYN(wtmp.ut_line, p->line);
4153608Swnj 			SCPYN(wtmp.ut_name, "");
41612682Ssam 			SCPYN(wtmp.ut_host, "");
4173608Swnj 			time(&wtmp.ut_time);
4183608Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4193608Swnj 			close(f);
4203608Swnj 		}
42117582Ssam 		/*
42217582Ssam 		 * After a proper login force reset
42317582Ssam 		 * of error detection code in dfork.
42417582Ssam 		 */
42517582Ssam 		p->gettytime = 0;
426*22181Skarels 		p->windtime = 0;
4271029Sbill 	}
4281029Sbill }
4291029Sbill 
4301029Sbill reset()
4311029Sbill {
43213021Ssam 
4331029Sbill 	longjmp(sjbuf, 1);
4341029Sbill }
4352821Swnj 
43613021Ssam jmp_buf	idlebuf;
43713021Ssam 
43813021Ssam idlehup()
43913021Ssam {
44013021Ssam 
44113021Ssam 	longjmp(idlebuf, 1);
44213021Ssam }
44313021Ssam 
4442821Swnj idle()
4452821Swnj {
4462821Swnj 	register struct tab *p;
4472821Swnj 	register pid;
4482821Swnj 
44913021Ssam 	signal(SIGHUP, idlehup);
45018542Sralph 	for (EVER) {
45113021Ssam 		if (setjmp(idlebuf))
45213021Ssam 			return;
4532821Swnj 		pid = wait((int *) 0);
45413021Ssam 		if (pid == -1) {
45513021Ssam 			sigpause(0);
45613021Ssam 			continue;
4572821Swnj 		}
45818542Sralph 		for (ALL) {
45918542Sralph 			/* if window system dies, mark it for restart */
46018542Sralph 			if (p->wpid == pid)
46118542Sralph 				p->wpid = -1;
46213021Ssam 			if (p->pid == pid) {
46313021Ssam 				rmut(p);
46413021Ssam 				p->pid = -1;
46513021Ssam 			}
46618542Sralph 		}
4672821Swnj 	}
4682821Swnj }
46918542Sralph 
47018542Sralph wterm(p)
47118542Sralph 	register struct tab *p;
47218542Sralph {
47318542Sralph 	if (p->wpid != 0) {
47418542Sralph 		kill(p->wpid, SIGKILL);
47518542Sralph 	}
47618542Sralph 	p->wpid = 0;
47718542Sralph }
47818542Sralph 
47918542Sralph wstart(p)
48018542Sralph 	register struct tab *p;
48118542Sralph {
482*22181Skarels 	register pid;
483*22181Skarels 	time_t t;
484*22181Skarels 	int dowait = 0;
48518542Sralph 
486*22181Skarels 	time(&t);
487*22181Skarels 	p->windcnt++;
488*22181Skarels 	if ((t - p->windtime) >= 60) {
489*22181Skarels 		p->windtime = t;
490*22181Skarels 		p->windcnt = 1;
491*22181Skarels 	} else if (p->windcnt >= 5) {
492*22181Skarels 		dowait = 1;
493*22181Skarels 		p->windtime = t;
494*22181Skarels 		p->windcnt = 1;
495*22181Skarels 	}
496*22181Skarels 
497*22181Skarels 	pid = fork();
498*22181Skarels 
499*22181Skarels 	if (pid == 0) {
50018542Sralph 		signal(SIGTERM, SIG_DFL);
501*22181Skarels 		signal(SIGHUP,  SIG_IGN);
502*22181Skarels 		sigsetmask(0);	/* since can be called from masked code */
503*22181Skarels 		if (dowait) {
504*22181Skarels 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
505*22181Skarels 			closelog();
506*22181Skarels 			sleep(30);
507*22181Skarels 		}
50818542Sralph 		execit(p->wcmd, p->line);
50918542Sralph 		exit(0);
51018542Sralph 	}
511*22181Skarels 	p->wpid = pid;
51218542Sralph }
51318542Sralph 
514*22181Skarels #define NARGS	20	/* must be at least 4 */
51518542Sralph #define ARGLEN	512	/* total size for all the argument strings */
51618542Sralph 
51718542Sralph execit(s, arg)
51818542Sralph 	char *s;
51918542Sralph 	char *arg;	/* last argument on line */
52018542Sralph {
52118542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
52218542Sralph 	register char *sp = s;
52318542Sralph 	register char *ap = args;
52418542Sralph 	register char c;
52518542Sralph 	register int i;
52618542Sralph 
52718542Sralph 	/*
52818542Sralph 	 * First we have to set up the argument vector.
52918542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
53018542Sralph 	 */
53118542Sralph 	for (i = 1; i < NARGS - 2; i++) {
53218542Sralph 		argv[i] = ap;
53318542Sralph 		for (EVER) {
53418542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
53518542Sralph 				*ap = '\0';
53618542Sralph 				goto done;
53718542Sralph 			}
53818542Sralph 			if (c == ' ') {
53918542Sralph 				*ap++ = '\0';
54018542Sralph 				while (*sp == ' ')
54118542Sralph 					sp++;
54218542Sralph 				if (*sp == '\0')
54318542Sralph 					goto done;
54418542Sralph 				break;
54518542Sralph 			}
54618542Sralph 			*ap++ = c;
54718542Sralph 		}
54818542Sralph 	}
54918542Sralph done:
55018542Sralph 	argv[0] = argv[1];
55118542Sralph 	argv[1] = "-";
55218542Sralph 	argv[i+1] = arg;
55318542Sralph 	argv[i+2] = 0;
55418542Sralph 	envp[0] = 0;
55518542Sralph 	execve(argv[0], &argv[1], envp);
55618542Sralph 	/* report failure of exec */
55718542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
55818542Sralph 	closelog();
55918542Sralph 	sleep(10);	/* prevent failures from eating machine */
56018542Sralph }
561