xref: /csrg-svn/old/init/init.c (revision 13021)
112682Ssam #ifndef lint
2*13021Ssam static	char *sccsid = "@(#)init.c	4.12 (Berkeley) 06/12/83";
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>
11*13021Ssam #include <sys/file.h>
121029Sbill 
131029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
141029Sbill #define	TABSIZ	100
151029Sbill #define	ALL	p = &itab[0]; p < &itab[TABSIZ]; p++
161029Sbill #define	EVER	;;
171029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
181029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
19*13021Ssam #define	mask(s)	(1 << ((s)-1))
201029Sbill 
211029Sbill char	shell[]	= "/bin/sh";
221403Sbill char	getty[]	 = "/etc/getty";
231029Sbill char	minus[]	= "-";
241029Sbill char	runc[]	= "/etc/rc";
251029Sbill char	ifile[]	= "/etc/ttys";
261029Sbill char	utmp[]	= "/etc/utmp";
271029Sbill char	wtmpf[]	= "/usr/adm/wtmp";
281029Sbill char	ctty[]	= "/dev/console";
291029Sbill char	dev[]	= "/dev/";
301029Sbill 
311029Sbill struct utmp wtmp;
321029Sbill struct
331029Sbill {
341029Sbill 	char	line[LINSIZ];
351029Sbill 	char	comn;
361029Sbill 	char	flag;
371029Sbill } line;
381029Sbill struct	tab
391029Sbill {
401029Sbill 	char	line[LINSIZ];
411029Sbill 	char	comn;
421029Sbill 	char	xflag;
431029Sbill 	int	pid;
445971Sroot 	time_t	gettytime;
455971Sroot 	int	gettycnt;
461029Sbill } itab[TABSIZ];
471029Sbill 
481029Sbill int	fi;
491029Sbill int	mergflag;
501029Sbill char	tty[20];
511429Sbill jmp_buf	sjbuf, shutpass;
522821Swnj time_t	time0;
531029Sbill 
541029Sbill int	reset();
552821Swnj int	idle();
561029Sbill char	*strcpy(), *strcat();
571029Sbill long	lseek();
581029Sbill 
59*13021Ssam struct	sigvec rvec = { reset, mask(SIGHUP), 0 };
60*13021Ssam 
61*13021Ssam #ifdef vax
621029Sbill main()
631029Sbill {
641403Sbill 	register int r11;		/* passed thru from boot */
65*13021Ssam #else
669869Spugs main(argc, argv)
679869Spugs 	char **argv;
689869Spugs {
69*13021Ssam #endif
701403Sbill 	int howto, oldhowto;
711403Sbill 
722821Swnj 	time0 = time(0);
73*13021Ssam #ifdef vax
741403Sbill 	howto = r11;
75*13021Ssam #else
769869Spugs 	if (argc > 1 && argv[1][0] == '-') {
779869Spugs 		char *cp;
789869Spugs 
799869Spugs 		howto = 0;
809869Spugs 		cp = &argv[1][1];
819869Spugs 		while (*cp) switch (*cp++) {
829869Spugs 		case 'a':
839869Spugs 			howto |= RB_ASKNAME;
849869Spugs 			break;
859869Spugs 		case 's':
869869Spugs 			howto |= RB_SINGLE;
879869Spugs 			break;
889869Spugs 		}
899869Spugs 	} else {
909869Spugs 		howto = RB_SINGLE;
919869Spugs 	}
92*13021Ssam #endif
93*13021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
942821Swnj 	signal(SIGTSTP, idle);
951029Sbill 	signal(SIGSTOP, SIG_IGN);
961029Sbill 	signal(SIGTTIN, SIG_IGN);
971029Sbill 	signal(SIGTTOU, SIG_IGN);
98*13021Ssam 	(void) setjmp(sjbuf);
99*13021Ssam 	for (EVER) {
1001403Sbill 		oldhowto = howto;
1011403Sbill 		howto = RB_SINGLE;
1021429Sbill 		if (setjmp(shutpass) == 0)
1031429Sbill 			shutdown();
1041403Sbill 		if (oldhowto & RB_SINGLE)
1051403Sbill 			single();
1061403Sbill 		if (runcom(oldhowto) == 0)
1071403Sbill 			continue;
1081029Sbill 		merge();
1091029Sbill 		multiple();
1101029Sbill 	}
1111029Sbill }
1121029Sbill 
1131429Sbill int	shutreset();
1141429Sbill 
1151029Sbill shutdown()
1161029Sbill {
1171029Sbill 	register i;
1181029Sbill 	register struct tab *p;
1191029Sbill 
1201029Sbill 	close(creat(utmp, 0644));
1211029Sbill 	signal(SIGHUP, SIG_IGN);
122*13021Ssam 	for (ALL) {
1231029Sbill 		term(p);
1241029Sbill 		p->line[0] = 0;
1251029Sbill 	}
1261429Sbill 	signal(SIGALRM, shutreset);
1271429Sbill 	alarm(30);
128*13021Ssam 	for (i = 0; i < 5; i++)
1291029Sbill 		kill(-1, SIGKILL);
130*13021Ssam 	while (wait((int *)0) != -1)
1311029Sbill 		;
1321029Sbill 	alarm(0);
1331429Sbill 	shutend();
1341429Sbill }
1351429Sbill 
1361429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
1371429Sbill 
1381429Sbill shutreset()
1391429Sbill {
1401429Sbill 	int status;
1411429Sbill 
1421429Sbill 	if (fork() == 0) {
1431429Sbill 		int ct = open(ctty, 1);
1441429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1451429Sbill 		sleep(5);
1461429Sbill 		exit(1);
1471429Sbill 	}
1481429Sbill 	sleep(5);
1491429Sbill 	shutend();
1501429Sbill 	longjmp(shutpass, 1);
1511429Sbill }
1521429Sbill 
1531429Sbill shutend()
1541429Sbill {
1552821Swnj 	register i, f;
1561429Sbill 
1572821Swnj 	acct(0);
1581029Sbill 	signal(SIGALRM, SIG_DFL);
159*13021Ssam 	for (i = 0; i < 10; i++)
1601029Sbill 		close(i);
161*13021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1622821Swnj 	if (f >= 0) {
1632821Swnj 		SCPYN(wtmp.ut_line, "~");
1642821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
16512682Ssam 		SCPYN(wtmp.ut_host, "");
1662821Swnj 		time(&wtmp.ut_time);
1672821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1682821Swnj 		close(f);
1692821Swnj 	}
170*13021Ssam 	return (1);
1711029Sbill }
1721029Sbill 
1731029Sbill single()
1741029Sbill {
1751029Sbill 	register pid;
1762821Swnj 	register xpid;
1772821Swnj 	extern	errno;
1781029Sbill 
179*13021Ssam 	do {
180*13021Ssam 		pid = fork();
181*13021Ssam 		if (pid == 0) {
182*13021Ssam 			signal(SIGTERM, SIG_DFL);
183*13021Ssam 			signal(SIGHUP, SIG_DFL);
184*13021Ssam 			signal(SIGALRM, SIG_DFL);
185*13021Ssam 			(void) open(ctty, O_RDWR);
186*13021Ssam 			dup2(0, 1);
187*13021Ssam 			dup2(0, 2);
188*13021Ssam 			execl(shell, minus, (char *)0);
189*13021Ssam 			exit(0);
190*13021Ssam 		}
191*13021Ssam 		while ((xpid = wait((int *)0)) != pid)
192*13021Ssam 			if (xpid == -1 && errno == ECHILD)
193*13021Ssam 				break;
194*13021Ssam 	} while (xpid == -1);
1951029Sbill }
1961029Sbill 
1971403Sbill runcom(oldhowto)
1981403Sbill 	int oldhowto;
1991029Sbill {
2001029Sbill 	register pid, f;
2011403Sbill 	int status;
2021029Sbill 
2031029Sbill 	pid = fork();
204*13021Ssam 	if (pid == 0) {
205*13021Ssam 		(void) open("/", O_RDONLY);
206*13021Ssam 		dup2(0, 1);
207*13021Ssam 		dup2(0, 2);
2081403Sbill 		if (oldhowto & RB_SINGLE)
2091403Sbill 			execl(shell, shell, runc, (char *)0);
2101403Sbill 		else
2111403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2121403Sbill 		exit(1);
2131029Sbill 	}
214*13021Ssam 	while (wait(&status) != pid)
2151029Sbill 		;
216*13021Ssam 	if (status)
217*13021Ssam 		return (0);
218*13021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2191029Sbill 	if (f >= 0) {
2201029Sbill 		SCPYN(wtmp.ut_line, "~");
2211029Sbill 		SCPYN(wtmp.ut_name, "reboot");
22212682Ssam 		SCPYN(wtmp.ut_host, "");
2232821Swnj 		if (time0) {
2242821Swnj 			wtmp.ut_time = time0;
2252821Swnj 			time0 = 0;
2262821Swnj 		} else
2272821Swnj 			time(&wtmp.ut_time);
2281029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2291029Sbill 		close(f);
2301029Sbill 	}
231*13021Ssam 	return (1);
2321029Sbill }
2331029Sbill 
234*13021Ssam struct	sigvec	mvec = { merge, mask(SIGTERM), 0 };
235*13021Ssam /*
236*13021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
237*13021Ssam  * which indicate ttys has changed, and SIGTERM's which
238*13021Ssam  * are used to shutdown the system.
239*13021Ssam  */
2401029Sbill multiple()
2411029Sbill {
2421029Sbill 	register struct tab *p;
2431029Sbill 	register pid;
2441029Sbill 
245*13021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
246*13021Ssam 	for (EVER) {
2471029Sbill 		pid = wait((int *)0);
248*13021Ssam 		if (pid == -1)
2491029Sbill 			return;
250*13021Ssam 		for (ALL)
251*13021Ssam 			if (p->pid == pid || p->pid == -1) {
2521029Sbill 				rmut(p);
2531029Sbill 				dfork(p);
2541029Sbill 			}
2551029Sbill 	}
2561029Sbill }
2571029Sbill 
258*13021Ssam /*
259*13021Ssam  * Merge current contents of ttys file
260*13021Ssam  * into in-core table of configured tty lines.
261*13021Ssam  * Entered as signal handler for SIGHUP.
262*13021Ssam  */
263*13021Ssam #define	FOUND	1
264*13021Ssam #define	CHANGE	2
265*13021Ssam 
266*13021Ssam merge()
267*13021Ssam {
268*13021Ssam 	register struct tab *p;
269*13021Ssam 
270*13021Ssam 	fi = open(ifile, 0);
271*13021Ssam 	if (fi < 0)
272*13021Ssam 		return;
273*13021Ssam 	for (ALL)
274*13021Ssam 		p->xflag = 0;
275*13021Ssam 	while (rline()) {
276*13021Ssam 		for (ALL) {
277*13021Ssam 			if (SCMPN(p->line, line.line))
278*13021Ssam 				continue;
279*13021Ssam 			p->xflag |= FOUND;
280*13021Ssam 			if (line.comn != p->comn) {
281*13021Ssam 				p->xflag |= CHANGE;
282*13021Ssam 				p->comn = line.comn;
283*13021Ssam 			}
284*13021Ssam 			goto contin1;
285*13021Ssam 		}
286*13021Ssam 		for (ALL) {
287*13021Ssam 			if (p->line[0] != 0)
288*13021Ssam 				continue;
289*13021Ssam 			SCPYN(p->line, line.line);
290*13021Ssam 			p->xflag |= FOUND|CHANGE;
291*13021Ssam 			p->comn = line.comn;
292*13021Ssam 			goto contin1;
293*13021Ssam 		}
294*13021Ssam 	contin1:
295*13021Ssam 		;
296*13021Ssam 	}
297*13021Ssam 	close(fi);
298*13021Ssam 	for (ALL) {
299*13021Ssam 		if ((p->xflag&FOUND) == 0) {
300*13021Ssam 			term(p);
301*13021Ssam 			p->line[0] = 0;
302*13021Ssam 		}
303*13021Ssam 		if (p->xflag&CHANGE) {
304*13021Ssam 			term(p);
305*13021Ssam 			dfork(p);
306*13021Ssam 		}
307*13021Ssam 	}
308*13021Ssam }
309*13021Ssam 
3101029Sbill term(p)
311*13021Ssam 	register struct tab *p;
3121029Sbill {
3131029Sbill 
314*13021Ssam 	if (p->pid != 0) {
3151029Sbill 		rmut(p);
3161029Sbill 		kill(p->pid, SIGKILL);
3171029Sbill 	}
3181029Sbill 	p->pid = 0;
3191029Sbill }
3201029Sbill 
3211029Sbill rline()
3221029Sbill {
3231029Sbill 	register c, i;
3241029Sbill 
3251029Sbill loop:
3261029Sbill 	c = get();
327*13021Ssam 	if (c < 0)
3281029Sbill 		return(0);
329*13021Ssam 	if (c == 0)
3301029Sbill 		goto loop;
3311029Sbill 	line.flag = c;
3321029Sbill 	c = get();
333*13021Ssam 	if (c <= 0)
3341029Sbill 		goto loop;
3351029Sbill 	line.comn = c;
3361029Sbill 	SCPYN(line.line, "");
337*13021Ssam 	for (i = 0; i < LINSIZ; i++) {
3381029Sbill 		c = get();
339*13021Ssam 		if (c <= 0)
3401029Sbill 			break;
3411029Sbill 		line.line[i] = c;
3421029Sbill 	}
343*13021Ssam 	while (c > 0)
3441029Sbill 		c = get();
345*13021Ssam 	if (line.line[0] == 0)
3461029Sbill 		goto loop;
347*13021Ssam 	if (line.flag == '0')
3481029Sbill 		goto loop;
3491029Sbill 	strcpy(tty, dev);
3501029Sbill 	strncat(tty, line.line, LINSIZ);
351*13021Ssam 	if (access(tty, 06) < 0)
3521029Sbill 		goto loop;
353*13021Ssam 	return (1);
3541029Sbill }
3551029Sbill 
3561029Sbill get()
3571029Sbill {
3581029Sbill 	char b;
3591029Sbill 
360*13021Ssam 	if (read(fi, &b, 1) != 1)
361*13021Ssam 		return (-1);
362*13021Ssam 	if (b == '\n')
363*13021Ssam 		return (0);
364*13021Ssam 	return (b);
3651029Sbill }
3661029Sbill 
3676816Ssam #include <sys/ioctl.h>
3686816Ssam 
3691029Sbill dfork(p)
370*13021Ssam 	struct tab *p;
3711029Sbill {
3721029Sbill 	register pid;
3735971Sroot 	time_t t;
3745971Sroot 	int dowait = 0;
3759579Spugs 	extern char *sys_errlist[];
3761029Sbill 
3775971Sroot 	time(&t);
3785971Sroot 	p->gettycnt++;
3795971Sroot 	if ((t - p->gettytime) >= 60) {
3805971Sroot 		p->gettytime = t;
3815971Sroot 		p->gettycnt = 1;
3825971Sroot 	} else {
3835971Sroot 		if (p->gettycnt >= 5) {
3845971Sroot 			dowait = 1;
3855971Sroot 			p->gettytime = t;
3865971Sroot 			p->gettycnt = 1;
3875971Sroot 		}
3885971Sroot 	}
3891029Sbill 	pid = fork();
390*13021Ssam 	if (pid == 0) {
3916816Ssam 		int oerrno, f;
3926816Ssam 		extern int errno;
3936816Ssam 
3946816Ssam 		signal(SIGTERM, SIG_DFL);
3956816Ssam 		signal(SIGHUP, SIG_IGN);
3969579Spugs 		strcpy(tty, dev);
3979579Spugs 		strncat(tty, p->line, LINSIZ);
3985971Sroot 		if (dowait) {
399*13021Ssam 			f = open("/dev/console", O_WRONLY);
4005971Sroot 			write(f, "init: ", 6);
4015971Sroot 			write(f, tty, strlen(tty));
4025971Sroot 			write(f, ": getty failing, sleeping\n\r", 27);
4035971Sroot 			close(f);
4045971Sroot 			sleep(30);
405*13021Ssam 			if ((f = open("/dev/tty", O_RDWR)) >= 0) {
4066816Ssam 				ioctl(f, TIOCNOTTY, 0);
4076816Ssam 				close(f);
4086816Ssam 			}
4095971Sroot 		}
4101029Sbill 		chown(tty, 0, 0);
4111029Sbill 		chmod(tty, 0622);
412*13021Ssam 		if (open(tty, O_RDWR) < 0) {
4133608Swnj 			int repcnt = 0;
4143608Swnj 			do {
4156816Ssam 				oerrno = errno;
4163608Swnj 				if (repcnt % 10 == 0) {
417*13021Ssam 					f = open("/dev/console", O_WRONLY);
4183608Swnj 					write(f, "init: ", 6);
4199579Spugs 					write(f, tty, strlen(tty));
4209579Spugs 					write(f, ": ", 2);
4219579Spugs 					write(f, sys_errlist[oerrno],
4229579Spugs 						strlen(sys_errlist[oerrno]));
4239579Spugs 					write(f, "\n", 1);
4243608Swnj 					close(f);
4256816Ssam 					if ((f = open("/dev/tty", 2)) >= 0) {
4266816Ssam 						ioctl(f, TIOCNOTTY, 0);
4276816Ssam 						close(f);
4286816Ssam 					}
4293608Swnj 				}
4303608Swnj 				repcnt++;
4313608Swnj 				sleep(60);
432*13021Ssam 			} while (open(tty, O_RDWR) < 0);
4333608Swnj 			exit(0);	/* have wrong control tty, start over */
4343608Swnj 		}
4351029Sbill 		vhangup();
4361029Sbill 		signal(SIGHUP, SIG_DFL);
437*13021Ssam 		(void) open(tty, O_RDWR);
4381029Sbill 		close(0);
4391029Sbill 		dup(1);
4401029Sbill 		dup(0);
4411029Sbill 		tty[0] = p->comn;
4421029Sbill 		tty[1] = 0;
4431029Sbill 		execl(getty, minus, tty, (char *)0);
4441029Sbill 		exit(0);
4451029Sbill 	}
4461029Sbill 	p->pid = pid;
4471029Sbill }
4481029Sbill 
449*13021Ssam /*
450*13021Ssam  * Remove utmp entry.
451*13021Ssam  */
4521029Sbill rmut(p)
453*13021Ssam 	register struct tab *p;
4541029Sbill {
4551029Sbill 	register f;
4563608Swnj 	int found = 0;
4571029Sbill 
458*13021Ssam 	f = open(utmp, O_RDWR);
459*13021Ssam 	if (f >= 0) {
460*13021Ssam 		while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
4613608Swnj 			if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0)
4621029Sbill 				continue;
4631029Sbill 			lseek(f, -(long)sizeof(wtmp), 1);
4641029Sbill 			SCPYN(wtmp.ut_name, "");
46512682Ssam 			SCPYN(wtmp.ut_host, "");
4661029Sbill 			time(&wtmp.ut_time);
4671029Sbill 			write(f, (char *)&wtmp, sizeof(wtmp));
4683608Swnj 			found++;
4691029Sbill 		}
4701029Sbill 		close(f);
4711029Sbill 	}
4723608Swnj 	if (found) {
473*13021Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
4743608Swnj 		if (f >= 0) {
4753608Swnj 			SCPYN(wtmp.ut_line, p->line);
4763608Swnj 			SCPYN(wtmp.ut_name, "");
47712682Ssam 			SCPYN(wtmp.ut_host, "");
4783608Swnj 			time(&wtmp.ut_time);
4793608Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4803608Swnj 			close(f);
4813608Swnj 		}
4821029Sbill 	}
4831029Sbill }
4841029Sbill 
4851029Sbill reset()
4861029Sbill {
487*13021Ssam 
4881029Sbill 	longjmp(sjbuf, 1);
4891029Sbill }
4902821Swnj 
491*13021Ssam jmp_buf	idlebuf;
492*13021Ssam 
493*13021Ssam idlehup()
494*13021Ssam {
495*13021Ssam 
496*13021Ssam 	longjmp(idlebuf, 1);
497*13021Ssam }
498*13021Ssam 
4992821Swnj idle()
5002821Swnj {
5012821Swnj 	register struct tab *p;
5022821Swnj 	register pid;
5032821Swnj 
504*13021Ssam 	signal(SIGHUP, idlehup);
5052821Swnj 	for (;;) {
506*13021Ssam 		if (setjmp(idlebuf))
507*13021Ssam 			return;
5082821Swnj 		pid = wait((int *) 0);
509*13021Ssam 		if (pid == -1) {
510*13021Ssam 			sigpause(0);
511*13021Ssam 			continue;
5122821Swnj 		}
513*13021Ssam 		for (ALL)
514*13021Ssam 			if (p->pid == pid) {
515*13021Ssam 				rmut(p);
516*13021Ssam 				p->pid = -1;
517*13021Ssam 			}
5182821Swnj 	}
5192821Swnj }
520