xref: /csrg-svn/old/init/init.c (revision 47659)
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*47659Skarels static char sccsid[] = "@(#)init.c	5.19 (Berkeley) 03/25/91";
921135Sdist #endif not lint
1012682Ssam 
111029Sbill #include <sys/types.h>
1237284Sbostic #include <sys/file.h>
1337284Sbostic #include <sys/signal.h>
1437284Sbostic #include <sys/reboot.h>
1537284Sbostic #include <sys/syslog.h>
1637284Sbostic #include <sys/stat.h>
1742407Smarc #include <sys/ioctl.h>
181029Sbill #include <setjmp.h>
1935606Sbostic #include <utmp.h>
202821Swnj #include <errno.h>
2116452Sroot #include <ttyent.h>
2237284Sbostic #include "pathnames.h"
231029Sbill 
2424494Skarels #define	CMDSIZ	200	/* max string length for getty or window command*/
2523147Sbloom #define	ALL	p = itab; p ; p = p->next
261029Sbill #define	EVER	;;
271029Sbill #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
281029Sbill #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
291029Sbill 
3037284Sbostic char	shell[]	= _PATH_BSHELL;
311029Sbill char	minus[]	= "-";
3237284Sbostic char	runc[]	= _PATH_RC;
3337284Sbostic char	ctty[]	= _PATH_CONSOLE;
341029Sbill 
351029Sbill struct	tab
361029Sbill {
3735670Sbostic 	char	line[UT_LINESIZE];
3818542Sralph 	char	comn[CMDSIZ];
391029Sbill 	char	xflag;
401029Sbill 	int	pid;
4118542Sralph 	int	wpid;		/* window system pid for SIGHUP	*/
4218542Sralph 	char	wcmd[CMDSIZ];	/* command to start window system process */
435971Sroot 	time_t	gettytime;
445971Sroot 	int	gettycnt;
4522181Skarels 	time_t	windtime;
4622181Skarels 	int	windcnt;
4723147Sbloom 	struct	tab *next;
4823147Sbloom } *itab;
491029Sbill 
501029Sbill int	fi;
511029Sbill int	mergflag;
521029Sbill char	tty[20];
531429Sbill jmp_buf	sjbuf, shutpass;
541029Sbill 
551029Sbill char	*strcpy(), *strcat();
561029Sbill long	lseek();
5742407Smarc void	idle(), merge(), reset();
581029Sbill 
5918542Sralph struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
6013021Ssam 
main(argc,argv)6143633Skarels main(argc, argv)
6243633Skarels 	char **argv;
631029Sbill {
64*47659Skarels 	/* insure proper semantics for setjmp/longjmp */
65*47659Skarels 	static int howto, oldhowto, started = 0;
6629836Ssam #if defined(tahoe)
6729836Ssam 	register int r12;		/* make sure r11 gets bootflags */
6829836Ssam #endif
6943633Skarels #if defined(vax) || defined(tahoe) || defined(hp300)
70*47659Skarels 	/* howto passed in high-order register XXX */
711403Sbill 	register int r11;		/* passed thru from boot */
7242408Smckusick #ifdef __GNUC__
7342408Smckusick #ifdef hp300
7442408Smckusick 	asm("movl d7,%0" : "=rm" (howto));
7542408Smckusick #else
7642408Smckusick 	asm("movl r11,%0" : "=rm" (howto));
7742408Smckusick #endif
7842408Smckusick #else
791403Sbill 	howto = r11;
8043633Skarels #endif /* __GNUC__ */
81*47659Skarels #else  /* vax || tahoe || hp300 */
8243633Skarels 	/* howto passed as argument */
83*47659Skarels 	howto = 0;
84*47659Skarels #endif  /* ! (vax || tahoe || hp300) */
85*47659Skarels 
86*47659Skarels 	/*
87*47659Skarels 	 * We expect a single options argument from the kernel.
88*47659Skarels 	 * If it is present, we ignore anything in registers from above.
89*47659Skarels 	 */
909869Spugs 	if (argc > 1 && argv[1][0] == '-') {
919869Spugs 		char *cp;
929869Spugs 
9342408Smckusick 		howto = 0;
949869Spugs 		cp = &argv[1][1];
959869Spugs 		while (*cp) switch (*cp++) {
96*47659Skarels #ifdef notyet
97*47659Skarels 		case 'f':
98*47659Skarels 			howto |= RB_FASTBOOT;
999869Spugs 			break;
100*47659Skarels #endif
1019869Spugs 		case 's':
1029869Spugs 			howto |= RB_SINGLE;
1039869Spugs 			break;
1049869Spugs 		}
105*47659Skarels 	}
10642407Smarc 	if (getuid() != 0)
10742407Smarc 		exit(1);
10824854Seric 	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
10942407Smarc 	if (setsid() < 0)
11042407Smarc 		syslog(LOG_ERR, "setsid failed (initial) %m");
11113021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
1122821Swnj 	signal(SIGTSTP, idle);
1131029Sbill 	signal(SIGTTIN, SIG_IGN);
1141029Sbill 	signal(SIGTTOU, SIG_IGN);
11513021Ssam 	(void) setjmp(sjbuf);
11643633Skarels 	for (; ; ) {
1171403Sbill 		oldhowto = howto;
1181403Sbill 		howto = RB_SINGLE;
11942407Smarc 		if (started && setjmp(shutpass) == 0)
1201429Sbill 			shutdown();
12142407Smarc 		started = 1;
1221403Sbill 		if (oldhowto & RB_SINGLE)
1231403Sbill 			single();
1241403Sbill 		if (runcom(oldhowto) == 0)
1251403Sbill 			continue;
1261029Sbill 		merge();
1271029Sbill 		multiple();
1281029Sbill 	}
1291029Sbill }
1301029Sbill 
13142407Smarc void	shutreset();
1321429Sbill 
shutdown()1331029Sbill shutdown()
1341029Sbill {
1351029Sbill 	register i;
13623147Sbloom 	register struct tab *p, *p1;
1371029Sbill 
1381029Sbill 	signal(SIGHUP, SIG_IGN);
13923147Sbloom 	for (p = itab; p ; ) {
1401029Sbill 		term(p);
14123147Sbloom 		p1 = p->next;
14223147Sbloom 		free(p);
14323147Sbloom 		p = p1;
1441029Sbill 	}
14523147Sbloom 	itab = (struct tab *)0;
1461429Sbill 	signal(SIGALRM, shutreset);
14728801Skarels 	(void) kill(-1, SIGTERM);	/* one chance to catch it */
14828801Skarels 	sleep(5);
1491429Sbill 	alarm(30);
15013021Ssam 	for (i = 0; i < 5; i++)
1511029Sbill 		kill(-1, SIGKILL);
15213021Ssam 	while (wait((int *)0) != -1)
1531029Sbill 		;
1541029Sbill 	alarm(0);
1551429Sbill 	shutend();
1561429Sbill }
1571429Sbill 
15842407Smarc char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n";
1591429Sbill 
16042407Smarc void
shutreset()1611429Sbill shutreset()
1621429Sbill {
1631429Sbill 	int status;
1641429Sbill 
1651429Sbill 	if (fork() == 0) {
1661429Sbill 		int ct = open(ctty, 1);
1671429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1681429Sbill 		sleep(5);
1691429Sbill 		exit(1);
1701429Sbill 	}
1711429Sbill 	sleep(5);
1721429Sbill 	shutend();
1731429Sbill 	longjmp(shutpass, 1);
1741429Sbill }
1751429Sbill 
shutend()1761429Sbill shutend()
1771429Sbill {
17842408Smckusick 	register i;
1791429Sbill 
1802821Swnj 	acct(0);
1811029Sbill 	signal(SIGALRM, SIG_DFL);
18213021Ssam 	for (i = 0; i < 10; i++)
1831029Sbill 		close(i);
18435606Sbostic 	logwtmp("~", "shutdown", "");
1851029Sbill }
1861029Sbill 
single()1871029Sbill single()
1881029Sbill {
1891029Sbill 	register pid;
1902821Swnj 	register xpid;
19143633Skarels 	int fd;
19235606Sbostic 	extern int errno;
1931029Sbill 
19413021Ssam 	do {
19513021Ssam 		pid = fork();
19613021Ssam 		if (pid == 0) {
19713021Ssam 			signal(SIGTERM, SIG_DFL);
19813021Ssam 			signal(SIGHUP, SIG_DFL);
19913021Ssam 			signal(SIGALRM, SIG_DFL);
20016452Sroot 			signal(SIGTSTP, SIG_IGN);
20142407Smarc 			if (setsid() < 0)
20242407Smarc 				syslog(LOG_ERR, "setsid failed (single): %m");
20343633Skarels 			(void) revoke(ctty);
20443633Skarels 			if ((fd = open(ctty, O_RDWR)) < 0) {
20543633Skarels 				syslog(LOG_ERR, "open %s: %m", ctty);
20643633Skarels 				exit(1);
20743633Skarels 			}
20843633Skarels 			if (ioctl(fd, TIOCSCTTY, 0) < 0)
20942407Smarc 				syslog(LOG_ERR, "TIOCSCTTY failed: %m");
21043633Skarels 			dup2(fd, 0);
21143633Skarels 			dup2(fd, 1);
21243633Skarels 			dup2(fd, 2);
21343633Skarels 			if (fd > 2)
21443633Skarels 				close(fd);
21513021Ssam 			execl(shell, minus, (char *)0);
21630516Sbostic 			perror(shell);
21713021Ssam 			exit(0);
21813021Ssam 		}
21913021Ssam 		while ((xpid = wait((int *)0)) != pid)
22013021Ssam 			if (xpid == -1 && errno == ECHILD)
22113021Ssam 				break;
22213021Ssam 	} while (xpid == -1);
2231029Sbill }
2241029Sbill 
runcom(oldhowto)2251403Sbill runcom(oldhowto)
2261403Sbill 	int oldhowto;
2271029Sbill {
22842408Smckusick 	register pid;
22944284Skarels 	int fd, status;
2301029Sbill 
2311029Sbill 	pid = fork();
23213021Ssam 	if (pid == 0) {
23344284Skarels 		signal(SIGTSTP, SIG_IGN);
23444284Skarels 		signal(SIGHUP, SIG_IGN);
23544284Skarels 		if ((fd = open(ctty, O_RDWR)) < 0)
23644284Skarels 			syslog(LOG_ERR, "open %s: %m", ctty);
23744284Skarels 		else {
23844284Skarels 			dup2(fd, 0);
23944284Skarels 			dup2(fd, 1);
24044284Skarels 			dup2(fd, 2);
24144284Skarels 			if (fd > 2)
24244284Skarels 				close(fd);
24344284Skarels 		}
24442407Smarc 		if (setsid() < 0)
24542407Smarc 			syslog(LOG_ERR, "setsid failed (runcom) %m");
24642407Smarc 		if (ioctl(0, TIOCSCTTY, 0) < 0)
24742407Smarc 			syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m");
2481403Sbill 		if (oldhowto & RB_SINGLE)
2491403Sbill 			execl(shell, shell, runc, (char *)0);
2501403Sbill 		else
2511403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2521403Sbill 		exit(1);
2531029Sbill 	}
25413021Ssam 	while (wait(&status) != pid)
2551029Sbill 		;
25613021Ssam 	if (status)
25713021Ssam 		return (0);
25835606Sbostic 	logwtmp("~", "reboot", "");
25913021Ssam 	return (1);
2601029Sbill }
2611029Sbill 
26218542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
26313021Ssam /*
26413021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
26513021Ssam  * which indicate ttys has changed, and SIGTERM's which
26613021Ssam  * are used to shutdown the system.
26713021Ssam  */
multiple()2681029Sbill multiple()
2691029Sbill {
27042407Smarc 	extern int errno;
2711029Sbill 	register struct tab *p;
2721029Sbill 	register pid;
27323147Sbloom 	int omask;
2741029Sbill 
27513021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
27613021Ssam 	for (EVER) {
2771029Sbill 		pid = wait((int *)0);
27842407Smarc /* SHOULD FIX THIS IN THE KERNEL */
27942407Smarc 		if (pid == -1 && errno != EINTR)
2801029Sbill 			return;
28130516Sbostic 		omask = sigblock(sigmask(SIGHUP));
28218542Sralph 		for (ALL) {
28318542Sralph 			/* must restart window system BEFORE emulator */
28418542Sralph 			if (p->wpid == pid || p->wpid == -1)
28518542Sralph 				wstart(p);
28613021Ssam 			if (p->pid == pid || p->pid == -1) {
28718542Sralph 				/* disown the window system */
28818542Sralph 				if (p->wpid)
28918542Sralph 					kill(p->wpid, SIGHUP);
29035445Sbostic 				cleanutmp(p);
2911029Sbill 				dfork(p);
2921029Sbill 			}
29318542Sralph 		}
29423147Sbloom 		sigsetmask(omask);
2951029Sbill 	}
2961029Sbill }
2971029Sbill 
29813021Ssam /*
29913021Ssam  * Merge current contents of ttys file
30013021Ssam  * into in-core table of configured tty lines.
30113021Ssam  * Entered as signal handler for SIGHUP.
30213021Ssam  */
30313021Ssam #define	FOUND	1
30413021Ssam #define	CHANGE	2
30518542Sralph #define WCHANGE 4
30613021Ssam 
30742407Smarc void
merge()30813021Ssam merge()
30913021Ssam {
31013021Ssam 	register struct tab *p;
31116452Sroot 	register struct ttyent *t;
31223147Sbloom 	register struct tab *p1;
31313021Ssam 
31413021Ssam 	for (ALL)
31513021Ssam 		p->xflag = 0;
31616452Sroot 	setttyent();
31716452Sroot 	while (t = getttyent()) {
31816452Sroot 		if ((t->ty_status & TTY_ON) == 0)
31916452Sroot 			continue;
32013021Ssam 		for (ALL) {
32116452Sroot 			if (SCMPN(p->line, t->ty_name))
32213021Ssam 				continue;
32313021Ssam 			p->xflag |= FOUND;
32416452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
32513021Ssam 				p->xflag |= CHANGE;
32616452Sroot 				SCPYN(p->comn, t->ty_getty);
32713021Ssam 			}
32830516Sbostic 			if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
32918542Sralph 				p->xflag |= WCHANGE|CHANGE;
33018542Sralph 				SCPYN(p->wcmd, t->ty_window);
33118542Sralph 			}
33213021Ssam 			goto contin1;
33313021Ssam 		}
33418542Sralph 
33523147Sbloom 		/*
33623147Sbloom 		 * Make space for a new one
33723147Sbloom 		 */
33823147Sbloom 		p1 = (struct tab *)calloc(1, sizeof(*p1));
33923147Sbloom 		if (!p1) {
34023147Sbloom 			syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
34113021Ssam 			goto contin1;
34213021Ssam 		}
34323147Sbloom 		/*
34423147Sbloom 		 * Put new terminal at the end of the linked list.
34523147Sbloom 		 */
34623147Sbloom 		if (itab) {
34723147Sbloom 			for (p = itab; p->next ; p = p->next)
34823147Sbloom 				;
34923147Sbloom 			p->next = p1;
35023147Sbloom 		} else
35123147Sbloom 			itab = p1;
35223147Sbloom 
35323147Sbloom 		p = p1;
35423147Sbloom 		SCPYN(p->line, t->ty_name);
35523147Sbloom 		p->xflag |= FOUND|CHANGE;
35623147Sbloom 		SCPYN(p->comn, t->ty_getty);
35730516Sbostic 		if (t->ty_window && strcmp(t->ty_window, "") != 0) {
35823147Sbloom 			p->xflag |= WCHANGE;
35923147Sbloom 			SCPYN(p->wcmd, t->ty_window);
36023147Sbloom 		}
36113021Ssam 	contin1:
36213021Ssam 		;
36313021Ssam 	}
36416452Sroot 	endttyent();
36523147Sbloom 	p1 = (struct tab *)0;
36613021Ssam 	for (ALL) {
36713021Ssam 		if ((p->xflag&FOUND) == 0) {
36813021Ssam 			term(p);
36918542Sralph 			wterm(p);
37023147Sbloom 			if (p1)
37123147Sbloom 				p1->next = p->next;
37223147Sbloom 			else
37323147Sbloom 				itab = p->next;
37423147Sbloom 			free(p);
37523147Sbloom 			p = p1 ? p1 : itab;
37623147Sbloom 		} else {
37723147Sbloom 			/* window system should be started first */
37823147Sbloom 			if (p->xflag&WCHANGE) {
37923147Sbloom 				wterm(p);
38023147Sbloom 				wstart(p);
38123147Sbloom 			}
38223147Sbloom 			if (p->xflag&CHANGE) {
38323147Sbloom 				term(p);
38423147Sbloom 				dfork(p);
38523147Sbloom 			}
38613021Ssam 		}
38723147Sbloom 		p1 = p;
38813021Ssam 	}
38913021Ssam }
39013021Ssam 
term(p)3911029Sbill term(p)
39213021Ssam 	register struct tab *p;
3931029Sbill {
3941029Sbill 
39513021Ssam 	if (p->pid != 0) {
39635445Sbostic 		cleanutmp(p);
3971029Sbill 		kill(p->pid, SIGKILL);
3981029Sbill 	}
3991029Sbill 	p->pid = 0;
40018542Sralph 	/* send SIGHUP to get rid of connections */
40118542Sralph 	if (p->wpid > 0)
40218542Sralph 		kill(p->wpid, SIGHUP);
4031029Sbill }
4041029Sbill 
4051029Sbill dfork(p)
40613021Ssam 	struct tab *p;
4071029Sbill {
4081029Sbill 	register pid;
4095971Sroot 	time_t t;
4105971Sroot 	int dowait = 0;
4111029Sbill 
4125971Sroot 	time(&t);
4135971Sroot 	p->gettycnt++;
4145971Sroot 	if ((t - p->gettytime) >= 60) {
4155971Sroot 		p->gettytime = t;
4165971Sroot 		p->gettycnt = 1;
41718542Sralph 	} else if (p->gettycnt >= 5) {
41818542Sralph 		dowait = 1;
41918542Sralph 		p->gettytime = t;
42018542Sralph 		p->gettycnt = 1;
4215971Sroot 	}
4221029Sbill 	pid = fork();
42313021Ssam 	if (pid == 0) {
4246816Ssam 		signal(SIGTERM, SIG_DFL);
4256816Ssam 		signal(SIGHUP, SIG_IGN);
42622181Skarels 		sigsetmask(0);	/* since can be called from masked code */
4275971Sroot 		if (dowait) {
42818542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
42918542Sralph 			closelog();
4305971Sroot 			sleep(30);
4315971Sroot 		}
43242407Smarc 		if (setsid() < 0)
43342407Smarc 			syslog(LOG_ERR, "setsid failed(dfork) %m");
43418542Sralph 		execit(p->comn, p->line);
4351029Sbill 		exit(0);
4361029Sbill 	}
4371029Sbill 	p->pid = pid;
4381029Sbill }
4391029Sbill 
cleanutmp(p)44035445Sbostic cleanutmp(p)
44113021Ssam 	register struct tab *p;
4421029Sbill {
44335445Sbostic 	if (logout(p->line)) {
44442407Smarc 		logwtmp(p->line, "", "");
44517582Ssam 		/*
44617582Ssam 		 * After a proper login force reset
44717582Ssam 		 * of error detection code in dfork.
44817582Ssam 		 */
44917582Ssam 		p->gettytime = 0;
45022181Skarels 		p->windtime = 0;
4511029Sbill 	}
4521029Sbill }
4531029Sbill 
45442407Smarc void
reset()4551029Sbill reset()
4561029Sbill {
4571029Sbill 	longjmp(sjbuf, 1);
4581029Sbill }
4592821Swnj 
46013021Ssam jmp_buf	idlebuf;
46113021Ssam 
46242407Smarc void
idlehup()46313021Ssam idlehup()
46413021Ssam {
46513021Ssam 	longjmp(idlebuf, 1);
46613021Ssam }
46713021Ssam 
46842407Smarc void
idle()4692821Swnj idle()
4702821Swnj {
4712821Swnj 	register struct tab *p;
4722821Swnj 	register pid;
4732821Swnj 
47413021Ssam 	signal(SIGHUP, idlehup);
47518542Sralph 	for (EVER) {
47613021Ssam 		if (setjmp(idlebuf))
47713021Ssam 			return;
4782821Swnj 		pid = wait((int *) 0);
47913021Ssam 		if (pid == -1) {
48013021Ssam 			sigpause(0);
48113021Ssam 			continue;
4822821Swnj 		}
48318542Sralph 		for (ALL) {
48418542Sralph 			/* if window system dies, mark it for restart */
48518542Sralph 			if (p->wpid == pid)
48618542Sralph 				p->wpid = -1;
48713021Ssam 			if (p->pid == pid) {
48835445Sbostic 				cleanutmp(p);
48913021Ssam 				p->pid = -1;
49013021Ssam 			}
49118542Sralph 		}
4922821Swnj 	}
4932821Swnj }
49418542Sralph 
wterm(p)49518542Sralph wterm(p)
49618542Sralph 	register struct tab *p;
49718542Sralph {
49818542Sralph 	if (p->wpid != 0) {
49918542Sralph 		kill(p->wpid, SIGKILL);
50018542Sralph 	}
50118542Sralph 	p->wpid = 0;
50218542Sralph }
50318542Sralph 
wstart(p)50418542Sralph wstart(p)
50518542Sralph 	register struct tab *p;
50618542Sralph {
50722181Skarels 	register pid;
50822181Skarels 	time_t t;
50922181Skarels 	int dowait = 0;
51018542Sralph 
51122181Skarels 	time(&t);
51222181Skarels 	p->windcnt++;
51322181Skarels 	if ((t - p->windtime) >= 60) {
51422181Skarels 		p->windtime = t;
51522181Skarels 		p->windcnt = 1;
51622181Skarels 	} else if (p->windcnt >= 5) {
51722181Skarels 		dowait = 1;
51822181Skarels 		p->windtime = t;
51922181Skarels 		p->windcnt = 1;
52022181Skarels 	}
52122181Skarels 
52222181Skarels 	pid = fork();
52322181Skarels 
52422181Skarels 	if (pid == 0) {
52518542Sralph 		signal(SIGTERM, SIG_DFL);
52622181Skarels 		signal(SIGHUP,  SIG_IGN);
52722181Skarels 		sigsetmask(0);	/* since can be called from masked code */
52822181Skarels 		if (dowait) {
52922181Skarels 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
53022181Skarels 			closelog();
53122181Skarels 			sleep(30);
53222181Skarels 		}
53342407Smarc 		if (setsid() < 0)
53442407Smarc 			syslog(LOG_ERR, "setsid failed (window) %m");
53518542Sralph 		execit(p->wcmd, p->line);
53618542Sralph 		exit(0);
53718542Sralph 	}
53822181Skarels 	p->wpid = pid;
53918542Sralph }
54018542Sralph 
54122181Skarels #define NARGS	20	/* must be at least 4 */
54218542Sralph #define ARGLEN	512	/* total size for all the argument strings */
54318542Sralph 
execit(s,arg)54418542Sralph execit(s, arg)
54518542Sralph 	char *s;
54618542Sralph 	char *arg;	/* last argument on line */
54718542Sralph {
54818542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
54918542Sralph 	register char *sp = s;
55018542Sralph 	register char *ap = args;
55118542Sralph 	register char c;
55218542Sralph 	register int i;
55318542Sralph 
55418542Sralph 	/*
55518542Sralph 	 * First we have to set up the argument vector.
55618542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
55718542Sralph 	 */
55818542Sralph 	for (i = 1; i < NARGS - 2; i++) {
55918542Sralph 		argv[i] = ap;
56018542Sralph 		for (EVER) {
56118542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
56218542Sralph 				*ap = '\0';
56318542Sralph 				goto done;
56418542Sralph 			}
56518542Sralph 			if (c == ' ') {
56618542Sralph 				*ap++ = '\0';
56718542Sralph 				while (*sp == ' ')
56818542Sralph 					sp++;
56918542Sralph 				if (*sp == '\0')
57018542Sralph 					goto done;
57118542Sralph 				break;
57218542Sralph 			}
57318542Sralph 			*ap++ = c;
57418542Sralph 		}
57518542Sralph 	}
57618542Sralph done:
57718542Sralph 	argv[0] = argv[1];
57818542Sralph 	argv[1] = "-";
57918542Sralph 	argv[i+1] = arg;
58018542Sralph 	argv[i+2] = 0;
58118542Sralph 	envp[0] = 0;
58218542Sralph 	execve(argv[0], &argv[1], envp);
58318542Sralph 	/* report failure of exec */
58418542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
58518542Sralph 	closelog();
58618542Sralph 	sleep(10);	/* prevent failures from eating machine */
58718542Sralph }
588