xref: /csrg-svn/old/init/init.c (revision 18542)
112682Ssam #ifndef lint
2*18542Sralph static	char *sccsid = "@(#)init.c	4.15 (Berkeley) 04/01/85";
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>
1216452Sroot #include <ttyent.h>
13*18542Sralph #include <syslog.h>
141029Sbill 
151029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
16*18542Sralph #define	CMDSIZ	70	/* max string length for getty or window command*/
171029Sbill #define	TABSIZ	100
181029Sbill #define	ALL	p = &itab[0]; p < &itab[TABSIZ]; p++
191029Sbill #define	EVER	;;
201029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
211029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
221029Sbill 
231029Sbill char	shell[]	= "/bin/sh";
241029Sbill char	minus[]	= "-";
251029Sbill char	runc[]	= "/etc/rc";
261029Sbill char	utmp[]	= "/etc/utmp";
271029Sbill char	wtmpf[]	= "/usr/adm/wtmp";
281029Sbill char	ctty[]	= "/dev/console";
291029Sbill 
301029Sbill struct utmp wtmp;
311029Sbill struct	tab
321029Sbill {
331029Sbill 	char	line[LINSIZ];
34*18542Sralph 	char	comn[CMDSIZ];
351029Sbill 	char	xflag;
361029Sbill 	int	pid;
37*18542Sralph 	int	wpid;		/* window system pid for SIGHUP	*/
38*18542Sralph 	char	wcmd[CMDSIZ];	/* command to start window system process */
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 
54*18542Sralph struct	sigvec rvec = { reset, sigmask(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
88*18542Sralph 	openlog("init", LOG_CONS|LOG_ODELAY, 0);
8913021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
902821Swnj 	signal(SIGTSTP, idle);
911029Sbill 	signal(SIGSTOP, SIG_IGN);
921029Sbill 	signal(SIGTTIN, SIG_IGN);
931029Sbill 	signal(SIGTTOU, SIG_IGN);
9413021Ssam 	(void) setjmp(sjbuf);
9513021Ssam 	for (EVER) {
961403Sbill 		oldhowto = howto;
971403Sbill 		howto = RB_SINGLE;
981429Sbill 		if (setjmp(shutpass) == 0)
991429Sbill 			shutdown();
1001403Sbill 		if (oldhowto & RB_SINGLE)
1011403Sbill 			single();
1021403Sbill 		if (runcom(oldhowto) == 0)
1031403Sbill 			continue;
1041029Sbill 		merge();
1051029Sbill 		multiple();
1061029Sbill 	}
1071029Sbill }
1081029Sbill 
1091429Sbill int	shutreset();
1101429Sbill 
1111029Sbill shutdown()
1121029Sbill {
1131029Sbill 	register i;
1141029Sbill 	register struct tab *p;
1151029Sbill 
1161029Sbill 	close(creat(utmp, 0644));
1171029Sbill 	signal(SIGHUP, SIG_IGN);
11813021Ssam 	for (ALL) {
1191029Sbill 		term(p);
1201029Sbill 		p->line[0] = 0;
1211029Sbill 	}
1221429Sbill 	signal(SIGALRM, shutreset);
1231429Sbill 	alarm(30);
12413021Ssam 	for (i = 0; i < 5; i++)
1251029Sbill 		kill(-1, SIGKILL);
12613021Ssam 	while (wait((int *)0) != -1)
1271029Sbill 		;
1281029Sbill 	alarm(0);
1291429Sbill 	shutend();
1301429Sbill }
1311429Sbill 
1321429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
1331429Sbill 
1341429Sbill shutreset()
1351429Sbill {
1361429Sbill 	int status;
1371429Sbill 
1381429Sbill 	if (fork() == 0) {
1391429Sbill 		int ct = open(ctty, 1);
1401429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1411429Sbill 		sleep(5);
1421429Sbill 		exit(1);
1431429Sbill 	}
1441429Sbill 	sleep(5);
1451429Sbill 	shutend();
1461429Sbill 	longjmp(shutpass, 1);
1471429Sbill }
1481429Sbill 
1491429Sbill shutend()
1501429Sbill {
1512821Swnj 	register i, f;
1521429Sbill 
1532821Swnj 	acct(0);
1541029Sbill 	signal(SIGALRM, SIG_DFL);
15513021Ssam 	for (i = 0; i < 10; i++)
1561029Sbill 		close(i);
15713021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1582821Swnj 	if (f >= 0) {
1592821Swnj 		SCPYN(wtmp.ut_line, "~");
1602821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
16112682Ssam 		SCPYN(wtmp.ut_host, "");
1622821Swnj 		time(&wtmp.ut_time);
1632821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1642821Swnj 		close(f);
1652821Swnj 	}
16613021Ssam 	return (1);
1671029Sbill }
1681029Sbill 
1691029Sbill single()
1701029Sbill {
1711029Sbill 	register pid;
1722821Swnj 	register xpid;
1732821Swnj 	extern	errno;
1741029Sbill 
17513021Ssam 	do {
17613021Ssam 		pid = fork();
17713021Ssam 		if (pid == 0) {
17813021Ssam 			signal(SIGTERM, SIG_DFL);
17913021Ssam 			signal(SIGHUP, SIG_DFL);
18013021Ssam 			signal(SIGALRM, SIG_DFL);
18116452Sroot 			signal(SIGTSTP, SIG_IGN);
18213021Ssam 			(void) open(ctty, O_RDWR);
18313021Ssam 			dup2(0, 1);
18413021Ssam 			dup2(0, 2);
18513021Ssam 			execl(shell, minus, (char *)0);
18613021Ssam 			exit(0);
18713021Ssam 		}
18813021Ssam 		while ((xpid = wait((int *)0)) != pid)
18913021Ssam 			if (xpid == -1 && errno == ECHILD)
19013021Ssam 				break;
19113021Ssam 	} while (xpid == -1);
1921029Sbill }
1931029Sbill 
1941403Sbill runcom(oldhowto)
1951403Sbill 	int oldhowto;
1961029Sbill {
1971029Sbill 	register pid, f;
1981403Sbill 	int status;
1991029Sbill 
2001029Sbill 	pid = fork();
20113021Ssam 	if (pid == 0) {
20213021Ssam 		(void) open("/", O_RDONLY);
20313021Ssam 		dup2(0, 1);
20413021Ssam 		dup2(0, 2);
2051403Sbill 		if (oldhowto & RB_SINGLE)
2061403Sbill 			execl(shell, shell, runc, (char *)0);
2071403Sbill 		else
2081403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2091403Sbill 		exit(1);
2101029Sbill 	}
21113021Ssam 	while (wait(&status) != pid)
2121029Sbill 		;
21313021Ssam 	if (status)
21413021Ssam 		return (0);
21513021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2161029Sbill 	if (f >= 0) {
2171029Sbill 		SCPYN(wtmp.ut_line, "~");
2181029Sbill 		SCPYN(wtmp.ut_name, "reboot");
21912682Ssam 		SCPYN(wtmp.ut_host, "");
2202821Swnj 		if (time0) {
2212821Swnj 			wtmp.ut_time = time0;
2222821Swnj 			time0 = 0;
2232821Swnj 		} else
2242821Swnj 			time(&wtmp.ut_time);
2251029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2261029Sbill 		close(f);
2271029Sbill 	}
22813021Ssam 	return (1);
2291029Sbill }
2301029Sbill 
231*18542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
23213021Ssam /*
23313021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
23413021Ssam  * which indicate ttys has changed, and SIGTERM's which
23513021Ssam  * are used to shutdown the system.
23613021Ssam  */
2371029Sbill multiple()
2381029Sbill {
2391029Sbill 	register struct tab *p;
2401029Sbill 	register pid;
2411029Sbill 
24213021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
24313021Ssam 	for (EVER) {
2441029Sbill 		pid = wait((int *)0);
24513021Ssam 		if (pid == -1)
2461029Sbill 			return;
247*18542Sralph 		for (ALL) {
248*18542Sralph 			/* must restart window system BEFORE emulator */
249*18542Sralph 			if (p->wpid == pid || p->wpid == -1)
250*18542Sralph 				wstart(p);
25113021Ssam 			if (p->pid == pid || p->pid == -1) {
252*18542Sralph 				/* disown the window system */
253*18542Sralph 				if (p->wpid)
254*18542Sralph 					kill(p->wpid, SIGHUP);
2551029Sbill 				rmut(p);
2561029Sbill 				dfork(p);
2571029Sbill 			}
258*18542Sralph 		}
2591029Sbill 	}
2601029Sbill }
2611029Sbill 
26213021Ssam /*
26313021Ssam  * Merge current contents of ttys file
26413021Ssam  * into in-core table of configured tty lines.
26513021Ssam  * Entered as signal handler for SIGHUP.
26613021Ssam  */
26713021Ssam #define	FOUND	1
26813021Ssam #define	CHANGE	2
269*18542Sralph #define WCHANGE 4
27013021Ssam 
27113021Ssam merge()
27213021Ssam {
27313021Ssam 	register struct tab *p;
27416452Sroot 	register struct ttyent *t;
27513021Ssam 
27613021Ssam 	for (ALL)
27713021Ssam 		p->xflag = 0;
27816452Sroot 	setttyent();
27916452Sroot 	while (t = getttyent()) {
28016452Sroot 		if ((t->ty_status & TTY_ON) == 0)
28116452Sroot 			continue;
28213021Ssam 		for (ALL) {
28316452Sroot 			if (SCMPN(p->line, t->ty_name))
28413021Ssam 				continue;
28513021Ssam 			p->xflag |= FOUND;
28616452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
28713021Ssam 				p->xflag |= CHANGE;
28816452Sroot 				SCPYN(p->comn, t->ty_getty);
28913021Ssam 			}
290*18542Sralph 			if (SCMPN(p->wcmd, t->ty_window)) {
291*18542Sralph 				p->xflag |= WCHANGE|CHANGE;
292*18542Sralph 				SCPYN(p->wcmd, t->ty_window);
293*18542Sralph 			}
29413021Ssam 			goto contin1;
29513021Ssam 		}
296*18542Sralph 
29713021Ssam 		for (ALL) {
29813021Ssam 			if (p->line[0] != 0)
29913021Ssam 				continue;
30016452Sroot 			SCPYN(p->line, t->ty_name);
30113021Ssam 			p->xflag |= FOUND|CHANGE;
30216452Sroot 			SCPYN(p->comn, t->ty_getty);
303*18542Sralph 			if (strcmp(t->ty_window, "") != 0) {
304*18542Sralph 				p->xflag |= WCHANGE;
305*18542Sralph 				SCPYN(p->wcmd, t->ty_window);
306*18542Sralph 			}
30713021Ssam 			goto contin1;
30813021Ssam 		}
30913021Ssam 	contin1:
31013021Ssam 		;
31113021Ssam 	}
31216452Sroot 	endttyent();
31313021Ssam 	for (ALL) {
31413021Ssam 		if ((p->xflag&FOUND) == 0) {
31513021Ssam 			term(p);
31613021Ssam 			p->line[0] = 0;
317*18542Sralph 			wterm(p);
31813021Ssam 		}
319*18542Sralph 		/* window system should be started first */
320*18542Sralph 		if (p->xflag&WCHANGE) {
321*18542Sralph 			wterm(p);
322*18542Sralph 			wstart(p);
323*18542Sralph 		}
32413021Ssam 		if (p->xflag&CHANGE) {
32513021Ssam 			term(p);
32613021Ssam 			dfork(p);
32713021Ssam 		}
32813021Ssam 	}
32913021Ssam }
33013021Ssam 
3311029Sbill term(p)
33213021Ssam 	register struct tab *p;
3331029Sbill {
3341029Sbill 
33513021Ssam 	if (p->pid != 0) {
3361029Sbill 		rmut(p);
3371029Sbill 		kill(p->pid, SIGKILL);
3381029Sbill 	}
3391029Sbill 	p->pid = 0;
340*18542Sralph 	/* send SIGHUP to get rid of connections */
341*18542Sralph 	if (p->wpid > 0)
342*18542Sralph 		kill(p->wpid, SIGHUP);
3431029Sbill }
3441029Sbill 
3456816Ssam #include <sys/ioctl.h>
3466816Ssam 
3471029Sbill dfork(p)
34813021Ssam 	struct tab *p;
3491029Sbill {
3501029Sbill 	register pid;
3515971Sroot 	time_t t;
3525971Sroot 	int dowait = 0;
3531029Sbill 
3545971Sroot 	time(&t);
3555971Sroot 	p->gettycnt++;
3565971Sroot 	if ((t - p->gettytime) >= 60) {
3575971Sroot 		p->gettytime = t;
3585971Sroot 		p->gettycnt = 1;
359*18542Sralph 	} else if (p->gettycnt >= 5) {
360*18542Sralph 		dowait = 1;
361*18542Sralph 		p->gettytime = t;
362*18542Sralph 		p->gettycnt = 1;
3635971Sroot 	}
3641029Sbill 	pid = fork();
36513021Ssam 	if (pid == 0) {
3666816Ssam 		signal(SIGTERM, SIG_DFL);
3676816Ssam 		signal(SIGHUP, SIG_IGN);
3685971Sroot 		if (dowait) {
369*18542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
370*18542Sralph 			closelog();
3715971Sroot 			sleep(30);
3725971Sroot 		}
373*18542Sralph 		execit(p->comn, p->line);
3741029Sbill 		exit(0);
3751029Sbill 	}
3761029Sbill 	p->pid = pid;
3771029Sbill }
3781029Sbill 
37913021Ssam /*
38013021Ssam  * Remove utmp entry.
38113021Ssam  */
3821029Sbill rmut(p)
38313021Ssam 	register struct tab *p;
3841029Sbill {
3851029Sbill 	register f;
3863608Swnj 	int found = 0;
3871029Sbill 
38813021Ssam 	f = open(utmp, O_RDWR);
38913021Ssam 	if (f >= 0) {
39013021Ssam 		while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
3913608Swnj 			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
3921029Sbill 				continue;
3931029Sbill 			lseek(f, -(long)sizeof(wtmp), 1);
3941029Sbill 			SCPYN(wtmp.ut_name, "");
39512682Ssam 			SCPYN(wtmp.ut_host, "");
3961029Sbill 			time(&wtmp.ut_time);
3971029Sbill 			write(f, (char *)&wtmp, sizeof(wtmp));
3983608Swnj 			found++;
3991029Sbill 		}
4001029Sbill 		close(f);
4011029Sbill 	}
4023608Swnj 	if (found) {
40313021Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
4043608Swnj 		if (f >= 0) {
4053608Swnj 			SCPYN(wtmp.ut_line, p->line);
4063608Swnj 			SCPYN(wtmp.ut_name, "");
40712682Ssam 			SCPYN(wtmp.ut_host, "");
4083608Swnj 			time(&wtmp.ut_time);
4093608Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4103608Swnj 			close(f);
4113608Swnj 		}
41217582Ssam 		/*
41317582Ssam 		 * After a proper login force reset
41417582Ssam 		 * of error detection code in dfork.
41517582Ssam 		 */
41617582Ssam 		p->gettytime = 0;
4171029Sbill 	}
4181029Sbill }
4191029Sbill 
4201029Sbill reset()
4211029Sbill {
42213021Ssam 
4231029Sbill 	longjmp(sjbuf, 1);
4241029Sbill }
4252821Swnj 
42613021Ssam jmp_buf	idlebuf;
42713021Ssam 
42813021Ssam idlehup()
42913021Ssam {
43013021Ssam 
43113021Ssam 	longjmp(idlebuf, 1);
43213021Ssam }
43313021Ssam 
4342821Swnj idle()
4352821Swnj {
4362821Swnj 	register struct tab *p;
4372821Swnj 	register pid;
4382821Swnj 
43913021Ssam 	signal(SIGHUP, idlehup);
440*18542Sralph 	for (EVER) {
44113021Ssam 		if (setjmp(idlebuf))
44213021Ssam 			return;
4432821Swnj 		pid = wait((int *) 0);
44413021Ssam 		if (pid == -1) {
44513021Ssam 			sigpause(0);
44613021Ssam 			continue;
4472821Swnj 		}
448*18542Sralph 		for (ALL) {
449*18542Sralph 			/* if window system dies, mark it for restart */
450*18542Sralph 			if (p->wpid == pid)
451*18542Sralph 				p->wpid = -1;
45213021Ssam 			if (p->pid == pid) {
45313021Ssam 				rmut(p);
45413021Ssam 				p->pid = -1;
45513021Ssam 			}
456*18542Sralph 		}
4572821Swnj 	}
4582821Swnj }
459*18542Sralph 
460*18542Sralph wterm(p)
461*18542Sralph 	register struct tab *p;
462*18542Sralph {
463*18542Sralph 	if (p->wpid != 0) {
464*18542Sralph 		kill(p->wpid, SIGKILL);
465*18542Sralph 	}
466*18542Sralph 	p->wpid = 0;
467*18542Sralph }
468*18542Sralph 
469*18542Sralph wstart(p)
470*18542Sralph 	register struct tab *p;
471*18542Sralph {
472*18542Sralph 	int npid = fork();
473*18542Sralph 
474*18542Sralph 	if (npid == 0) {
475*18542Sralph /*
476*18542Sralph 		signal(SIGTERM, SIG_DFL);
477*18542Sralph 		signal(SIGHUP,  SIG_DFL);
478*18542Sralph 		signal(SIGALRM, SIG_DFL);
479*18542Sralph 		signal(SIGTSTP, SIG_IGN);
480*18542Sralph */
481*18542Sralph 		execit(p->wcmd, p->line);
482*18542Sralph 		exit(0);
483*18542Sralph 	}
484*18542Sralph 	p->wpid = npid;
485*18542Sralph }
486*18542Sralph 
487*18542Sralph #define NARGS	20	/* must be at lease 4 */
488*18542Sralph #define ARGLEN	512	/* total size for all the argument strings */
489*18542Sralph 
490*18542Sralph execit(s, arg)
491*18542Sralph 	char *s;
492*18542Sralph 	char *arg;	/* last argument on line */
493*18542Sralph {
494*18542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
495*18542Sralph 	register char *sp = s;
496*18542Sralph 	register char *ap = args;
497*18542Sralph 	register char c;
498*18542Sralph 	register int i;
499*18542Sralph 
500*18542Sralph 	/*
501*18542Sralph 	 * First we have to set up the argument vector.
502*18542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
503*18542Sralph 	 */
504*18542Sralph 	for (i = 1; i < NARGS - 2; i++) {
505*18542Sralph 		argv[i] = ap;
506*18542Sralph 		for (EVER) {
507*18542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
508*18542Sralph 				*ap = '\0';
509*18542Sralph 				goto done;
510*18542Sralph 			}
511*18542Sralph 			if (c == ' ') {
512*18542Sralph 				*ap++ = '\0';
513*18542Sralph 				while (*sp == ' ')
514*18542Sralph 					sp++;
515*18542Sralph 				if (*sp == '\0')
516*18542Sralph 					goto done;
517*18542Sralph 				break;
518*18542Sralph 			}
519*18542Sralph 			*ap++ = c;
520*18542Sralph 		}
521*18542Sralph 	}
522*18542Sralph done:
523*18542Sralph 	argv[0] = argv[1];
524*18542Sralph 	argv[1] = "-";
525*18542Sralph 	argv[i+1] = arg;
526*18542Sralph 	argv[i+2] = 0;
527*18542Sralph 	envp[0] = 0;
528*18542Sralph 	execve(argv[0], &argv[1], envp);
529*18542Sralph 	/* report failure of exec */
530*18542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
531*18542Sralph 	closelog();
532*18542Sralph 	sleep(10);	/* prevent failures from eating machine */
533*18542Sralph }
534