xref: /csrg-svn/old/init/init.c (revision 35445)
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*35445Sbostic static char sccsid[] = "@(#)init.c	5.11 (Berkeley) 08/31/88";
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>
1928801Skarels #include <sys/syslog.h>
2023147Sbloom #include <sys/stat.h>
211029Sbill 
221029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
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 
291029Sbill char	shell[]	= "/bin/sh";
301029Sbill char	minus[]	= "-";
311029Sbill char	runc[]	= "/etc/rc";
3223147Sbloom char	utmpf[]	= "/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;
4722181Skarels 	time_t	windtime;
4822181Skarels 	int	windcnt;
4923147Sbloom 	struct	tab *next;
5023147Sbloom } *itab;
511029Sbill 
521029Sbill int	fi;
531029Sbill int	mergflag;
541029Sbill char	tty[20];
551429Sbill jmp_buf	sjbuf, shutpass;
562821Swnj time_t	time0;
571029Sbill 
581029Sbill int	reset();
592821Swnj int	idle();
601029Sbill char	*strcpy(), *strcat();
611029Sbill long	lseek();
621029Sbill 
6318542Sralph struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
6413021Ssam 
6523147Sbloom 
6629836Ssam #if defined(vax) || defined(tahoe)
671029Sbill main()
681029Sbill {
6929836Ssam #if defined(tahoe)
7029836Ssam 	register int r12;		/* make sure r11 gets bootflags */
7129836Ssam #endif
721403Sbill 	register int r11;		/* passed thru from boot */
7313021Ssam #else
749869Spugs main(argc, argv)
759869Spugs 	char **argv;
769869Spugs {
7713021Ssam #endif
781403Sbill 	int howto, oldhowto;
791403Sbill 
802821Swnj 	time0 = time(0);
8129836Ssam #if defined(vax) || defined(tahoe)
821403Sbill 	howto = r11;
8313021Ssam #else
849869Spugs 	if (argc > 1 && argv[1][0] == '-') {
859869Spugs 		char *cp;
869869Spugs 
879869Spugs 		howto = 0;
889869Spugs 		cp = &argv[1][1];
899869Spugs 		while (*cp) switch (*cp++) {
909869Spugs 		case 'a':
919869Spugs 			howto |= RB_ASKNAME;
929869Spugs 			break;
939869Spugs 		case 's':
949869Spugs 			howto |= RB_SINGLE;
959869Spugs 			break;
969869Spugs 		}
979869Spugs 	} else {
989869Spugs 		howto = RB_SINGLE;
999869Spugs 	}
10013021Ssam #endif
10124854Seric 	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
10213021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
1032821Swnj 	signal(SIGTSTP, idle);
1041029Sbill 	signal(SIGSTOP, SIG_IGN);
1051029Sbill 	signal(SIGTTIN, SIG_IGN);
1061029Sbill 	signal(SIGTTOU, SIG_IGN);
10713021Ssam 	(void) setjmp(sjbuf);
10813021Ssam 	for (EVER) {
1091403Sbill 		oldhowto = howto;
1101403Sbill 		howto = RB_SINGLE;
1111429Sbill 		if (setjmp(shutpass) == 0)
1121429Sbill 			shutdown();
1131403Sbill 		if (oldhowto & RB_SINGLE)
1141403Sbill 			single();
1151403Sbill 		if (runcom(oldhowto) == 0)
1161403Sbill 			continue;
1171029Sbill 		merge();
1181029Sbill 		multiple();
1191029Sbill 	}
1201029Sbill }
1211029Sbill 
1221429Sbill int	shutreset();
1231429Sbill 
1241029Sbill shutdown()
1251029Sbill {
1261029Sbill 	register i;
12723147Sbloom 	register struct tab *p, *p1;
1281029Sbill 
12923147Sbloom 	close(creat(utmpf, 0644));
1301029Sbill 	signal(SIGHUP, SIG_IGN);
13123147Sbloom 	for (p = itab; p ; ) {
1321029Sbill 		term(p);
13323147Sbloom 		p1 = p->next;
13423147Sbloom 		free(p);
13523147Sbloom 		p = p1;
1361029Sbill 	}
13723147Sbloom 	itab = (struct tab *)0;
1381429Sbill 	signal(SIGALRM, shutreset);
13928801Skarels 	(void) kill(-1, SIGTERM);	/* one chance to catch it */
14028801Skarels 	sleep(5);
1411429Sbill 	alarm(30);
14213021Ssam 	for (i = 0; i < 5; i++)
1431029Sbill 		kill(-1, SIGKILL);
14413021Ssam 	while (wait((int *)0) != -1)
1451029Sbill 		;
1461029Sbill 	alarm(0);
1471429Sbill 	shutend();
1481429Sbill }
1491429Sbill 
15030516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n";
1511429Sbill 
1521429Sbill shutreset()
1531429Sbill {
1541429Sbill 	int status;
1551429Sbill 
1561429Sbill 	if (fork() == 0) {
1571429Sbill 		int ct = open(ctty, 1);
1581429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1591429Sbill 		sleep(5);
1601429Sbill 		exit(1);
1611429Sbill 	}
1621429Sbill 	sleep(5);
1631429Sbill 	shutend();
1641429Sbill 	longjmp(shutpass, 1);
1651429Sbill }
1661429Sbill 
1671429Sbill shutend()
1681429Sbill {
1692821Swnj 	register i, f;
1701429Sbill 
1712821Swnj 	acct(0);
1721029Sbill 	signal(SIGALRM, SIG_DFL);
17313021Ssam 	for (i = 0; i < 10; i++)
1741029Sbill 		close(i);
17513021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1762821Swnj 	if (f >= 0) {
1772821Swnj 		SCPYN(wtmp.ut_line, "~");
1782821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
17912682Ssam 		SCPYN(wtmp.ut_host, "");
1802821Swnj 		time(&wtmp.ut_time);
1812821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1822821Swnj 		close(f);
1832821Swnj 	}
18413021Ssam 	return (1);
1851029Sbill }
1861029Sbill 
1871029Sbill single()
1881029Sbill {
1891029Sbill 	register pid;
1902821Swnj 	register xpid;
1912821Swnj 	extern	errno;
1921029Sbill 
19313021Ssam 	do {
19413021Ssam 		pid = fork();
19513021Ssam 		if (pid == 0) {
19613021Ssam 			signal(SIGTERM, SIG_DFL);
19713021Ssam 			signal(SIGHUP, SIG_DFL);
19813021Ssam 			signal(SIGALRM, SIG_DFL);
19916452Sroot 			signal(SIGTSTP, SIG_IGN);
20013021Ssam 			(void) open(ctty, O_RDWR);
20113021Ssam 			dup2(0, 1);
20213021Ssam 			dup2(0, 2);
20313021Ssam 			execl(shell, minus, (char *)0);
20430516Sbostic 			perror(shell);
20513021Ssam 			exit(0);
20613021Ssam 		}
20713021Ssam 		while ((xpid = wait((int *)0)) != pid)
20813021Ssam 			if (xpid == -1 && errno == ECHILD)
20913021Ssam 				break;
21013021Ssam 	} while (xpid == -1);
2111029Sbill }
2121029Sbill 
2131403Sbill runcom(oldhowto)
2141403Sbill 	int oldhowto;
2151029Sbill {
2161029Sbill 	register pid, f;
2171403Sbill 	int status;
2181029Sbill 
2191029Sbill 	pid = fork();
22013021Ssam 	if (pid == 0) {
22113021Ssam 		(void) open("/", O_RDONLY);
22213021Ssam 		dup2(0, 1);
22313021Ssam 		dup2(0, 2);
2241403Sbill 		if (oldhowto & RB_SINGLE)
2251403Sbill 			execl(shell, shell, runc, (char *)0);
2261403Sbill 		else
2271403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2281403Sbill 		exit(1);
2291029Sbill 	}
23013021Ssam 	while (wait(&status) != pid)
2311029Sbill 		;
23213021Ssam 	if (status)
23313021Ssam 		return (0);
23413021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2351029Sbill 	if (f >= 0) {
2361029Sbill 		SCPYN(wtmp.ut_line, "~");
2371029Sbill 		SCPYN(wtmp.ut_name, "reboot");
23812682Ssam 		SCPYN(wtmp.ut_host, "");
2392821Swnj 		if (time0) {
2402821Swnj 			wtmp.ut_time = time0;
2412821Swnj 			time0 = 0;
2422821Swnj 		} else
2432821Swnj 			time(&wtmp.ut_time);
2441029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2451029Sbill 		close(f);
2461029Sbill 	}
24713021Ssam 	return (1);
2481029Sbill }
2491029Sbill 
25033302Sbostic int merge();
25118542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
25213021Ssam /*
25313021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
25413021Ssam  * which indicate ttys has changed, and SIGTERM's which
25513021Ssam  * are used to shutdown the system.
25613021Ssam  */
2571029Sbill multiple()
2581029Sbill {
2591029Sbill 	register struct tab *p;
2601029Sbill 	register pid;
26123147Sbloom 	int omask;
2621029Sbill 
26313021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
26413021Ssam 	for (EVER) {
2651029Sbill 		pid = wait((int *)0);
26613021Ssam 		if (pid == -1)
2671029Sbill 			return;
26830516Sbostic 		omask = sigblock(sigmask(SIGHUP));
26918542Sralph 		for (ALL) {
27018542Sralph 			/* must restart window system BEFORE emulator */
27118542Sralph 			if (p->wpid == pid || p->wpid == -1)
27218542Sralph 				wstart(p);
27313021Ssam 			if (p->pid == pid || p->pid == -1) {
27418542Sralph 				/* disown the window system */
27518542Sralph 				if (p->wpid)
27618542Sralph 					kill(p->wpid, SIGHUP);
277*35445Sbostic 				cleanutmp(p);
2781029Sbill 				dfork(p);
2791029Sbill 			}
28018542Sralph 		}
28123147Sbloom 		sigsetmask(omask);
2821029Sbill 	}
2831029Sbill }
2841029Sbill 
28513021Ssam /*
28613021Ssam  * Merge current contents of ttys file
28713021Ssam  * into in-core table of configured tty lines.
28813021Ssam  * Entered as signal handler for SIGHUP.
28913021Ssam  */
29013021Ssam #define	FOUND	1
29113021Ssam #define	CHANGE	2
29218542Sralph #define WCHANGE 4
29313021Ssam 
29413021Ssam merge()
29513021Ssam {
29613021Ssam 	register struct tab *p;
29716452Sroot 	register struct ttyent *t;
29823147Sbloom 	register struct tab *p1;
29913021Ssam 
30013021Ssam 	for (ALL)
30113021Ssam 		p->xflag = 0;
30216452Sroot 	setttyent();
30316452Sroot 	while (t = getttyent()) {
30416452Sroot 		if ((t->ty_status & TTY_ON) == 0)
30516452Sroot 			continue;
30613021Ssam 		for (ALL) {
30716452Sroot 			if (SCMPN(p->line, t->ty_name))
30813021Ssam 				continue;
30913021Ssam 			p->xflag |= FOUND;
31016452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
31113021Ssam 				p->xflag |= CHANGE;
31216452Sroot 				SCPYN(p->comn, t->ty_getty);
31313021Ssam 			}
31430516Sbostic 			if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
31518542Sralph 				p->xflag |= WCHANGE|CHANGE;
31618542Sralph 				SCPYN(p->wcmd, t->ty_window);
31718542Sralph 			}
31813021Ssam 			goto contin1;
31913021Ssam 		}
32018542Sralph 
32123147Sbloom 		/*
32223147Sbloom 		 * Make space for a new one
32323147Sbloom 		 */
32423147Sbloom 		p1 = (struct tab *)calloc(1, sizeof(*p1));
32523147Sbloom 		if (!p1) {
32623147Sbloom 			syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
32713021Ssam 			goto contin1;
32813021Ssam 		}
32923147Sbloom 		/*
33023147Sbloom 		 * Put new terminal at the end of the linked list.
33123147Sbloom 		 */
33223147Sbloom 		if (itab) {
33323147Sbloom 			for (p = itab; p->next ; p = p->next)
33423147Sbloom 				;
33523147Sbloom 			p->next = p1;
33623147Sbloom 		} else
33723147Sbloom 			itab = p1;
33823147Sbloom 
33923147Sbloom 		p = p1;
34023147Sbloom 		SCPYN(p->line, t->ty_name);
34123147Sbloom 		p->xflag |= FOUND|CHANGE;
34223147Sbloom 		SCPYN(p->comn, t->ty_getty);
34330516Sbostic 		if (t->ty_window && strcmp(t->ty_window, "") != 0) {
34423147Sbloom 			p->xflag |= WCHANGE;
34523147Sbloom 			SCPYN(p->wcmd, t->ty_window);
34623147Sbloom 		}
34713021Ssam 	contin1:
34813021Ssam 		;
34913021Ssam 	}
35016452Sroot 	endttyent();
35123147Sbloom 	p1 = (struct tab *)0;
35213021Ssam 	for (ALL) {
35313021Ssam 		if ((p->xflag&FOUND) == 0) {
35413021Ssam 			term(p);
35518542Sralph 			wterm(p);
35623147Sbloom 			if (p1)
35723147Sbloom 				p1->next = p->next;
35823147Sbloom 			else
35923147Sbloom 				itab = p->next;
36023147Sbloom 			free(p);
36123147Sbloom 			p = p1 ? p1 : itab;
36223147Sbloom 		} else {
36323147Sbloom 			/* window system should be started first */
36423147Sbloom 			if (p->xflag&WCHANGE) {
36523147Sbloom 				wterm(p);
36623147Sbloom 				wstart(p);
36723147Sbloom 			}
36823147Sbloom 			if (p->xflag&CHANGE) {
36923147Sbloom 				term(p);
37023147Sbloom 				dfork(p);
37123147Sbloom 			}
37213021Ssam 		}
37323147Sbloom 		p1 = p;
37413021Ssam 	}
37513021Ssam }
37613021Ssam 
3771029Sbill term(p)
37813021Ssam 	register struct tab *p;
3791029Sbill {
3801029Sbill 
38113021Ssam 	if (p->pid != 0) {
382*35445Sbostic 		cleanutmp(p);
3831029Sbill 		kill(p->pid, SIGKILL);
3841029Sbill 	}
3851029Sbill 	p->pid = 0;
38618542Sralph 	/* send SIGHUP to get rid of connections */
38718542Sralph 	if (p->wpid > 0)
38818542Sralph 		kill(p->wpid, SIGHUP);
3891029Sbill }
3901029Sbill 
3911029Sbill dfork(p)
39213021Ssam 	struct tab *p;
3931029Sbill {
3941029Sbill 	register pid;
3955971Sroot 	time_t t;
3965971Sroot 	int dowait = 0;
3971029Sbill 
3985971Sroot 	time(&t);
3995971Sroot 	p->gettycnt++;
4005971Sroot 	if ((t - p->gettytime) >= 60) {
4015971Sroot 		p->gettytime = t;
4025971Sroot 		p->gettycnt = 1;
40318542Sralph 	} else if (p->gettycnt >= 5) {
40418542Sralph 		dowait = 1;
40518542Sralph 		p->gettytime = t;
40618542Sralph 		p->gettycnt = 1;
4075971Sroot 	}
4081029Sbill 	pid = fork();
40913021Ssam 	if (pid == 0) {
4106816Ssam 		signal(SIGTERM, SIG_DFL);
4116816Ssam 		signal(SIGHUP, SIG_IGN);
41222181Skarels 		sigsetmask(0);	/* since can be called from masked code */
4135971Sroot 		if (dowait) {
41418542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
41518542Sralph 			closelog();
4165971Sroot 			sleep(30);
4175971Sroot 		}
41818542Sralph 		execit(p->comn, p->line);
4191029Sbill 		exit(0);
4201029Sbill 	}
4211029Sbill 	p->pid = pid;
4221029Sbill }
4231029Sbill 
424*35445Sbostic cleanutmp(p)
42513021Ssam 	register struct tab *p;
4261029Sbill {
427*35445Sbostic 	if (logout(p->line)) {
428*35445Sbostic 		logwtmp(p->line);
42917582Ssam 		/*
43017582Ssam 		 * After a proper login force reset
43117582Ssam 		 * of error detection code in dfork.
43217582Ssam 		 */
43317582Ssam 		p->gettytime = 0;
43422181Skarels 		p->windtime = 0;
4351029Sbill 	}
4361029Sbill }
4371029Sbill 
4381029Sbill reset()
4391029Sbill {
44013021Ssam 
4411029Sbill 	longjmp(sjbuf, 1);
4421029Sbill }
4432821Swnj 
44413021Ssam jmp_buf	idlebuf;
44513021Ssam 
44613021Ssam idlehup()
44713021Ssam {
44813021Ssam 
44913021Ssam 	longjmp(idlebuf, 1);
45013021Ssam }
45113021Ssam 
4522821Swnj idle()
4532821Swnj {
4542821Swnj 	register struct tab *p;
4552821Swnj 	register pid;
4562821Swnj 
45713021Ssam 	signal(SIGHUP, idlehup);
45818542Sralph 	for (EVER) {
45913021Ssam 		if (setjmp(idlebuf))
46013021Ssam 			return;
4612821Swnj 		pid = wait((int *) 0);
46213021Ssam 		if (pid == -1) {
46313021Ssam 			sigpause(0);
46413021Ssam 			continue;
4652821Swnj 		}
46618542Sralph 		for (ALL) {
46718542Sralph 			/* if window system dies, mark it for restart */
46818542Sralph 			if (p->wpid == pid)
46918542Sralph 				p->wpid = -1;
47013021Ssam 			if (p->pid == pid) {
471*35445Sbostic 				cleanutmp(p);
47213021Ssam 				p->pid = -1;
47313021Ssam 			}
47418542Sralph 		}
4752821Swnj 	}
4762821Swnj }
47718542Sralph 
47818542Sralph wterm(p)
47918542Sralph 	register struct tab *p;
48018542Sralph {
48118542Sralph 	if (p->wpid != 0) {
48218542Sralph 		kill(p->wpid, SIGKILL);
48318542Sralph 	}
48418542Sralph 	p->wpid = 0;
48518542Sralph }
48618542Sralph 
48718542Sralph wstart(p)
48818542Sralph 	register struct tab *p;
48918542Sralph {
49022181Skarels 	register pid;
49122181Skarels 	time_t t;
49222181Skarels 	int dowait = 0;
49318542Sralph 
49422181Skarels 	time(&t);
49522181Skarels 	p->windcnt++;
49622181Skarels 	if ((t - p->windtime) >= 60) {
49722181Skarels 		p->windtime = t;
49822181Skarels 		p->windcnt = 1;
49922181Skarels 	} else if (p->windcnt >= 5) {
50022181Skarels 		dowait = 1;
50122181Skarels 		p->windtime = t;
50222181Skarels 		p->windcnt = 1;
50322181Skarels 	}
50422181Skarels 
50522181Skarels 	pid = fork();
50622181Skarels 
50722181Skarels 	if (pid == 0) {
50818542Sralph 		signal(SIGTERM, SIG_DFL);
50922181Skarels 		signal(SIGHUP,  SIG_IGN);
51022181Skarels 		sigsetmask(0);	/* since can be called from masked code */
51122181Skarels 		if (dowait) {
51222181Skarels 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
51322181Skarels 			closelog();
51422181Skarels 			sleep(30);
51522181Skarels 		}
51618542Sralph 		execit(p->wcmd, p->line);
51718542Sralph 		exit(0);
51818542Sralph 	}
51922181Skarels 	p->wpid = pid;
52018542Sralph }
52118542Sralph 
52222181Skarels #define NARGS	20	/* must be at least 4 */
52318542Sralph #define ARGLEN	512	/* total size for all the argument strings */
52418542Sralph 
52518542Sralph execit(s, arg)
52618542Sralph 	char *s;
52718542Sralph 	char *arg;	/* last argument on line */
52818542Sralph {
52918542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
53018542Sralph 	register char *sp = s;
53118542Sralph 	register char *ap = args;
53218542Sralph 	register char c;
53318542Sralph 	register int i;
53418542Sralph 
53518542Sralph 	/*
53618542Sralph 	 * First we have to set up the argument vector.
53718542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
53818542Sralph 	 */
53918542Sralph 	for (i = 1; i < NARGS - 2; i++) {
54018542Sralph 		argv[i] = ap;
54118542Sralph 		for (EVER) {
54218542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
54318542Sralph 				*ap = '\0';
54418542Sralph 				goto done;
54518542Sralph 			}
54618542Sralph 			if (c == ' ') {
54718542Sralph 				*ap++ = '\0';
54818542Sralph 				while (*sp == ' ')
54918542Sralph 					sp++;
55018542Sralph 				if (*sp == '\0')
55118542Sralph 					goto done;
55218542Sralph 				break;
55318542Sralph 			}
55418542Sralph 			*ap++ = c;
55518542Sralph 		}
55618542Sralph 	}
55718542Sralph done:
55818542Sralph 	argv[0] = argv[1];
55918542Sralph 	argv[1] = "-";
56018542Sralph 	argv[i+1] = arg;
56118542Sralph 	argv[i+2] = 0;
56218542Sralph 	envp[0] = 0;
56318542Sralph 	execve(argv[0], &argv[1], envp);
56418542Sralph 	/* report failure of exec */
56518542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
56618542Sralph 	closelog();
56718542Sralph 	sleep(10);	/* prevent failures from eating machine */
56818542Sralph }
569