xref: /csrg-svn/old/init/init.c (revision 24494)
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*24494Skarels static char sccsid[] = "@(#)init.c	5.4 (Berkeley) 08/30/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>
2023147Sbloom #include <sys/stat.h>
211029Sbill 
221029Sbill #define	LINSIZ	sizeof(wtmp.ut_line)
23*24494Skarels #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 
6613021Ssam #ifdef vax
671029Sbill main()
681029Sbill {
691403Sbill 	register int r11;		/* passed thru from boot */
7013021Ssam #else
719869Spugs main(argc, argv)
729869Spugs 	char **argv;
739869Spugs {
7413021Ssam #endif
751403Sbill 	int howto, oldhowto;
761403Sbill 
772821Swnj 	time0 = time(0);
7813021Ssam #ifdef vax
791403Sbill 	howto = r11;
8013021Ssam #else
819869Spugs 	if (argc > 1 && argv[1][0] == '-') {
829869Spugs 		char *cp;
839869Spugs 
849869Spugs 		howto = 0;
859869Spugs 		cp = &argv[1][1];
869869Spugs 		while (*cp) switch (*cp++) {
879869Spugs 		case 'a':
889869Spugs 			howto |= RB_ASKNAME;
899869Spugs 			break;
909869Spugs 		case 's':
919869Spugs 			howto |= RB_SINGLE;
929869Spugs 			break;
939869Spugs 		}
949869Spugs 	} else {
959869Spugs 		howto = RB_SINGLE;
969869Spugs 	}
9713021Ssam #endif
9818542Sralph 	openlog("init", LOG_CONS|LOG_ODELAY, 0);
9913021Ssam 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
1002821Swnj 	signal(SIGTSTP, idle);
1011029Sbill 	signal(SIGSTOP, SIG_IGN);
1021029Sbill 	signal(SIGTTIN, SIG_IGN);
1031029Sbill 	signal(SIGTTOU, SIG_IGN);
10413021Ssam 	(void) setjmp(sjbuf);
10513021Ssam 	for (EVER) {
1061403Sbill 		oldhowto = howto;
1071403Sbill 		howto = RB_SINGLE;
1081429Sbill 		if (setjmp(shutpass) == 0)
1091429Sbill 			shutdown();
1101403Sbill 		if (oldhowto & RB_SINGLE)
1111403Sbill 			single();
1121403Sbill 		if (runcom(oldhowto) == 0)
1131403Sbill 			continue;
1141029Sbill 		merge();
1151029Sbill 		multiple();
1161029Sbill 	}
1171029Sbill }
1181029Sbill 
1191429Sbill int	shutreset();
1201429Sbill 
1211029Sbill shutdown()
1221029Sbill {
1231029Sbill 	register i;
12423147Sbloom 	register struct tab *p, *p1;
1251029Sbill 
12623147Sbloom 	close(creat(utmpf, 0644));
1271029Sbill 	signal(SIGHUP, SIG_IGN);
12823147Sbloom 	for (p = itab; p ; ) {
1291029Sbill 		term(p);
13023147Sbloom 		p1 = p->next;
13123147Sbloom 		free(p);
13223147Sbloom 		p = p1;
1331029Sbill 	}
13423147Sbloom 	itab = (struct tab *)0;
1351429Sbill 	signal(SIGALRM, shutreset);
1361429Sbill 	alarm(30);
13713021Ssam 	for (i = 0; i < 5; i++)
1381029Sbill 		kill(-1, SIGKILL);
13913021Ssam 	while (wait((int *)0) != -1)
1401029Sbill 		;
1411029Sbill 	alarm(0);
1421429Sbill 	shutend();
1431429Sbill }
1441429Sbill 
1451429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
1461429Sbill 
1471429Sbill shutreset()
1481429Sbill {
1491429Sbill 	int status;
1501429Sbill 
1511429Sbill 	if (fork() == 0) {
1521429Sbill 		int ct = open(ctty, 1);
1531429Sbill 		write(ct, shutfailm, sizeof (shutfailm));
1541429Sbill 		sleep(5);
1551429Sbill 		exit(1);
1561429Sbill 	}
1571429Sbill 	sleep(5);
1581429Sbill 	shutend();
1591429Sbill 	longjmp(shutpass, 1);
1601429Sbill }
1611429Sbill 
1621429Sbill shutend()
1631429Sbill {
1642821Swnj 	register i, f;
1651429Sbill 
1662821Swnj 	acct(0);
1671029Sbill 	signal(SIGALRM, SIG_DFL);
16813021Ssam 	for (i = 0; i < 10; i++)
1691029Sbill 		close(i);
17013021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
1712821Swnj 	if (f >= 0) {
1722821Swnj 		SCPYN(wtmp.ut_line, "~");
1732821Swnj 		SCPYN(wtmp.ut_name, "shutdown");
17412682Ssam 		SCPYN(wtmp.ut_host, "");
1752821Swnj 		time(&wtmp.ut_time);
1762821Swnj 		write(f, (char *)&wtmp, sizeof(wtmp));
1772821Swnj 		close(f);
1782821Swnj 	}
17913021Ssam 	return (1);
1801029Sbill }
1811029Sbill 
1821029Sbill single()
1831029Sbill {
1841029Sbill 	register pid;
1852821Swnj 	register xpid;
1862821Swnj 	extern	errno;
1871029Sbill 
18813021Ssam 	do {
18913021Ssam 		pid = fork();
19013021Ssam 		if (pid == 0) {
19113021Ssam 			signal(SIGTERM, SIG_DFL);
19213021Ssam 			signal(SIGHUP, SIG_DFL);
19313021Ssam 			signal(SIGALRM, SIG_DFL);
19416452Sroot 			signal(SIGTSTP, SIG_IGN);
19513021Ssam 			(void) open(ctty, O_RDWR);
19613021Ssam 			dup2(0, 1);
19713021Ssam 			dup2(0, 2);
19813021Ssam 			execl(shell, minus, (char *)0);
19913021Ssam 			exit(0);
20013021Ssam 		}
20113021Ssam 		while ((xpid = wait((int *)0)) != pid)
20213021Ssam 			if (xpid == -1 && errno == ECHILD)
20313021Ssam 				break;
20413021Ssam 	} while (xpid == -1);
2051029Sbill }
2061029Sbill 
2071403Sbill runcom(oldhowto)
2081403Sbill 	int oldhowto;
2091029Sbill {
2101029Sbill 	register pid, f;
2111403Sbill 	int status;
2121029Sbill 
2131029Sbill 	pid = fork();
21413021Ssam 	if (pid == 0) {
21513021Ssam 		(void) open("/", O_RDONLY);
21613021Ssam 		dup2(0, 1);
21713021Ssam 		dup2(0, 2);
2181403Sbill 		if (oldhowto & RB_SINGLE)
2191403Sbill 			execl(shell, shell, runc, (char *)0);
2201403Sbill 		else
2211403Sbill 			execl(shell, shell, runc, "autoboot", (char *)0);
2221403Sbill 		exit(1);
2231029Sbill 	}
22413021Ssam 	while (wait(&status) != pid)
2251029Sbill 		;
22613021Ssam 	if (status)
22713021Ssam 		return (0);
22813021Ssam 	f = open(wtmpf, O_WRONLY|O_APPEND);
2291029Sbill 	if (f >= 0) {
2301029Sbill 		SCPYN(wtmp.ut_line, "~");
2311029Sbill 		SCPYN(wtmp.ut_name, "reboot");
23212682Ssam 		SCPYN(wtmp.ut_host, "");
2332821Swnj 		if (time0) {
2342821Swnj 			wtmp.ut_time = time0;
2352821Swnj 			time0 = 0;
2362821Swnj 		} else
2372821Swnj 			time(&wtmp.ut_time);
2381029Sbill 		write(f, (char *)&wtmp, sizeof(wtmp));
2391029Sbill 		close(f);
2401029Sbill 	}
24113021Ssam 	return (1);
2421029Sbill }
2431029Sbill 
24418542Sralph struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
24513021Ssam /*
24613021Ssam  * Multi-user.  Listen for users leaving, SIGHUP's
24713021Ssam  * which indicate ttys has changed, and SIGTERM's which
24813021Ssam  * are used to shutdown the system.
24913021Ssam  */
2501029Sbill multiple()
2511029Sbill {
2521029Sbill 	register struct tab *p;
2531029Sbill 	register pid;
25423147Sbloom 	int omask;
2551029Sbill 
25613021Ssam 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
25713021Ssam 	for (EVER) {
2581029Sbill 		pid = wait((int *)0);
25913021Ssam 		if (pid == -1)
2601029Sbill 			return;
26123147Sbloom 		omask = sigblock(SIGHUP);
26218542Sralph 		for (ALL) {
26318542Sralph 			/* must restart window system BEFORE emulator */
26418542Sralph 			if (p->wpid == pid || p->wpid == -1)
26518542Sralph 				wstart(p);
26613021Ssam 			if (p->pid == pid || p->pid == -1) {
26718542Sralph 				/* disown the window system */
26818542Sralph 				if (p->wpid)
26918542Sralph 					kill(p->wpid, SIGHUP);
2701029Sbill 				rmut(p);
2711029Sbill 				dfork(p);
2721029Sbill 			}
27318542Sralph 		}
27423147Sbloom 		sigsetmask(omask);
2751029Sbill 	}
2761029Sbill }
2771029Sbill 
27813021Ssam /*
27913021Ssam  * Merge current contents of ttys file
28013021Ssam  * into in-core table of configured tty lines.
28113021Ssam  * Entered as signal handler for SIGHUP.
28213021Ssam  */
28313021Ssam #define	FOUND	1
28413021Ssam #define	CHANGE	2
28518542Sralph #define WCHANGE 4
28613021Ssam 
28713021Ssam merge()
28813021Ssam {
28913021Ssam 	register struct tab *p;
29016452Sroot 	register struct ttyent *t;
29123147Sbloom 	register struct tab *p1;
29213021Ssam 
29313021Ssam 	for (ALL)
29413021Ssam 		p->xflag = 0;
29516452Sroot 	setttyent();
29616452Sroot 	while (t = getttyent()) {
29716452Sroot 		if ((t->ty_status & TTY_ON) == 0)
29816452Sroot 			continue;
29913021Ssam 		for (ALL) {
30016452Sroot 			if (SCMPN(p->line, t->ty_name))
30113021Ssam 				continue;
30213021Ssam 			p->xflag |= FOUND;
30316452Sroot 			if (SCMPN(p->comn, t->ty_getty)) {
30413021Ssam 				p->xflag |= CHANGE;
30516452Sroot 				SCPYN(p->comn, t->ty_getty);
30613021Ssam 			}
30718542Sralph 			if (SCMPN(p->wcmd, t->ty_window)) {
30818542Sralph 				p->xflag |= WCHANGE|CHANGE;
30918542Sralph 				SCPYN(p->wcmd, t->ty_window);
31018542Sralph 			}
31113021Ssam 			goto contin1;
31213021Ssam 		}
31318542Sralph 
31423147Sbloom 		/*
31523147Sbloom 		 * Make space for a new one
31623147Sbloom 		 */
31723147Sbloom 		p1 = (struct tab *)calloc(1, sizeof(*p1));
31823147Sbloom 		if (!p1) {
31923147Sbloom 			syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
32013021Ssam 			goto contin1;
32113021Ssam 		}
32223147Sbloom 		/*
32323147Sbloom 		 * Put new terminal at the end of the linked list.
32423147Sbloom 		 */
32523147Sbloom 		if (itab) {
32623147Sbloom 			for (p = itab; p->next ; p = p->next)
32723147Sbloom 				;
32823147Sbloom 			p->next = p1;
32923147Sbloom 		} else
33023147Sbloom 			itab = p1;
33123147Sbloom 
33223147Sbloom 		p = p1;
33323147Sbloom 		SCPYN(p->line, t->ty_name);
33423147Sbloom 		p->xflag |= FOUND|CHANGE;
33523147Sbloom 		SCPYN(p->comn, t->ty_getty);
33623147Sbloom 		if (strcmp(t->ty_window, "") != 0) {
33723147Sbloom 			p->xflag |= WCHANGE;
33823147Sbloom 			SCPYN(p->wcmd, t->ty_window);
33923147Sbloom 		}
34013021Ssam 	contin1:
34113021Ssam 		;
34213021Ssam 	}
34316452Sroot 	endttyent();
34423147Sbloom 	p1 = (struct tab *)0;
34513021Ssam 	for (ALL) {
34613021Ssam 		if ((p->xflag&FOUND) == 0) {
34713021Ssam 			term(p);
34818542Sralph 			wterm(p);
34923147Sbloom 			if (p1)
35023147Sbloom 				p1->next = p->next;
35123147Sbloom 			else
35223147Sbloom 				itab = p->next;
35323147Sbloom 			free(p);
35423147Sbloom 			p = p1 ? p1 : itab;
35523147Sbloom 		} else {
35623147Sbloom 			/* window system should be started first */
35723147Sbloom 			if (p->xflag&WCHANGE) {
35823147Sbloom 				wterm(p);
35923147Sbloom 				wstart(p);
36023147Sbloom 			}
36123147Sbloom 			if (p->xflag&CHANGE) {
36223147Sbloom 				term(p);
36323147Sbloom 				dfork(p);
36423147Sbloom 			}
36513021Ssam 		}
36623147Sbloom 		p1 = p;
36713021Ssam 	}
36813021Ssam }
36913021Ssam 
3701029Sbill term(p)
37113021Ssam 	register struct tab *p;
3721029Sbill {
3731029Sbill 
37413021Ssam 	if (p->pid != 0) {
3751029Sbill 		rmut(p);
3761029Sbill 		kill(p->pid, SIGKILL);
3771029Sbill 	}
3781029Sbill 	p->pid = 0;
37918542Sralph 	/* send SIGHUP to get rid of connections */
38018542Sralph 	if (p->wpid > 0)
38118542Sralph 		kill(p->wpid, SIGHUP);
3821029Sbill }
3831029Sbill 
3846816Ssam #include <sys/ioctl.h>
3856816Ssam 
3861029Sbill dfork(p)
38713021Ssam 	struct tab *p;
3881029Sbill {
3891029Sbill 	register pid;
3905971Sroot 	time_t t;
3915971Sroot 	int dowait = 0;
3921029Sbill 
3935971Sroot 	time(&t);
3945971Sroot 	p->gettycnt++;
3955971Sroot 	if ((t - p->gettytime) >= 60) {
3965971Sroot 		p->gettytime = t;
3975971Sroot 		p->gettycnt = 1;
39818542Sralph 	} else if (p->gettycnt >= 5) {
39918542Sralph 		dowait = 1;
40018542Sralph 		p->gettytime = t;
40118542Sralph 		p->gettycnt = 1;
4025971Sroot 	}
4031029Sbill 	pid = fork();
40413021Ssam 	if (pid == 0) {
4056816Ssam 		signal(SIGTERM, SIG_DFL);
4066816Ssam 		signal(SIGHUP, SIG_IGN);
40722181Skarels 		sigsetmask(0);	/* since can be called from masked code */
4085971Sroot 		if (dowait) {
40918542Sralph 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
41018542Sralph 			closelog();
4115971Sroot 			sleep(30);
4125971Sroot 		}
41318542Sralph 		execit(p->comn, p->line);
4141029Sbill 		exit(0);
4151029Sbill 	}
4161029Sbill 	p->pid = pid;
4171029Sbill }
4181029Sbill 
41913021Ssam /*
42013021Ssam  * Remove utmp entry.
42113021Ssam  */
4221029Sbill rmut(p)
42313021Ssam 	register struct tab *p;
4241029Sbill {
4251029Sbill 	register f;
4263608Swnj 	int found = 0;
42723147Sbloom 	static unsigned utmpsize;
42823147Sbloom 	static struct utmp *utmp;
42923147Sbloom 	register struct utmp *u;
43023147Sbloom 	int nutmp;
43123147Sbloom 	struct stat statbf;
4321029Sbill 
43323147Sbloom 	f = open(utmpf, O_RDWR);
43413021Ssam 	if (f >= 0) {
43523147Sbloom 		fstat(f, &statbf);
43623147Sbloom 		if (utmpsize < statbf.st_size) {
43723147Sbloom 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
43823147Sbloom 			if (utmp)
43923147Sbloom 				utmp = (struct utmp *)realloc(utmp, utmpsize);
44023147Sbloom 			else
44123147Sbloom 				utmp = (struct utmp *)malloc(utmpsize);
44223147Sbloom 			if (!utmp)
44323147Sbloom 				syslog(LOG_ERR, "utmp malloc failed");
4441029Sbill 		}
44523147Sbloom 		if (statbf.st_size && utmp) {
44623147Sbloom 			nutmp = read(f, utmp, statbf.st_size);
44723147Sbloom 			nutmp /= sizeof(struct utmp);
44823147Sbloom 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
44923147Sbloom 				if (SCMPN(u->ut_line, p->line) ||
45023147Sbloom 				    u->ut_name[0]==0)
45123147Sbloom 					continue;
45223147Sbloom 				lseek(f, ((long)u)-((long)utmp), L_SET);
45323147Sbloom 				SCPYN(u->ut_name, "");
45423147Sbloom 				SCPYN(u->ut_host, "");
45523147Sbloom 				time(&u->ut_time);
45623147Sbloom 				write(f, (char *)u, sizeof(*u));
45723147Sbloom 				found++;
45823147Sbloom 			}
45923147Sbloom 		}
4601029Sbill 		close(f);
4611029Sbill 	}
4623608Swnj 	if (found) {
46313021Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
4643608Swnj 		if (f >= 0) {
4653608Swnj 			SCPYN(wtmp.ut_line, p->line);
4663608Swnj 			SCPYN(wtmp.ut_name, "");
46712682Ssam 			SCPYN(wtmp.ut_host, "");
4683608Swnj 			time(&wtmp.ut_time);
4693608Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4703608Swnj 			close(f);
4713608Swnj 		}
47217582Ssam 		/*
47317582Ssam 		 * After a proper login force reset
47417582Ssam 		 * of error detection code in dfork.
47517582Ssam 		 */
47617582Ssam 		p->gettytime = 0;
47722181Skarels 		p->windtime = 0;
4781029Sbill 	}
4791029Sbill }
4801029Sbill 
4811029Sbill reset()
4821029Sbill {
48313021Ssam 
4841029Sbill 	longjmp(sjbuf, 1);
4851029Sbill }
4862821Swnj 
48713021Ssam jmp_buf	idlebuf;
48813021Ssam 
48913021Ssam idlehup()
49013021Ssam {
49113021Ssam 
49213021Ssam 	longjmp(idlebuf, 1);
49313021Ssam }
49413021Ssam 
4952821Swnj idle()
4962821Swnj {
4972821Swnj 	register struct tab *p;
4982821Swnj 	register pid;
4992821Swnj 
50013021Ssam 	signal(SIGHUP, idlehup);
50118542Sralph 	for (EVER) {
50213021Ssam 		if (setjmp(idlebuf))
50313021Ssam 			return;
5042821Swnj 		pid = wait((int *) 0);
50513021Ssam 		if (pid == -1) {
50613021Ssam 			sigpause(0);
50713021Ssam 			continue;
5082821Swnj 		}
50918542Sralph 		for (ALL) {
51018542Sralph 			/* if window system dies, mark it for restart */
51118542Sralph 			if (p->wpid == pid)
51218542Sralph 				p->wpid = -1;
51313021Ssam 			if (p->pid == pid) {
51413021Ssam 				rmut(p);
51513021Ssam 				p->pid = -1;
51613021Ssam 			}
51718542Sralph 		}
5182821Swnj 	}
5192821Swnj }
52018542Sralph 
52118542Sralph wterm(p)
52218542Sralph 	register struct tab *p;
52318542Sralph {
52418542Sralph 	if (p->wpid != 0) {
52518542Sralph 		kill(p->wpid, SIGKILL);
52618542Sralph 	}
52718542Sralph 	p->wpid = 0;
52818542Sralph }
52918542Sralph 
53018542Sralph wstart(p)
53118542Sralph 	register struct tab *p;
53218542Sralph {
53322181Skarels 	register pid;
53422181Skarels 	time_t t;
53522181Skarels 	int dowait = 0;
53618542Sralph 
53722181Skarels 	time(&t);
53822181Skarels 	p->windcnt++;
53922181Skarels 	if ((t - p->windtime) >= 60) {
54022181Skarels 		p->windtime = t;
54122181Skarels 		p->windcnt = 1;
54222181Skarels 	} else if (p->windcnt >= 5) {
54322181Skarels 		dowait = 1;
54422181Skarels 		p->windtime = t;
54522181Skarels 		p->windcnt = 1;
54622181Skarels 	}
54722181Skarels 
54822181Skarels 	pid = fork();
54922181Skarels 
55022181Skarels 	if (pid == 0) {
55118542Sralph 		signal(SIGTERM, SIG_DFL);
55222181Skarels 		signal(SIGHUP,  SIG_IGN);
55322181Skarels 		sigsetmask(0);	/* since can be called from masked code */
55422181Skarels 		if (dowait) {
55522181Skarels 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
55622181Skarels 			closelog();
55722181Skarels 			sleep(30);
55822181Skarels 		}
55918542Sralph 		execit(p->wcmd, p->line);
56018542Sralph 		exit(0);
56118542Sralph 	}
56222181Skarels 	p->wpid = pid;
56318542Sralph }
56418542Sralph 
56522181Skarels #define NARGS	20	/* must be at least 4 */
56618542Sralph #define ARGLEN	512	/* total size for all the argument strings */
56718542Sralph 
56818542Sralph execit(s, arg)
56918542Sralph 	char *s;
57018542Sralph 	char *arg;	/* last argument on line */
57118542Sralph {
57218542Sralph 	char *argv[NARGS], args[ARGLEN], *envp[1];
57318542Sralph 	register char *sp = s;
57418542Sralph 	register char *ap = args;
57518542Sralph 	register char c;
57618542Sralph 	register int i;
57718542Sralph 
57818542Sralph 	/*
57918542Sralph 	 * First we have to set up the argument vector.
58018542Sralph 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
58118542Sralph 	 */
58218542Sralph 	for (i = 1; i < NARGS - 2; i++) {
58318542Sralph 		argv[i] = ap;
58418542Sralph 		for (EVER) {
58518542Sralph 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
58618542Sralph 				*ap = '\0';
58718542Sralph 				goto done;
58818542Sralph 			}
58918542Sralph 			if (c == ' ') {
59018542Sralph 				*ap++ = '\0';
59118542Sralph 				while (*sp == ' ')
59218542Sralph 					sp++;
59318542Sralph 				if (*sp == '\0')
59418542Sralph 					goto done;
59518542Sralph 				break;
59618542Sralph 			}
59718542Sralph 			*ap++ = c;
59818542Sralph 		}
59918542Sralph 	}
60018542Sralph done:
60118542Sralph 	argv[0] = argv[1];
60218542Sralph 	argv[1] = "-";
60318542Sralph 	argv[i+1] = arg;
60418542Sralph 	argv[i+2] = 0;
60518542Sralph 	envp[0] = 0;
60618542Sralph 	execve(argv[0], &argv[1], envp);
60718542Sralph 	/* report failure of exec */
60818542Sralph 	syslog(LOG_ERR, "%s: %m", argv[0]);
60918542Sralph 	closelog();
61018542Sralph 	sleep(10);	/* prevent failures from eating machine */
61118542Sralph }
612