xref: /plan9/sys/src/cmd/upas/q/runq.c (revision 39dc14208bd73723190dc96abcf59ed5c10cfd3b)
17dd7cddfSDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include <ctype.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier void	doalldirs(void);
53e12c5d1SDavid du Colombier void	dodir(char*);
63e12c5d1SDavid du Colombier void	dofile(Dir*);
73e12c5d1SDavid du Colombier void	rundir(char*);
83e12c5d1SDavid du Colombier char*	file(char*, char);
93e12c5d1SDavid du Colombier void	warning(char*, void*);
103e12c5d1SDavid du Colombier void	error(char*, void*);
113e12c5d1SDavid du Colombier int	returnmail(char**, char*, char*);
127dd7cddfSDavid du Colombier void	logit(char*, char*, char**);
137dd7cddfSDavid du Colombier void	doload(int);
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier #define HUNK 32
163e12c5d1SDavid du Colombier char	*cmd;
173e12c5d1SDavid du Colombier char	*root;
183e12c5d1SDavid du Colombier int	debug;
197dd7cddfSDavid du Colombier int	giveup = 2*24*60*60;
207dd7cddfSDavid du Colombier int	load;
2114414594SDavid du Colombier int	limit;
22219b2ee8SDavid du Colombier 
23219b2ee8SDavid du Colombier /* the current directory */
24219b2ee8SDavid du Colombier Dir	*dirbuf;
25219b2ee8SDavid du Colombier long	ndirbuf = 0;
26219b2ee8SDavid du Colombier int	nfiles;
277dd7cddfSDavid du Colombier char	*curdir;
28219b2ee8SDavid du Colombier 
297dd7cddfSDavid du Colombier char *runqlog = "runq";
30219b2ee8SDavid du Colombier 
317dd7cddfSDavid du Colombier int	*pidlist;
327dd7cddfSDavid du Colombier char	**badsys;		/* array of recalcitrant systems */
337dd7cddfSDavid du Colombier int	nbad;
347dd7cddfSDavid du Colombier int	npid = 50;
357dd7cddfSDavid du Colombier int	sflag;			/* single thread per directory */
367dd7cddfSDavid du Colombier int	aflag;			/* all directories */
377dd7cddfSDavid du Colombier int	Eflag;			/* ignore E.xxxxxx dates */
3867031067SDavid du Colombier int	Rflag;			/* no giving up, ever */
393e12c5d1SDavid du Colombier 
403e12c5d1SDavid du Colombier void
usage(void)413e12c5d1SDavid du Colombier usage(void)
423e12c5d1SDavid du Colombier {
4314414594SDavid du Colombier 	fprint(2, "usage: runq [-adsE] [-q dir] [-l load] [-t time] [-r nfiles] [-n nprocs] q-root cmd\n");
443e12c5d1SDavid du Colombier 	exits("");
453e12c5d1SDavid du Colombier }
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier void
main(int argc,char ** argv)48219b2ee8SDavid du Colombier main(int argc, char **argv)
493e12c5d1SDavid du Colombier {
507dd7cddfSDavid du Colombier 	char *qdir, *x;
513e12c5d1SDavid du Colombier 
527dd7cddfSDavid du Colombier 	qdir = 0;
533e12c5d1SDavid du Colombier 
54219b2ee8SDavid du Colombier 	ARGBEGIN{
557dd7cddfSDavid du Colombier 	case 'l':
567dd7cddfSDavid du Colombier 		x = ARGF();
577dd7cddfSDavid du Colombier 		if(x == 0)
587dd7cddfSDavid du Colombier 			usage();
597dd7cddfSDavid du Colombier 		load = atoi(x);
607dd7cddfSDavid du Colombier 		if(load < 0)
617dd7cddfSDavid du Colombier 			load = 0;
627dd7cddfSDavid du Colombier 		break;
637dd7cddfSDavid du Colombier 	case 'E':
647dd7cddfSDavid du Colombier 		Eflag++;
657dd7cddfSDavid du Colombier 		break;
6667031067SDavid du Colombier 	case 'R':	/* no giving up -- just leave stuff in the queue */
6767031067SDavid du Colombier 		Rflag++;
6867031067SDavid du Colombier 		break;
693e12c5d1SDavid du Colombier 	case 'a':
707dd7cddfSDavid du Colombier 		aflag++;
713e12c5d1SDavid du Colombier 		break;
723e12c5d1SDavid du Colombier 	case 'd':
73219b2ee8SDavid du Colombier 		debug++;
743e12c5d1SDavid du Colombier 		break;
7514414594SDavid du Colombier 	case 'r':
7614414594SDavid du Colombier 		limit = atoi(ARGF());
7714414594SDavid du Colombier 		break;
787dd7cddfSDavid du Colombier 	case 's':
797dd7cddfSDavid du Colombier 		sflag++;
807dd7cddfSDavid du Colombier 		break;
81219b2ee8SDavid du Colombier 	case 't':
82219b2ee8SDavid du Colombier 		giveup = 60*60*atoi(ARGF());
83219b2ee8SDavid du Colombier 		break;
847dd7cddfSDavid du Colombier 	case 'q':
857dd7cddfSDavid du Colombier 		qdir = ARGF();
867dd7cddfSDavid du Colombier 		if(qdir == 0)
877dd7cddfSDavid du Colombier 			usage();
887dd7cddfSDavid du Colombier 		break;
897dd7cddfSDavid du Colombier 	case 'n':
907dd7cddfSDavid du Colombier 		npid = atoi(ARGF());
917dd7cddfSDavid du Colombier 		if(npid == 0)
927dd7cddfSDavid du Colombier 			usage();
937dd7cddfSDavid du Colombier 		break;
94219b2ee8SDavid du Colombier 	}ARGEND;
95219b2ee8SDavid du Colombier 
96219b2ee8SDavid du Colombier 	if(argc != 2)
973e12c5d1SDavid du Colombier 		usage();
98219b2ee8SDavid du Colombier 
997dd7cddfSDavid du Colombier 	pidlist = malloc(npid*sizeof(*pidlist));
1007dd7cddfSDavid du Colombier 	if(pidlist == 0)
1017dd7cddfSDavid du Colombier 		error("can't malloc", 0);
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	if(aflag == 0 && qdir == 0) {
1047dd7cddfSDavid du Colombier 		qdir = getuser();
1057dd7cddfSDavid du Colombier 		if(qdir == 0)
1067dd7cddfSDavid du Colombier 			error("unknown user", 0);
1077dd7cddfSDavid du Colombier 	}
108219b2ee8SDavid du Colombier 	root = argv[0];
109219b2ee8SDavid du Colombier 	cmd = argv[1];
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier 	if(chdir(root) < 0)
1123e12c5d1SDavid du Colombier 		error("can't cd to %s", root);
1133e12c5d1SDavid du Colombier 
1147dd7cddfSDavid du Colombier 	doload(1);
1157dd7cddfSDavid du Colombier 	if(aflag)
1163e12c5d1SDavid du Colombier 		doalldirs();
1173e12c5d1SDavid du Colombier 	else
1187dd7cddfSDavid du Colombier 		dodir(qdir);
1197dd7cddfSDavid du Colombier 	doload(0);
1203e12c5d1SDavid du Colombier 	exits(0);
1213e12c5d1SDavid du Colombier }
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier int
emptydir(char * name)1243e12c5d1SDavid du Colombier emptydir(char *name)
1253e12c5d1SDavid du Colombier {
1263e12c5d1SDavid du Colombier 	int fd;
1273e12c5d1SDavid du Colombier 	long n;
1289a747e4fSDavid du Colombier 	char buf[2048];
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	fd = open(name, OREAD);
1313e12c5d1SDavid du Colombier 	if(fd < 0)
1323e12c5d1SDavid du Colombier 		return 1;
1339a747e4fSDavid du Colombier 	n = read(fd, buf, sizeof(buf));
1343e12c5d1SDavid du Colombier 	close(fd);
1357dd7cddfSDavid du Colombier 	if(n <= 0) {
1367dd7cddfSDavid du Colombier 		if(debug)
1377dd7cddfSDavid du Colombier 			fprint(2, "removing directory %s\n", name);
1387dd7cddfSDavid du Colombier 		syslog(0, runqlog, "rmdir %s", name);
1397dd7cddfSDavid du Colombier 		sysremove(name);
1403e12c5d1SDavid du Colombier 		return 1;
1417dd7cddfSDavid du Colombier 	}
1423e12c5d1SDavid du Colombier 	return 0;
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier 
1457dd7cddfSDavid du Colombier int
forkltd(void)1467dd7cddfSDavid du Colombier forkltd(void)
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier 	int i;
1497dd7cddfSDavid du Colombier 	int pid;
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	for(i = 0; i < npid; i++){
1527dd7cddfSDavid du Colombier 		if(pidlist[i] <= 0)
1537dd7cddfSDavid du Colombier 			break;
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	while(i >= npid){
1579a747e4fSDavid du Colombier 		pid = waitpid();
1587dd7cddfSDavid du Colombier 		if(pid < 0){
1597dd7cddfSDavid du Colombier 			syslog(0, runqlog, "forkltd confused");
1607dd7cddfSDavid du Colombier 			exits(0);
1617dd7cddfSDavid du Colombier 		}
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 		for(i = 0; i < npid; i++)
1647dd7cddfSDavid du Colombier 			if(pidlist[i] == pid)
1657dd7cddfSDavid du Colombier 				break;
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 	pidlist[i] = fork();
1687dd7cddfSDavid du Colombier 	return pidlist[i];
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1713e12c5d1SDavid du Colombier /*
1727dd7cddfSDavid du Colombier  *  run all user directories, must be bootes (or root on unix) to do this
1733e12c5d1SDavid du Colombier  */
1743e12c5d1SDavid du Colombier void
doalldirs(void)1753e12c5d1SDavid du Colombier doalldirs(void)
1763e12c5d1SDavid du Colombier {
1779a747e4fSDavid du Colombier 	Dir *db;
1783e12c5d1SDavid du Colombier 	int fd;
1793e12c5d1SDavid du Colombier 	long i, n;
1803e12c5d1SDavid du Colombier 
1817dd7cddfSDavid du Colombier 
1823e12c5d1SDavid du Colombier 	fd = open(".", OREAD);
1833e12c5d1SDavid du Colombier 	if(fd == -1){
1843e12c5d1SDavid du Colombier 		warning("reading %s", root);
1853e12c5d1SDavid du Colombier 		return;
1863e12c5d1SDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	n = sysdirreadall(fd, &db);
1889a747e4fSDavid du Colombier 	if(n > 0){
1893e12c5d1SDavid du Colombier 		for(i=0; i<n; i++){
1909a747e4fSDavid du Colombier 			if(db[i].qid.type & QTDIR){
1913e12c5d1SDavid du Colombier 				if(emptydir(db[i].name))
1923e12c5d1SDavid du Colombier 					continue;
1937dd7cddfSDavid du Colombier 				switch(forkltd()){
1943e12c5d1SDavid du Colombier 				case -1:
1957dd7cddfSDavid du Colombier 					syslog(0, runqlog, "out of procs");
1967dd7cddfSDavid du Colombier 					doload(0);
1977dd7cddfSDavid du Colombier 					exits(0);
1983e12c5d1SDavid du Colombier 				case 0:
1997dd7cddfSDavid du Colombier 					if(sysdetach() < 0)
2007dd7cddfSDavid du Colombier 						error("%r", 0);
2013e12c5d1SDavid du Colombier 					dodir(db[i].name);
2023e12c5d1SDavid du Colombier 					exits(0);
2033e12c5d1SDavid du Colombier 				default:
2043e12c5d1SDavid du Colombier 					break;
2053e12c5d1SDavid du Colombier 				}
2063e12c5d1SDavid du Colombier 			}
2073e12c5d1SDavid du Colombier 		}
2089a747e4fSDavid du Colombier 		free(db);
2093e12c5d1SDavid du Colombier 	}
2103e12c5d1SDavid du Colombier 	close(fd);
2113e12c5d1SDavid du Colombier }
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier /*
2143e12c5d1SDavid du Colombier  *  cd to a user directory and run it
2153e12c5d1SDavid du Colombier  */
2163e12c5d1SDavid du Colombier void
dodir(char * name)2173e12c5d1SDavid du Colombier dodir(char *name)
2183e12c5d1SDavid du Colombier {
2197dd7cddfSDavid du Colombier 	curdir = name;
2207dd7cddfSDavid du Colombier 
2213e12c5d1SDavid du Colombier 	if(chdir(name) < 0){
2223e12c5d1SDavid du Colombier 		warning("cd to %s", name);
2233e12c5d1SDavid du Colombier 		return;
2243e12c5d1SDavid du Colombier 	}
2253e12c5d1SDavid du Colombier 	if(debug)
2263e12c5d1SDavid du Colombier 		fprint(2, "running %s\n", name);
2273e12c5d1SDavid du Colombier 	rundir(name);
2283e12c5d1SDavid du Colombier 	chdir("..");
2293e12c5d1SDavid du Colombier }
2303e12c5d1SDavid du Colombier 
2313e12c5d1SDavid du Colombier /*
2323e12c5d1SDavid du Colombier  *  run the current directory
2333e12c5d1SDavid du Colombier  */
2343e12c5d1SDavid du Colombier void
rundir(char * name)2353e12c5d1SDavid du Colombier rundir(char *name)
2363e12c5d1SDavid du Colombier {
2373e12c5d1SDavid du Colombier 	int fd;
238219b2ee8SDavid du Colombier 	long i;
2393e12c5d1SDavid du Colombier 
2407dd7cddfSDavid du Colombier 	if(aflag && sflag)
2417dd7cddfSDavid du Colombier 		fd = sysopenlocked(".", OREAD);
2427dd7cddfSDavid du Colombier 	else
2433e12c5d1SDavid du Colombier 		fd = open(".", OREAD);
2443e12c5d1SDavid du Colombier 	if(fd == -1){
2453e12c5d1SDavid du Colombier 		warning("reading %s", name);
2463e12c5d1SDavid du Colombier 		return;
2473e12c5d1SDavid du Colombier 	}
2489a747e4fSDavid du Colombier 	nfiles = sysdirreadall(fd, &dirbuf);
2499a747e4fSDavid du Colombier 	if(nfiles > 0){
250219b2ee8SDavid du Colombier 		for(i=0; i<nfiles; i++){
251219b2ee8SDavid du Colombier 			if(dirbuf[i].name[0]!='C' || dirbuf[i].name[1]!='.')
252219b2ee8SDavid du Colombier 				continue;
253219b2ee8SDavid du Colombier 			dofile(&dirbuf[i]);
254219b2ee8SDavid du Colombier 		}
2559a747e4fSDavid du Colombier 		free(dirbuf);
2569a747e4fSDavid du Colombier 	}
2577dd7cddfSDavid du Colombier 	if(aflag && sflag)
2587dd7cddfSDavid du Colombier 		sysunlockfile(fd);
2597dd7cddfSDavid du Colombier 	else
2607dd7cddfSDavid du Colombier 		close(fd);
261219b2ee8SDavid du Colombier }
262219b2ee8SDavid du Colombier 
263219b2ee8SDavid du Colombier /*
264219b2ee8SDavid du Colombier  *  free files matching name in the current directory
265219b2ee8SDavid du Colombier  */
266219b2ee8SDavid du Colombier void
remmatch(char * name)267219b2ee8SDavid du Colombier remmatch(char *name)
268219b2ee8SDavid du Colombier {
269219b2ee8SDavid du Colombier 	long i;
270219b2ee8SDavid du Colombier 
2717dd7cddfSDavid du Colombier 	syslog(0, runqlog, "removing %s/%s", curdir, name);
2727dd7cddfSDavid du Colombier 
273219b2ee8SDavid du Colombier 	for(i=0; i<nfiles; i++){
274219b2ee8SDavid du Colombier 		if(strcmp(&dirbuf[i].name[1], &name[1]) == 0)
2757dd7cddfSDavid du Colombier 			sysremove(dirbuf[i].name);
276219b2ee8SDavid du Colombier 	}
277219b2ee8SDavid du Colombier 
278219b2ee8SDavid du Colombier 	/* error file (may have) appeared after we read the directory */
2797dd7cddfSDavid du Colombier 	/* stomp on data file in case of phase error */
2807dd7cddfSDavid du Colombier 	sysremove(file(name, 'D'));
2817dd7cddfSDavid du Colombier 	sysremove(file(name, 'E'));
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier 
2843e12c5d1SDavid du Colombier /*
2854f281771SDavid du Colombier  *  like trylock, but we've already got the lock on fd,
2864f281771SDavid du Colombier  *  and don't want an L. lock file.
2874f281771SDavid du Colombier  */
2884f281771SDavid du Colombier static Mlock *
keeplockalive(char * path,int fd)2894f281771SDavid du Colombier keeplockalive(char *path, int fd)
2904f281771SDavid du Colombier {
2914f281771SDavid du Colombier 	char buf[1];
2924f281771SDavid du Colombier 	Mlock *l;
2934f281771SDavid du Colombier 
2944f281771SDavid du Colombier 	l = malloc(sizeof(Mlock));
2954f281771SDavid du Colombier 	if(l == 0)
2964f281771SDavid du Colombier 		return 0;
2974f281771SDavid du Colombier 	l->fd = fd;
2984f281771SDavid du Colombier 	l->name = s_new();
2994f281771SDavid du Colombier 	s_append(l->name, path);
3004f281771SDavid du Colombier 
3014f281771SDavid du Colombier 	/* fork process to keep lock alive until sysunlock(l) */
3024f281771SDavid du Colombier 	switch(l->pid = rfork(RFPROC)){
3034f281771SDavid du Colombier 	default:
3044f281771SDavid du Colombier 		break;
3054f281771SDavid du Colombier 	case 0:
3064f281771SDavid du Colombier 		fd = l->fd;
3074f281771SDavid du Colombier 		for(;;){
3084f281771SDavid du Colombier 			sleep(1000*60);
3094f281771SDavid du Colombier 			if(pread(fd, buf, 1, 0) < 0)
3104f281771SDavid du Colombier 				break;
3114f281771SDavid du Colombier 		}
3124f281771SDavid du Colombier 		_exits(0);
3134f281771SDavid du Colombier 	}
3144f281771SDavid du Colombier 	return l;
3154f281771SDavid du Colombier }
3164f281771SDavid du Colombier 
3174f281771SDavid du Colombier /*
3183e12c5d1SDavid du Colombier  *  try a message
3193e12c5d1SDavid du Colombier  */
3203e12c5d1SDavid du Colombier void
dofile(Dir * dp)3213e12c5d1SDavid du Colombier dofile(Dir *dp)
3223e12c5d1SDavid du Colombier {
3239a747e4fSDavid du Colombier 	Dir *d;
3249a747e4fSDavid du Colombier 	int dfd, ac, dtime, efd, pid, i, etime;
3257dd7cddfSDavid du Colombier 	char *buf, *cp, **av;
3269a747e4fSDavid du Colombier 	Waitmsg *wm;
3277dd7cddfSDavid du Colombier 	Biobuf *b;
3284f281771SDavid du Colombier 	Mlock *l = nil;
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 	if(debug)
3313e12c5d1SDavid du Colombier 		fprint(2, "dofile %s\n", dp->name);
3323e12c5d1SDavid du Colombier 	/*
33314414594SDavid du Colombier 	 *  if no data file or empty control or data file, just clean up
33414414594SDavid du Colombier 	 *  the empty control file must be 15 minutes old, to minimize the
33514414594SDavid du Colombier 	 *  chance of a race.
3363e12c5d1SDavid du Colombier 	 */
3379a747e4fSDavid du Colombier 	d = dirstat(file(dp->name, 'D'));
3389a747e4fSDavid du Colombier 	if(d == nil){
3397dd7cddfSDavid du Colombier 		syslog(0, runqlog, "no data file for %s", dp->name);
340219b2ee8SDavid du Colombier 		remmatch(dp->name);
3413e12c5d1SDavid du Colombier 		return;
3423e12c5d1SDavid du Colombier 	}
34314414594SDavid du Colombier 	if(dp->length == 0){
34414414594SDavid du Colombier 		if(time(0)-dp->mtime > 15*60){
34514414594SDavid du Colombier 			syslog(0, runqlog, "empty ctl file for %s", dp->name);
34614414594SDavid du Colombier 			remmatch(dp->name);
34714414594SDavid du Colombier 		}
34814414594SDavid du Colombier 		return;
34914414594SDavid du Colombier 	}
3509a747e4fSDavid du Colombier 	dtime = d->mtime;
3519a747e4fSDavid du Colombier 	free(d);
3523e12c5d1SDavid du Colombier 
3533e12c5d1SDavid du Colombier 	/*
3543e12c5d1SDavid du Colombier 	 *  retry times depend on the age of the errors file
3553e12c5d1SDavid du Colombier 	 */
3569a747e4fSDavid du Colombier 	if(!Eflag && (d = dirstat(file(dp->name, 'E'))) != nil){
3579a747e4fSDavid du Colombier 		etime = d->mtime;
3589a747e4fSDavid du Colombier 		free(d);
359*39dc1420SDavid du Colombier 		if(etime - dtime < 15*60){
360*39dc1420SDavid du Colombier 			/* up to the first 15 minutes, every 30 seconds */
361*39dc1420SDavid du Colombier 			if(time(0) - etime < 30)
362*39dc1420SDavid du Colombier 				return;
363*39dc1420SDavid du Colombier 		} else if(etime - dtime < 60*60){
3643e12c5d1SDavid du Colombier 			/* up to the first hour, try every 15 minutes */
3659a747e4fSDavid du Colombier 			if(time(0) - etime < 15*60)
3663e12c5d1SDavid du Colombier 				return;
3673e12c5d1SDavid du Colombier 		} else {
3683e12c5d1SDavid du Colombier 			/* after the first hour, try once an hour */
3699a747e4fSDavid du Colombier 			if(time(0) - etime < 60*60)
3703e12c5d1SDavid du Colombier 				return;
3713e12c5d1SDavid du Colombier 		}
3729a747e4fSDavid du Colombier 
3733e12c5d1SDavid du Colombier 	}
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier 	/*
3763e12c5d1SDavid du Colombier 	 *  open control and data
3773e12c5d1SDavid du Colombier 	 */
3787dd7cddfSDavid du Colombier 	b = sysopen(file(dp->name, 'C'), "rl", 0660);
3797dd7cddfSDavid du Colombier 	if(b == 0) {
3807dd7cddfSDavid du Colombier 		if(debug)
3817dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'C'));
3823e12c5d1SDavid du Colombier 		return;
3837dd7cddfSDavid du Colombier 	}
3843e12c5d1SDavid du Colombier 	dfd = open(file(dp->name, 'D'), OREAD);
3853e12c5d1SDavid du Colombier 	if(dfd < 0){
3867dd7cddfSDavid du Colombier 		if(debug)
3877dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'D'));
3887dd7cddfSDavid du Colombier 		Bterm(b);
3897dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3903e12c5d1SDavid du Colombier 		return;
3913e12c5d1SDavid du Colombier 	}
3923e12c5d1SDavid du Colombier 
3933e12c5d1SDavid du Colombier 	/*
3943e12c5d1SDavid du Colombier 	 *  make arg list
3953e12c5d1SDavid du Colombier 	 *	- read args into (malloc'd) buffer
3963e12c5d1SDavid du Colombier 	 *	- malloc a vector and copy pointers to args into it
3973e12c5d1SDavid du Colombier 	 */
3983e12c5d1SDavid du Colombier 	buf = malloc(dp->length+1);
3997dd7cddfSDavid du Colombier 	if(buf == 0){
4007dd7cddfSDavid du Colombier 		warning("buffer allocation", 0);
4017dd7cddfSDavid du Colombier 		Bterm(b);
4027dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4037dd7cddfSDavid du Colombier 		close(dfd);
4047dd7cddfSDavid du Colombier 		return;
4057dd7cddfSDavid du Colombier 	}
4067dd7cddfSDavid du Colombier 	if(Bread(b, buf, dp->length) != dp->length){
4073e12c5d1SDavid du Colombier 		warning("reading control file %s\n", dp->name);
4087dd7cddfSDavid du Colombier 		Bterm(b);
4097dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4107dd7cddfSDavid du Colombier 		close(dfd);
4117dd7cddfSDavid du Colombier 		free(buf);
4127dd7cddfSDavid du Colombier 		return;
4133e12c5d1SDavid du Colombier 	}
4143e12c5d1SDavid du Colombier 	buf[dp->length] = 0;
4157dd7cddfSDavid du Colombier 	av = malloc(2*sizeof(char*));
4167dd7cddfSDavid du Colombier 	if(av == 0){
4177dd7cddfSDavid du Colombier 		warning("argv allocation", 0);
4187dd7cddfSDavid du Colombier 		close(dfd);
4197dd7cddfSDavid du Colombier 		free(buf);
4207dd7cddfSDavid du Colombier 		Bterm(b);
4217dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4227dd7cddfSDavid du Colombier 		return;
4233e12c5d1SDavid du Colombier 	}
4243e12c5d1SDavid du Colombier 	for(ac = 1, cp = buf; *cp; ac++){
4253e12c5d1SDavid du Colombier 		while(isspace(*cp))
4263e12c5d1SDavid du Colombier 			*cp++ = 0;
4277dd7cddfSDavid du Colombier 		if(*cp == 0)
4287dd7cddfSDavid du Colombier 			break;
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 		av = realloc(av, (ac+2)*sizeof(char*));
4317dd7cddfSDavid du Colombier 		if(av == 0){
4327dd7cddfSDavid du Colombier 			warning("argv allocation", 0);
4337dd7cddfSDavid du Colombier 			close(dfd);
4347dd7cddfSDavid du Colombier 			free(buf);
4357dd7cddfSDavid du Colombier 			Bterm(b);
4367dd7cddfSDavid du Colombier 			sysunlockfile(Bfildes(b));
4377dd7cddfSDavid du Colombier 			return;
4387dd7cddfSDavid du Colombier 		}
4393e12c5d1SDavid du Colombier 		av[ac] = cp;
4407dd7cddfSDavid du Colombier 		while(*cp && !isspace(*cp)){
4417dd7cddfSDavid du Colombier 			if(*cp++ == '"'){
4423e12c5d1SDavid du Colombier 				while(*cp && *cp != '"')
4433e12c5d1SDavid du Colombier 					cp++;
4443e12c5d1SDavid du Colombier 				if(*cp)
4453e12c5d1SDavid du Colombier 					cp++;
4463e12c5d1SDavid du Colombier 			}
4473e12c5d1SDavid du Colombier 		}
4487dd7cddfSDavid du Colombier 	}
4497dd7cddfSDavid du Colombier 	av[0] = cmd;
4503e12c5d1SDavid du Colombier 	av[ac] = 0;
4513e12c5d1SDavid du Colombier 
45280ee5cbfSDavid du Colombier 	if(!Eflag &&time(0) - dtime > giveup){
453ed250ae1SDavid du Colombier 		if(returnmail(av, dp->name, "Giveup") != 0)
4547dd7cddfSDavid du Colombier 			logit("returnmail failed", dp->name, av);
4557dd7cddfSDavid du Colombier 		remmatch(dp->name);
4567dd7cddfSDavid du Colombier 		goto done;
4577dd7cddfSDavid du Colombier 	}
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	for(i = 0; i < nbad; i++){
4607dd7cddfSDavid du Colombier 		if(strcmp(av[3], badsys[i]) == 0)
4617dd7cddfSDavid du Colombier 			goto done;
462219b2ee8SDavid du Colombier 	}
463219b2ee8SDavid du Colombier 
4643e12c5d1SDavid du Colombier 	/*
4654f281771SDavid du Colombier 	 * Ken's fs, for example, gives us 5 minutes of inactivity before
4664f281771SDavid du Colombier 	 * the lock goes stale, so we have to keep reading it.
4674f281771SDavid du Colombier  	 */
4684f281771SDavid du Colombier 	l = keeplockalive(file(dp->name, 'C'), Bfildes(b));
4694f281771SDavid du Colombier 
4704f281771SDavid du Colombier 	/*
4713e12c5d1SDavid du Colombier 	 *  transfer
4723e12c5d1SDavid du Colombier 	 */
4737dd7cddfSDavid du Colombier 	pid = fork();
4747dd7cddfSDavid du Colombier 	switch(pid){
4753e12c5d1SDavid du Colombier 	case -1:
4764f281771SDavid du Colombier 		sysunlock(l);
4777dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4787dd7cddfSDavid du Colombier 		syslog(0, runqlog, "out of procs");
4797dd7cddfSDavid du Colombier 		exits(0);
4803e12c5d1SDavid du Colombier 	case 0:
4817dd7cddfSDavid du Colombier 		if(debug) {
4827dd7cddfSDavid du Colombier 			fprint(2, "Starting %s", cmd);
4837dd7cddfSDavid du Colombier 			for(ac = 0; av[ac]; ac++)
4847dd7cddfSDavid du Colombier 				fprint(2, " %s", av[ac]);
4857dd7cddfSDavid du Colombier 			fprint(2, "\n");
4867dd7cddfSDavid du Colombier 		}
4877dd7cddfSDavid du Colombier 		logit("execing", dp->name, av);
4883e12c5d1SDavid du Colombier 		close(0);
4893e12c5d1SDavid du Colombier 		dup(dfd, 0);
4907dd7cddfSDavid du Colombier 		close(dfd);
4913e12c5d1SDavid du Colombier 		close(2);
4927dd7cddfSDavid du Colombier 		efd = open(file(dp->name, 'E'), OWRITE);
4932b7fd5adSDavid du Colombier 		if(efd < 0){
4942b7fd5adSDavid du Colombier 			if(debug) syslog(0, "runq", "open %s as %s: %r", file(dp->name,'E'), getuser());
4952b7fd5adSDavid du Colombier 			efd = create(file(dp->name, 'E'), OWRITE, 0666);
4962b7fd5adSDavid du Colombier 			if(efd < 0){
4972b7fd5adSDavid du Colombier 				if(debug) syslog(0, "runq", "create %s as %s: %r", file(dp->name, 'E'), getuser());
4982b7fd5adSDavid du Colombier 				exits("could not open error file - Retry");
4992b7fd5adSDavid du Colombier 			}
5002b7fd5adSDavid du Colombier 		}
5013e12c5d1SDavid du Colombier 		seek(efd, 0, 2);
5023e12c5d1SDavid du Colombier 		exec(cmd, av);
5033e12c5d1SDavid du Colombier 		error("can't exec %s", cmd);
5043e12c5d1SDavid du Colombier 		break;
5053e12c5d1SDavid du Colombier 	default:
5069a747e4fSDavid du Colombier 		for(;;){
5079a747e4fSDavid du Colombier 			wm = wait();
5089a747e4fSDavid du Colombier 			if(wm == nil)
5099a747e4fSDavid du Colombier 				error("wait failed: %r", "");
5109a747e4fSDavid du Colombier 			if(wm->pid == pid)
5119a747e4fSDavid du Colombier 				break;
5129a747e4fSDavid du Colombier 			free(wm);
5139a747e4fSDavid du Colombier 		}
5142b7fd5adSDavid du Colombier 		if(debug)
5152b7fd5adSDavid du Colombier 			fprint(2, "wm->pid %d wm->msg == %s\n", wm->pid, wm->msg);
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier 		if(wm->msg[0]){
5183e12c5d1SDavid du Colombier 			if(debug)
5199a747e4fSDavid du Colombier 				fprint(2, "[%d] wm->msg == %s\n", getpid(), wm->msg);
520*39dc1420SDavid du Colombier 			syslog(0, runqlog, "message: %s\n", wm->msg);
521*39dc1420SDavid du Colombier 			if(strstr(wm->msg, "Ignore") != nil){
522*39dc1420SDavid du Colombier 				/* fix for fish/chips, leave message alone */
523*39dc1420SDavid du Colombier 				logit("ignoring", dp->name, av);
524*39dc1420SDavid du Colombier 			}else if(!Rflag && strstr(wm->msg, "Retry")==0){
5253e12c5d1SDavid du Colombier 				/* return the message and remove it */
5262b7fd5adSDavid du Colombier 				if(returnmail(av, dp->name, wm->msg) != 0)
527ed250ae1SDavid du Colombier 					logit("returnmail failed", dp->name, av);
528219b2ee8SDavid du Colombier 				remmatch(dp->name);
5293e12c5d1SDavid du Colombier 			} else {
5307dd7cddfSDavid du Colombier 				/* add sys to bad list and try again later */
5317dd7cddfSDavid du Colombier 				nbad++;
5327dd7cddfSDavid du Colombier 				badsys = realloc(badsys, nbad*sizeof(char*));
5337dd7cddfSDavid du Colombier 				badsys[nbad-1] = strdup(av[3]);
5343e12c5d1SDavid du Colombier 			}
5353e12c5d1SDavid du Colombier 		} else {
5363e12c5d1SDavid du Colombier 			/* it worked remove the message */
537219b2ee8SDavid du Colombier 			remmatch(dp->name);
5383e12c5d1SDavid du Colombier 		}
5399a747e4fSDavid du Colombier 		free(wm);
5403e12c5d1SDavid du Colombier 
5413e12c5d1SDavid du Colombier 	}
5427dd7cddfSDavid du Colombier done:
5434f281771SDavid du Colombier 	if (l)
5444f281771SDavid du Colombier 		sysunlock(l);
5457dd7cddfSDavid du Colombier 	Bterm(b);
5467dd7cddfSDavid du Colombier 	sysunlockfile(Bfildes(b));
5477dd7cddfSDavid du Colombier 	free(buf);
5487dd7cddfSDavid du Colombier 	free(av);
5493e12c5d1SDavid du Colombier 	close(dfd);
5503e12c5d1SDavid du Colombier }
5513e12c5d1SDavid du Colombier 
5527dd7cddfSDavid du Colombier 
5533e12c5d1SDavid du Colombier /*
5543e12c5d1SDavid du Colombier  *  return a name starting with the given character
5553e12c5d1SDavid du Colombier  */
5563e12c5d1SDavid du Colombier char*
file(char * name,char type)5573e12c5d1SDavid du Colombier file(char *name, char type)
5583e12c5d1SDavid du Colombier {
5599a747e4fSDavid du Colombier 	static char nname[Elemlen+1];
5603e12c5d1SDavid du Colombier 
5619a747e4fSDavid du Colombier 	strncpy(nname, name, Elemlen);
5629a747e4fSDavid du Colombier 	nname[Elemlen] = 0;
5633e12c5d1SDavid du Colombier 	nname[0] = type;
5643e12c5d1SDavid du Colombier 	return nname;
5653e12c5d1SDavid du Colombier }
5663e12c5d1SDavid du Colombier 
5673e12c5d1SDavid du Colombier /*
5683e12c5d1SDavid du Colombier  *  send back the mail with an error message
5693e12c5d1SDavid du Colombier  *
5703e12c5d1SDavid du Colombier  *  return 0 if successful
5713e12c5d1SDavid du Colombier  */
5723e12c5d1SDavid du Colombier int
returnmail(char ** av,char * name,char * msg)5733e12c5d1SDavid du Colombier returnmail(char **av, char *name, char *msg)
5743e12c5d1SDavid du Colombier {
5753e12c5d1SDavid du Colombier 	int pfd[2];
5769a747e4fSDavid du Colombier 	Waitmsg *wm;
5773e12c5d1SDavid du Colombier 	int fd;
5783e12c5d1SDavid du Colombier 	char buf[256];
579d9306527SDavid du Colombier 	char attachment[256];
5803e12c5d1SDavid du Colombier 	int i;
5813e12c5d1SDavid du Colombier 	long n;
5827dd7cddfSDavid du Colombier 	String *s;
5837dd7cddfSDavid du Colombier 	char *sender;
5843e12c5d1SDavid du Colombier 
5857dd7cddfSDavid du Colombier 	if(av[1] == 0 || av[2] == 0){
5867dd7cddfSDavid du Colombier 		logit("runq - dumping bad file", name, av);
5877dd7cddfSDavid du Colombier 		return 0;
5887dd7cddfSDavid du Colombier 	}
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 	s = unescapespecial(s_copy(av[2]));
5917dd7cddfSDavid du Colombier 	sender = s_to_c(s);
5927dd7cddfSDavid du Colombier 
5937dd7cddfSDavid du Colombier 	if(!returnable(sender) || strcmp(sender, "postmaster") == 0) {
5947dd7cddfSDavid du Colombier 		logit("runq - dumping p to p mail", name, av);
5957dd7cddfSDavid du Colombier 		return 0;
5967dd7cddfSDavid du Colombier 	}
5973e12c5d1SDavid du Colombier 
5982b7fd5adSDavid du Colombier 	if(pipe(pfd) < 0){
5992b7fd5adSDavid du Colombier 		logit("runq - pipe failed", name, av);
6003e12c5d1SDavid du Colombier 		return -1;
6012b7fd5adSDavid du Colombier 	}
6023e12c5d1SDavid du Colombier 
6037dd7cddfSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFENVG)){
6043e12c5d1SDavid du Colombier 	case -1:
6052b7fd5adSDavid du Colombier 		logit("runq - fork failed", name, av);
6063e12c5d1SDavid du Colombier 		return -1;
6073e12c5d1SDavid du Colombier 	case 0:
6087dd7cddfSDavid du Colombier 		logit("returning", name, av);
6093e12c5d1SDavid du Colombier 		close(pfd[1]);
6103e12c5d1SDavid du Colombier 		close(0);
6113e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
6123e12c5d1SDavid du Colombier 		close(pfd[0]);
6137dd7cddfSDavid du Colombier 		putenv("upasname", "/dev/null");
614d9306527SDavid du Colombier 		snprint(buf, sizeof(buf), "%s/marshal", UPASBIN);
615d9306527SDavid du Colombier 		snprint(attachment, sizeof(attachment), "%s", file(name, 'D'));
616f19e7b74SDavid du Colombier 		execl(buf, "send", "-A", attachment, "-s", "permanent failure", sender, nil);
6173e12c5d1SDavid du Colombier 		error("can't exec", 0);
6183e12c5d1SDavid du Colombier 		break;
6193e12c5d1SDavid du Colombier 	default:
6203e12c5d1SDavid du Colombier 		break;
6213e12c5d1SDavid du Colombier 	}
6223e12c5d1SDavid du Colombier 
6233e12c5d1SDavid du Colombier 	close(pfd[0]);
6243ff48bf5SDavid du Colombier 	fprint(pfd[1], "\n");	/* get out of headers */
6253e12c5d1SDavid du Colombier 	if(av[1]){
6267dd7cddfSDavid du Colombier 		fprint(pfd[1], "Your request ``%.20s ", av[1]);
6273e12c5d1SDavid du Colombier 		for(n = 3; av[n]; n++)
6283e12c5d1SDavid du Colombier 			fprint(pfd[1], "%s ", av[n]);
6293e12c5d1SDavid du Colombier 	}
6303e12c5d1SDavid du Colombier 	fprint(pfd[1], "'' failed (code %s).\nThe symptom was:\n\n", msg);
6313e12c5d1SDavid du Colombier 	fd = open(file(name, 'E'), OREAD);
6323e12c5d1SDavid du Colombier 	if(fd >= 0){
6333e12c5d1SDavid du Colombier 		for(;;){
6343e12c5d1SDavid du Colombier 			n = read(fd, buf, sizeof(buf));
6353e12c5d1SDavid du Colombier 			if(n <= 0)
6363e12c5d1SDavid du Colombier 				break;
6373e12c5d1SDavid du Colombier 			if(write(pfd[1], buf, n) != n){
6383e12c5d1SDavid du Colombier 				close(fd);
6393e12c5d1SDavid du Colombier 				goto out;
6403e12c5d1SDavid du Colombier 			}
6413e12c5d1SDavid du Colombier 		}
6423e12c5d1SDavid du Colombier 		close(fd);
6433e12c5d1SDavid du Colombier 	}
6443e12c5d1SDavid du Colombier 	close(pfd[1]);
6453e12c5d1SDavid du Colombier out:
6469a747e4fSDavid du Colombier 	wm = wait();
6472b7fd5adSDavid du Colombier 	if(wm == nil){
6482b7fd5adSDavid du Colombier 		syslog(0, "runq", "wait: %r");
6492b7fd5adSDavid du Colombier 		logit("wait failed", name, av);
6509a747e4fSDavid du Colombier 		return -1;
6512b7fd5adSDavid du Colombier 	}
6522b7fd5adSDavid du Colombier 	i = 0;
6532b7fd5adSDavid du Colombier 	if(wm->msg[0]){
6542b7fd5adSDavid du Colombier 		i = -1;
6552b7fd5adSDavid du Colombier 		syslog(0, "runq", "returnmail child: %s", wm->msg);
6562b7fd5adSDavid du Colombier 		logit("returnmail child failed", name, av);
6572b7fd5adSDavid du Colombier 	}
6589a747e4fSDavid du Colombier 	free(wm);
6599a747e4fSDavid du Colombier 	return i;
6603e12c5d1SDavid du Colombier }
6613e12c5d1SDavid du Colombier 
6623e12c5d1SDavid du Colombier /*
6633e12c5d1SDavid du Colombier  *  print a warning and continue
6643e12c5d1SDavid du Colombier  */
6653e12c5d1SDavid du Colombier void
warning(char * f,void * a)6663e12c5d1SDavid du Colombier warning(char *f, void *a)
6673e12c5d1SDavid du Colombier {
6683e12c5d1SDavid du Colombier 	char err[65];
6693e12c5d1SDavid du Colombier 	char buf[256];
6703e12c5d1SDavid du Colombier 
6719a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6727dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6733e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6743e12c5d1SDavid du Colombier }
6753e12c5d1SDavid du Colombier 
6763e12c5d1SDavid du Colombier /*
6773e12c5d1SDavid du Colombier  *  print an error and die
6783e12c5d1SDavid du Colombier  */
6793e12c5d1SDavid du Colombier void
error(char * f,void * a)6803e12c5d1SDavid du Colombier error(char *f, void *a)
6813e12c5d1SDavid du Colombier {
6829a747e4fSDavid du Colombier 	char err[Errlen];
6833e12c5d1SDavid du Colombier 	char buf[256];
6843e12c5d1SDavid du Colombier 
6859a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6867dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6873e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6883e12c5d1SDavid du Colombier 	exits(buf);
6893e12c5d1SDavid du Colombier }
6903e12c5d1SDavid du Colombier 
6917dd7cddfSDavid du Colombier void
logit(char * msg,char * file,char ** av)6927dd7cddfSDavid du Colombier logit(char *msg, char *file, char **av)
6937dd7cddfSDavid du Colombier {
6947dd7cddfSDavid du Colombier 	int n, m;
6957dd7cddfSDavid du Colombier 	char buf[256];
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	n = snprint(buf, sizeof(buf), "%s/%s: %s", curdir, file, msg);
6987dd7cddfSDavid du Colombier 	for(; *av; av++){
6997dd7cddfSDavid du Colombier 		m = strlen(*av);
7007dd7cddfSDavid du Colombier 		if(n + m + 4 > sizeof(buf))
7017dd7cddfSDavid du Colombier 			break;
7027dd7cddfSDavid du Colombier 		sprint(buf + n, " '%s'", *av);
7037dd7cddfSDavid du Colombier 		n += m + 3;
7047dd7cddfSDavid du Colombier 	}
7059a747e4fSDavid du Colombier 	syslog(0, runqlog, "%s", buf);
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier char *loadfile = ".runqload";
7097dd7cddfSDavid du Colombier 
7107dd7cddfSDavid du Colombier /*
7117dd7cddfSDavid du Colombier  *  load balancing
7127dd7cddfSDavid du Colombier  */
7137dd7cddfSDavid du Colombier void
doload(int start)7147dd7cddfSDavid du Colombier doload(int start)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier 	int fd;
7177dd7cddfSDavid du Colombier 	char buf[32];
7187dd7cddfSDavid du Colombier 	int i, n;
7197dd7cddfSDavid du Colombier 	Mlock *l;
7209a747e4fSDavid du Colombier 	Dir *d;
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier 	if(load <= 0)
7237dd7cddfSDavid du Colombier 		return;
7247dd7cddfSDavid du Colombier 
7257dd7cddfSDavid du Colombier 	if(chdir(root) < 0){
7267dd7cddfSDavid du Colombier 		load = 0;
7277dd7cddfSDavid du Colombier 		return;
7287dd7cddfSDavid du Colombier 	}
7297dd7cddfSDavid du Colombier 
7307dd7cddfSDavid du Colombier 	l = syslock(loadfile);
7317dd7cddfSDavid du Colombier 	fd = open(loadfile, ORDWR);
7327dd7cddfSDavid du Colombier 	if(fd < 0){
7337dd7cddfSDavid du Colombier 		fd = create(loadfile, 0666, ORDWR);
7347dd7cddfSDavid du Colombier 		if(fd < 0){
7357dd7cddfSDavid du Colombier 			load = 0;
7367dd7cddfSDavid du Colombier 			sysunlock(l);
7377dd7cddfSDavid du Colombier 			return;
7387dd7cddfSDavid du Colombier 		}
7397dd7cddfSDavid du Colombier 	}
7407dd7cddfSDavid du Colombier 
7417dd7cddfSDavid du Colombier 	/* get current load */
7427dd7cddfSDavid du Colombier 	i = 0;
7437dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof(buf)-1);
7447dd7cddfSDavid du Colombier 	if(n >= 0){
7457dd7cddfSDavid du Colombier 		buf[n] = 0;
7467dd7cddfSDavid du Colombier 		i = atoi(buf);
7477dd7cddfSDavid du Colombier 	}
7487dd7cddfSDavid du Colombier 	if(i < 0)
7497dd7cddfSDavid du Colombier 		i = 0;
7507dd7cddfSDavid du Colombier 
7517dd7cddfSDavid du Colombier 	/* ignore load if file hasn't been changed in 30 minutes */
7529a747e4fSDavid du Colombier 	d = dirfstat(fd);
7539a747e4fSDavid du Colombier 	if(d != nil){
7549a747e4fSDavid du Colombier 		if(d->mtime + 30*60 < time(0))
7557dd7cddfSDavid du Colombier 			i = 0;
7569a747e4fSDavid du Colombier 		free(d);
7579a747e4fSDavid du Colombier 	}
7587dd7cddfSDavid du Colombier 
7597dd7cddfSDavid du Colombier 	/* if load already too high, give up */
7607dd7cddfSDavid du Colombier 	if(start && i >= load){
7617dd7cddfSDavid du Colombier 		sysunlock(l);
7627dd7cddfSDavid du Colombier 		exits(0);
7637dd7cddfSDavid du Colombier 	}
7647dd7cddfSDavid du Colombier 
7657dd7cddfSDavid du Colombier 	/* increment/decrement load */
7667dd7cddfSDavid du Colombier 	if(start)
7677dd7cddfSDavid du Colombier 		i++;
7687dd7cddfSDavid du Colombier 	else
7697dd7cddfSDavid du Colombier 		i--;
7707dd7cddfSDavid du Colombier 	seek(fd, 0, 0);
7717dd7cddfSDavid du Colombier 	fprint(fd, "%d\n", i);
7727dd7cddfSDavid du Colombier 	sysunlock(l);
7737dd7cddfSDavid du Colombier 	close(fd);
7747dd7cddfSDavid du Colombier }
775