xref: /plan9/sys/src/cmd/upas/q/runq.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
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 */
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier void
403e12c5d1SDavid du Colombier usage(void)
413e12c5d1SDavid du Colombier {
4214414594SDavid du Colombier 	fprint(2, "usage: runq [-adsE] [-q dir] [-l load] [-t time] [-r nfiles] [-n nprocs] q-root cmd\n");
433e12c5d1SDavid du Colombier 	exits("");
443e12c5d1SDavid du Colombier }
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier void
47219b2ee8SDavid du Colombier main(int argc, char **argv)
483e12c5d1SDavid du Colombier {
497dd7cddfSDavid du Colombier 	char *qdir, *x;
503e12c5d1SDavid du Colombier 
517dd7cddfSDavid du Colombier 	qdir = 0;
523e12c5d1SDavid du Colombier 
53219b2ee8SDavid du Colombier 	ARGBEGIN{
547dd7cddfSDavid du Colombier 	case 'l':
557dd7cddfSDavid du Colombier 		x = ARGF();
567dd7cddfSDavid du Colombier 		if(x == 0)
577dd7cddfSDavid du Colombier 			usage();
587dd7cddfSDavid du Colombier 		load = atoi(x);
597dd7cddfSDavid du Colombier 		if(load < 0)
607dd7cddfSDavid du Colombier 			load = 0;
617dd7cddfSDavid du Colombier 		break;
627dd7cddfSDavid du Colombier 	case 'E':
637dd7cddfSDavid du Colombier 		Eflag++;
647dd7cddfSDavid du Colombier 		break;
653e12c5d1SDavid du Colombier 	case 'a':
667dd7cddfSDavid du Colombier 		aflag++;
673e12c5d1SDavid du Colombier 		break;
683e12c5d1SDavid du Colombier 	case 'd':
69219b2ee8SDavid du Colombier 		debug++;
703e12c5d1SDavid du Colombier 		break;
7114414594SDavid du Colombier 	case 'r':
7214414594SDavid du Colombier 		limit = atoi(ARGF());
7314414594SDavid du Colombier 		break;
747dd7cddfSDavid du Colombier 	case 's':
757dd7cddfSDavid du Colombier 		sflag++;
767dd7cddfSDavid du Colombier 		break;
77219b2ee8SDavid du Colombier 	case 't':
78219b2ee8SDavid du Colombier 		giveup = 60*60*atoi(ARGF());
79219b2ee8SDavid du Colombier 		break;
807dd7cddfSDavid du Colombier 	case 'q':
817dd7cddfSDavid du Colombier 		qdir = ARGF();
827dd7cddfSDavid du Colombier 		if(qdir == 0)
837dd7cddfSDavid du Colombier 			usage();
847dd7cddfSDavid du Colombier 		break;
857dd7cddfSDavid du Colombier 	case 'n':
867dd7cddfSDavid du Colombier 		npid = atoi(ARGF());
877dd7cddfSDavid du Colombier 		if(npid == 0)
887dd7cddfSDavid du Colombier 			usage();
897dd7cddfSDavid du Colombier 		break;
90219b2ee8SDavid du Colombier 	}ARGEND;
91219b2ee8SDavid du Colombier 
92219b2ee8SDavid du Colombier 	if(argc != 2)
933e12c5d1SDavid du Colombier 		usage();
94219b2ee8SDavid du Colombier 
957dd7cddfSDavid du Colombier 	pidlist = malloc(npid*sizeof(*pidlist));
967dd7cddfSDavid du Colombier 	if(pidlist == 0)
977dd7cddfSDavid du Colombier 		error("can't malloc", 0);
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier 	if(aflag == 0 && qdir == 0) {
1007dd7cddfSDavid du Colombier 		qdir = getuser();
1017dd7cddfSDavid du Colombier 		if(qdir == 0)
1027dd7cddfSDavid du Colombier 			error("unknown user", 0);
1037dd7cddfSDavid du Colombier 	}
104219b2ee8SDavid du Colombier 	root = argv[0];
105219b2ee8SDavid du Colombier 	cmd = argv[1];
1063e12c5d1SDavid du Colombier 
1073e12c5d1SDavid du Colombier 	if(chdir(root) < 0)
1083e12c5d1SDavid du Colombier 		error("can't cd to %s", root);
1093e12c5d1SDavid du Colombier 
1107dd7cddfSDavid du Colombier 	doload(1);
1117dd7cddfSDavid du Colombier 	if(aflag)
1123e12c5d1SDavid du Colombier 		doalldirs();
1133e12c5d1SDavid du Colombier 	else
1147dd7cddfSDavid du Colombier 		dodir(qdir);
1157dd7cddfSDavid du Colombier 	doload(0);
1163e12c5d1SDavid du Colombier 	exits(0);
1173e12c5d1SDavid du Colombier }
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier int
1203e12c5d1SDavid du Colombier emptydir(char *name)
1213e12c5d1SDavid du Colombier {
1223e12c5d1SDavid du Colombier 	int fd;
1233e12c5d1SDavid du Colombier 	long n;
1249a747e4fSDavid du Colombier 	char buf[2048];
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier 	fd = open(name, OREAD);
1273e12c5d1SDavid du Colombier 	if(fd < 0)
1283e12c5d1SDavid du Colombier 		return 1;
1299a747e4fSDavid du Colombier 	n = read(fd, buf, sizeof(buf));
1303e12c5d1SDavid du Colombier 	close(fd);
1317dd7cddfSDavid du Colombier 	if(n <= 0) {
1327dd7cddfSDavid du Colombier 		if(debug)
1337dd7cddfSDavid du Colombier 			fprint(2, "removing directory %s\n", name);
1347dd7cddfSDavid du Colombier 		syslog(0, runqlog, "rmdir %s", name);
1357dd7cddfSDavid du Colombier 		sysremove(name);
1363e12c5d1SDavid du Colombier 		return 1;
1377dd7cddfSDavid du Colombier 	}
1383e12c5d1SDavid du Colombier 	return 0;
1393e12c5d1SDavid du Colombier }
1403e12c5d1SDavid du Colombier 
1417dd7cddfSDavid du Colombier int
1427dd7cddfSDavid du Colombier forkltd(void)
1437dd7cddfSDavid du Colombier {
1447dd7cddfSDavid du Colombier 	int i;
1457dd7cddfSDavid du Colombier 	int pid;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	for(i = 0; i < npid; i++){
1487dd7cddfSDavid du Colombier 		if(pidlist[i] <= 0)
1497dd7cddfSDavid du Colombier 			break;
1507dd7cddfSDavid du Colombier 	}
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	while(i >= npid){
1539a747e4fSDavid du Colombier 		pid = waitpid();
1547dd7cddfSDavid du Colombier 		if(pid < 0){
1557dd7cddfSDavid du Colombier 			syslog(0, runqlog, "forkltd confused");
1567dd7cddfSDavid du Colombier 			exits(0);
1577dd7cddfSDavid du Colombier 		}
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 		for(i = 0; i < npid; i++)
1607dd7cddfSDavid du Colombier 			if(pidlist[i] == pid)
1617dd7cddfSDavid du Colombier 				break;
1627dd7cddfSDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	pidlist[i] = fork();
1647dd7cddfSDavid du Colombier 	return pidlist[i];
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1673e12c5d1SDavid du Colombier /*
1687dd7cddfSDavid du Colombier  *  run all user directories, must be bootes (or root on unix) to do this
1693e12c5d1SDavid du Colombier  */
1703e12c5d1SDavid du Colombier void
1713e12c5d1SDavid du Colombier doalldirs(void)
1723e12c5d1SDavid du Colombier {
1739a747e4fSDavid du Colombier 	Dir *db;
1743e12c5d1SDavid du Colombier 	int fd;
1753e12c5d1SDavid du Colombier 	long i, n;
1763e12c5d1SDavid du Colombier 
1777dd7cddfSDavid du Colombier 
1783e12c5d1SDavid du Colombier 	fd = open(".", OREAD);
1793e12c5d1SDavid du Colombier 	if(fd == -1){
1803e12c5d1SDavid du Colombier 		warning("reading %s", root);
1813e12c5d1SDavid du Colombier 		return;
1823e12c5d1SDavid du Colombier 	}
1839a747e4fSDavid du Colombier 	n = sysdirreadall(fd, &db);
1849a747e4fSDavid du Colombier 	if(n > 0){
1853e12c5d1SDavid du Colombier 		for(i=0; i<n; i++){
1869a747e4fSDavid du Colombier 			if(db[i].qid.type & QTDIR){
1873e12c5d1SDavid du Colombier 				if(emptydir(db[i].name))
1883e12c5d1SDavid du Colombier 					continue;
1897dd7cddfSDavid du Colombier 				switch(forkltd()){
1903e12c5d1SDavid du Colombier 				case -1:
1917dd7cddfSDavid du Colombier 					syslog(0, runqlog, "out of procs");
1927dd7cddfSDavid du Colombier 					doload(0);
1937dd7cddfSDavid du Colombier 					exits(0);
1943e12c5d1SDavid du Colombier 				case 0:
1957dd7cddfSDavid du Colombier 					if(sysdetach() < 0)
1967dd7cddfSDavid du Colombier 						error("%r", 0);
1973e12c5d1SDavid du Colombier 					dodir(db[i].name);
1983e12c5d1SDavid du Colombier 					exits(0);
1993e12c5d1SDavid du Colombier 				default:
2003e12c5d1SDavid du Colombier 					break;
2013e12c5d1SDavid du Colombier 				}
2023e12c5d1SDavid du Colombier 			}
2033e12c5d1SDavid du Colombier 		}
2049a747e4fSDavid du Colombier 		free(db);
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 	close(fd);
2073e12c5d1SDavid du Colombier }
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier /*
2103e12c5d1SDavid du Colombier  *  cd to a user directory and run it
2113e12c5d1SDavid du Colombier  */
2123e12c5d1SDavid du Colombier void
2133e12c5d1SDavid du Colombier dodir(char *name)
2143e12c5d1SDavid du Colombier {
2157dd7cddfSDavid du Colombier 	curdir = name;
2167dd7cddfSDavid du Colombier 
2173e12c5d1SDavid du Colombier 	if(chdir(name) < 0){
2183e12c5d1SDavid du Colombier 		warning("cd to %s", name);
2193e12c5d1SDavid du Colombier 		return;
2203e12c5d1SDavid du Colombier 	}
2213e12c5d1SDavid du Colombier 	if(debug)
2223e12c5d1SDavid du Colombier 		fprint(2, "running %s\n", name);
2233e12c5d1SDavid du Colombier 	rundir(name);
2243e12c5d1SDavid du Colombier 	chdir("..");
2253e12c5d1SDavid du Colombier }
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier /*
2283e12c5d1SDavid du Colombier  *  run the current directory
2293e12c5d1SDavid du Colombier  */
2303e12c5d1SDavid du Colombier void
2313e12c5d1SDavid du Colombier rundir(char *name)
2323e12c5d1SDavid du Colombier {
2333e12c5d1SDavid du Colombier 	int fd;
234219b2ee8SDavid du Colombier 	long i;
2353e12c5d1SDavid du Colombier 
2367dd7cddfSDavid du Colombier 	if(aflag && sflag)
2377dd7cddfSDavid du Colombier 		fd = sysopenlocked(".", OREAD);
2387dd7cddfSDavid du Colombier 	else
2393e12c5d1SDavid du Colombier 		fd = open(".", OREAD);
2403e12c5d1SDavid du Colombier 	if(fd == -1){
2413e12c5d1SDavid du Colombier 		warning("reading %s", name);
2423e12c5d1SDavid du Colombier 		return;
2433e12c5d1SDavid du Colombier 	}
2449a747e4fSDavid du Colombier 	nfiles = sysdirreadall(fd, &dirbuf);
2459a747e4fSDavid du Colombier 	if(nfiles > 0){
246219b2ee8SDavid du Colombier 		for(i=0; i<nfiles; i++){
247219b2ee8SDavid du Colombier 			if(dirbuf[i].name[0]!='C' || dirbuf[i].name[1]!='.')
248219b2ee8SDavid du Colombier 				continue;
249219b2ee8SDavid du Colombier 			dofile(&dirbuf[i]);
250219b2ee8SDavid du Colombier 		}
2519a747e4fSDavid du Colombier 		free(dirbuf);
2529a747e4fSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 	if(aflag && sflag)
2547dd7cddfSDavid du Colombier 		sysunlockfile(fd);
2557dd7cddfSDavid du Colombier 	else
2567dd7cddfSDavid du Colombier 		close(fd);
257219b2ee8SDavid du Colombier }
258219b2ee8SDavid du Colombier 
259219b2ee8SDavid du Colombier /*
260219b2ee8SDavid du Colombier  *  free files matching name in the current directory
261219b2ee8SDavid du Colombier  */
262219b2ee8SDavid du Colombier void
263219b2ee8SDavid du Colombier remmatch(char *name)
264219b2ee8SDavid du Colombier {
265219b2ee8SDavid du Colombier 	long i;
266219b2ee8SDavid du Colombier 
2677dd7cddfSDavid du Colombier 	syslog(0, runqlog, "removing %s/%s", curdir, name);
2687dd7cddfSDavid du Colombier 
269219b2ee8SDavid du Colombier 	for(i=0; i<nfiles; i++){
270219b2ee8SDavid du Colombier 		if(strcmp(&dirbuf[i].name[1], &name[1]) == 0)
2717dd7cddfSDavid du Colombier 			sysremove(dirbuf[i].name);
272219b2ee8SDavid du Colombier 	}
273219b2ee8SDavid du Colombier 
274219b2ee8SDavid du Colombier 	/* error file (may have) appeared after we read the directory */
2757dd7cddfSDavid du Colombier 	/* stomp on data file in case of phase error */
2767dd7cddfSDavid du Colombier 	sysremove(file(name, 'D'));
2777dd7cddfSDavid du Colombier 	sysremove(file(name, 'E'));
2783e12c5d1SDavid du Colombier }
2793e12c5d1SDavid du Colombier 
2803e12c5d1SDavid du Colombier /*
2813e12c5d1SDavid du Colombier  *  try a message
2823e12c5d1SDavid du Colombier  */
2833e12c5d1SDavid du Colombier void
2843e12c5d1SDavid du Colombier dofile(Dir *dp)
2853e12c5d1SDavid du Colombier {
2869a747e4fSDavid du Colombier 	Dir *d;
2879a747e4fSDavid du Colombier 	int dfd, ac, dtime, efd, pid, i, etime;
2887dd7cddfSDavid du Colombier 	char *buf, *cp, **av;
2899a747e4fSDavid du Colombier 	Waitmsg *wm;
2907dd7cddfSDavid du Colombier 	Biobuf *b;
2913e12c5d1SDavid du Colombier 
2923e12c5d1SDavid du Colombier 	if(debug)
2933e12c5d1SDavid du Colombier 		fprint(2, "dofile %s\n", dp->name);
2943e12c5d1SDavid du Colombier 	/*
29514414594SDavid du Colombier 	 *  if no data file or empty control or data file, just clean up
29614414594SDavid du Colombier 	 *  the empty control file must be 15 minutes old, to minimize the
29714414594SDavid du Colombier 	 *  chance of a race.
2983e12c5d1SDavid du Colombier 	 */
2999a747e4fSDavid du Colombier 	d = dirstat(file(dp->name, 'D'));
3009a747e4fSDavid du Colombier 	if(d == nil){
3017dd7cddfSDavid du Colombier 		syslog(0, runqlog, "no data file for %s", dp->name);
302219b2ee8SDavid du Colombier 		remmatch(dp->name);
3033e12c5d1SDavid du Colombier 		return;
3043e12c5d1SDavid du Colombier 	}
30514414594SDavid du Colombier 	if(dp->length == 0){
30614414594SDavid du Colombier 		if(time(0)-dp->mtime > 15*60){
30714414594SDavid du Colombier 			syslog(0, runqlog, "empty ctl file for %s", dp->name);
30814414594SDavid du Colombier 			remmatch(dp->name);
30914414594SDavid du Colombier 		}
31014414594SDavid du Colombier 		return;
31114414594SDavid du Colombier 	}
3129a747e4fSDavid du Colombier 	dtime = d->mtime;
3139a747e4fSDavid du Colombier 	free(d);
3143e12c5d1SDavid du Colombier 
3153e12c5d1SDavid du Colombier 	/*
3163e12c5d1SDavid du Colombier 	 *  retry times depend on the age of the errors file
3173e12c5d1SDavid du Colombier 	 */
3189a747e4fSDavid du Colombier 	if(!Eflag && (d = dirstat(file(dp->name, 'E'))) != nil){
3199a747e4fSDavid du Colombier 		etime = d->mtime;
3209a747e4fSDavid du Colombier 		free(d);
3219a747e4fSDavid du Colombier 		if(etime - dtime < 60*60){
3223e12c5d1SDavid du Colombier 			/* up to the first hour, try every 15 minutes */
3239a747e4fSDavid du Colombier 			if(time(0) - etime < 15*60)
3243e12c5d1SDavid du Colombier 				return;
3253e12c5d1SDavid du Colombier 		} else {
3263e12c5d1SDavid du Colombier 			/* after the first hour, try once an hour */
3279a747e4fSDavid du Colombier 			if(time(0) - etime < 60*60)
3283e12c5d1SDavid du Colombier 				return;
3293e12c5d1SDavid du Colombier 		}
3309a747e4fSDavid du Colombier 
3313e12c5d1SDavid du Colombier 	}
3323e12c5d1SDavid du Colombier 
3333e12c5d1SDavid du Colombier 	/*
3343e12c5d1SDavid du Colombier 	 *  open control and data
3353e12c5d1SDavid du Colombier 	 */
3367dd7cddfSDavid du Colombier 	b = sysopen(file(dp->name, 'C'), "rl", 0660);
3377dd7cddfSDavid du Colombier 	if(b == 0) {
3387dd7cddfSDavid du Colombier 		if(debug)
3397dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'C'));
3403e12c5d1SDavid du Colombier 		return;
3417dd7cddfSDavid du Colombier 	}
3423e12c5d1SDavid du Colombier 	dfd = open(file(dp->name, 'D'), OREAD);
3433e12c5d1SDavid du Colombier 	if(dfd < 0){
3447dd7cddfSDavid du Colombier 		if(debug)
3457dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'D'));
3467dd7cddfSDavid du Colombier 		Bterm(b);
3477dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3483e12c5d1SDavid du Colombier 		return;
3493e12c5d1SDavid du Colombier 	}
3503e12c5d1SDavid du Colombier 
3513e12c5d1SDavid du Colombier 	/*
3523e12c5d1SDavid du Colombier 	 *  make arg list
3533e12c5d1SDavid du Colombier 	 *	- read args into (malloc'd) buffer
3543e12c5d1SDavid du Colombier 	 *	- malloc a vector and copy pointers to args into it
3553e12c5d1SDavid du Colombier 	 */
3563e12c5d1SDavid du Colombier 	buf = malloc(dp->length+1);
3577dd7cddfSDavid du Colombier 	if(buf == 0){
3587dd7cddfSDavid du Colombier 		warning("buffer allocation", 0);
3597dd7cddfSDavid du Colombier 		Bterm(b);
3607dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3617dd7cddfSDavid du Colombier 		close(dfd);
3627dd7cddfSDavid du Colombier 		return;
3637dd7cddfSDavid du Colombier 	}
3647dd7cddfSDavid du Colombier 	if(Bread(b, buf, dp->length) != dp->length){
3653e12c5d1SDavid du Colombier 		warning("reading control file %s\n", dp->name);
3667dd7cddfSDavid du Colombier 		Bterm(b);
3677dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3687dd7cddfSDavid du Colombier 		close(dfd);
3697dd7cddfSDavid du Colombier 		free(buf);
3707dd7cddfSDavid du Colombier 		return;
3713e12c5d1SDavid du Colombier 	}
3723e12c5d1SDavid du Colombier 	buf[dp->length] = 0;
3737dd7cddfSDavid du Colombier 	av = malloc(2*sizeof(char*));
3747dd7cddfSDavid du Colombier 	if(av == 0){
3757dd7cddfSDavid du Colombier 		warning("argv allocation", 0);
3767dd7cddfSDavid du Colombier 		close(dfd);
3777dd7cddfSDavid du Colombier 		free(buf);
3787dd7cddfSDavid du Colombier 		Bterm(b);
3797dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3807dd7cddfSDavid du Colombier 		return;
3813e12c5d1SDavid du Colombier 	}
3823e12c5d1SDavid du Colombier 	for(ac = 1, cp = buf; *cp; ac++){
3833e12c5d1SDavid du Colombier 		while(isspace(*cp))
3843e12c5d1SDavid du Colombier 			*cp++ = 0;
3857dd7cddfSDavid du Colombier 		if(*cp == 0)
3867dd7cddfSDavid du Colombier 			break;
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier 		av = realloc(av, (ac+2)*sizeof(char*));
3897dd7cddfSDavid du Colombier 		if(av == 0){
3907dd7cddfSDavid du Colombier 			warning("argv allocation", 0);
3917dd7cddfSDavid du Colombier 			close(dfd);
3927dd7cddfSDavid du Colombier 			free(buf);
3937dd7cddfSDavid du Colombier 			Bterm(b);
3947dd7cddfSDavid du Colombier 			sysunlockfile(Bfildes(b));
3957dd7cddfSDavid du Colombier 			return;
3967dd7cddfSDavid du Colombier 		}
3973e12c5d1SDavid du Colombier 		av[ac] = cp;
3987dd7cddfSDavid du Colombier 		while(*cp && !isspace(*cp)){
3997dd7cddfSDavid du Colombier 			if(*cp++ == '"'){
4003e12c5d1SDavid du Colombier 				while(*cp && *cp != '"')
4013e12c5d1SDavid du Colombier 					cp++;
4023e12c5d1SDavid du Colombier 				if(*cp)
4033e12c5d1SDavid du Colombier 					cp++;
4043e12c5d1SDavid du Colombier 			}
4053e12c5d1SDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier 	av[0] = cmd;
4083e12c5d1SDavid du Colombier 	av[ac] = 0;
4093e12c5d1SDavid du Colombier 
41080ee5cbfSDavid du Colombier 	if(!Eflag &&time(0) - dtime > giveup){
4117dd7cddfSDavid du Colombier 		if(returnmail(av, dp->name, "Giveup") == 0)
412219b2ee8SDavid du Colombier 			remmatch(dp->name);
4137dd7cddfSDavid du Colombier 		else {
4147dd7cddfSDavid du Colombier 			if(time(0) - dtime < giveup + 2*60*60)
4157dd7cddfSDavid du Colombier 				logit("returnmail failed", dp->name, av);
4167dd7cddfSDavid du Colombier 			if(time(0) - dtime > giveup + 24*60*60)
4177dd7cddfSDavid du Colombier 				remmatch(dp->name);
4187dd7cddfSDavid du Colombier 		}
4197dd7cddfSDavid du Colombier 		goto done;
4207dd7cddfSDavid du Colombier 	}
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	for(i = 0; i < nbad; i++){
4237dd7cddfSDavid du Colombier 		if(strcmp(av[3], badsys[i]) == 0)
4247dd7cddfSDavid du Colombier 			goto done;
425219b2ee8SDavid du Colombier 	}
426219b2ee8SDavid du Colombier 
4273e12c5d1SDavid du Colombier 	/*
4283e12c5d1SDavid du Colombier 	 *  transfer
4293e12c5d1SDavid du Colombier 	 */
4307dd7cddfSDavid du Colombier 	pid = fork();
4317dd7cddfSDavid du Colombier 	switch(pid){
4323e12c5d1SDavid du Colombier 	case -1:
4337dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4347dd7cddfSDavid du Colombier 		syslog(0, runqlog, "out of procs");
4357dd7cddfSDavid du Colombier 		exits(0);
4363e12c5d1SDavid du Colombier 	case 0:
4377dd7cddfSDavid du Colombier 		if(debug) {
4387dd7cddfSDavid du Colombier 			fprint(2, "Starting %s", cmd);
4397dd7cddfSDavid du Colombier 			for(ac = 0; av[ac]; ac++)
4407dd7cddfSDavid du Colombier 				fprint(2, " %s", av[ac]);
4417dd7cddfSDavid du Colombier 			fprint(2, "\n");
4427dd7cddfSDavid du Colombier 		}
4437dd7cddfSDavid du Colombier 		logit("execing", dp->name, av);
4443e12c5d1SDavid du Colombier 		close(0);
4453e12c5d1SDavid du Colombier 		dup(dfd, 0);
4467dd7cddfSDavid du Colombier 		close(dfd);
4473e12c5d1SDavid du Colombier 		close(2);
4487dd7cddfSDavid du Colombier 		efd = open(file(dp->name, 'E'), OWRITE);
4493e12c5d1SDavid du Colombier 		if(efd < 0)
4503e12c5d1SDavid du Colombier 			efd = create(file(dp->name, 'E'), OWRITE, 0664);
4513e12c5d1SDavid du Colombier 		if(efd < 0)
4523e12c5d1SDavid du Colombier 			exits("");
4533e12c5d1SDavid du Colombier 		seek(efd, 0, 2);
4543e12c5d1SDavid du Colombier 		exec(cmd, av);
4553e12c5d1SDavid du Colombier 		error("can't exec %s", cmd);
4563e12c5d1SDavid du Colombier 		break;
4573e12c5d1SDavid du Colombier 	default:
4589a747e4fSDavid du Colombier 		for(;;){
4599a747e4fSDavid du Colombier 			wm = wait();
4609a747e4fSDavid du Colombier 			if(wm == nil)
4619a747e4fSDavid du Colombier 				error("wait failed: %r", "");
4629a747e4fSDavid du Colombier 			if(wm->pid == pid)
4639a747e4fSDavid du Colombier 				break;
4649a747e4fSDavid du Colombier 			free(wm);
4659a747e4fSDavid du Colombier 		}
4669a747e4fSDavid du Colombier 
4679a747e4fSDavid du Colombier 		if(wm->msg[0]){
4683e12c5d1SDavid du Colombier 			if(debug)
4699a747e4fSDavid du Colombier 				fprint(2, "[%d] wm->msg == %s\n", getpid(), wm->msg);
4709a747e4fSDavid du Colombier 			if(strstr(wm->msg, "Retry")==0){
4713e12c5d1SDavid du Colombier 				/* return the message and remove it */
4729a747e4fSDavid du Colombier 				if(returnmail(av, dp->name, wm->msg) == 0)
473219b2ee8SDavid du Colombier 					remmatch(dp->name);
4743e12c5d1SDavid du Colombier 			} else {
4757dd7cddfSDavid du Colombier 				/* add sys to bad list and try again later */
4767dd7cddfSDavid du Colombier 				nbad++;
4777dd7cddfSDavid du Colombier 				badsys = realloc(badsys, nbad*sizeof(char*));
4787dd7cddfSDavid du Colombier 				badsys[nbad-1] = strdup(av[3]);
4793e12c5d1SDavid du Colombier 			}
4803e12c5d1SDavid du Colombier 		} else {
4813e12c5d1SDavid du Colombier 			/* it worked remove the message */
482219b2ee8SDavid du Colombier 			remmatch(dp->name);
4833e12c5d1SDavid du Colombier 		}
4849a747e4fSDavid du Colombier 		free(wm);
4853e12c5d1SDavid du Colombier 
4863e12c5d1SDavid du Colombier 	}
4877dd7cddfSDavid du Colombier done:
4887dd7cddfSDavid du Colombier 	Bterm(b);
4897dd7cddfSDavid du Colombier 	sysunlockfile(Bfildes(b));
4907dd7cddfSDavid du Colombier 	free(buf);
4917dd7cddfSDavid du Colombier 	free(av);
4923e12c5d1SDavid du Colombier 	close(dfd);
4933e12c5d1SDavid du Colombier }
4943e12c5d1SDavid du Colombier 
4957dd7cddfSDavid du Colombier 
4963e12c5d1SDavid du Colombier /*
4973e12c5d1SDavid du Colombier  *  return a name starting with the given character
4983e12c5d1SDavid du Colombier  */
4993e12c5d1SDavid du Colombier char*
5003e12c5d1SDavid du Colombier file(char *name, char type)
5013e12c5d1SDavid du Colombier {
5029a747e4fSDavid du Colombier 	static char nname[Elemlen+1];
5033e12c5d1SDavid du Colombier 
5049a747e4fSDavid du Colombier 	strncpy(nname, name, Elemlen);
5059a747e4fSDavid du Colombier 	nname[Elemlen] = 0;
5063e12c5d1SDavid du Colombier 	nname[0] = type;
5073e12c5d1SDavid du Colombier 	return nname;
5083e12c5d1SDavid du Colombier }
5093e12c5d1SDavid du Colombier 
5103e12c5d1SDavid du Colombier /*
5113e12c5d1SDavid du Colombier  *  send back the mail with an error message
5123e12c5d1SDavid du Colombier  *
5133e12c5d1SDavid du Colombier  *  return 0 if successful
5143e12c5d1SDavid du Colombier  */
5153e12c5d1SDavid du Colombier int
5163e12c5d1SDavid du Colombier returnmail(char **av, char *name, char *msg)
5173e12c5d1SDavid du Colombier {
5183e12c5d1SDavid du Colombier 	int pfd[2];
5199a747e4fSDavid du Colombier 	Waitmsg *wm;
5203e12c5d1SDavid du Colombier 	int fd;
5213e12c5d1SDavid du Colombier 	char buf[256];
5223e12c5d1SDavid du Colombier 	int i;
5233e12c5d1SDavid du Colombier 	long n;
5247dd7cddfSDavid du Colombier 	String *s;
5257dd7cddfSDavid du Colombier 	char *sender;
5263e12c5d1SDavid du Colombier 
5277dd7cddfSDavid du Colombier 	if(av[1] == 0 || av[2] == 0){
5287dd7cddfSDavid du Colombier 		logit("runq - dumping bad file", name, av);
5297dd7cddfSDavid du Colombier 		return 0;
5307dd7cddfSDavid du Colombier 	}
5317dd7cddfSDavid du Colombier 
5327dd7cddfSDavid du Colombier 	s = unescapespecial(s_copy(av[2]));
5337dd7cddfSDavid du Colombier 	sender = s_to_c(s);
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier 	if(!returnable(sender) || strcmp(sender, "postmaster") == 0) {
5367dd7cddfSDavid du Colombier 		logit("runq - dumping p to p mail", name, av);
5377dd7cddfSDavid du Colombier 		return 0;
5387dd7cddfSDavid du Colombier 	}
5393e12c5d1SDavid du Colombier 
5403e12c5d1SDavid du Colombier 	if(pipe(pfd) < 0)
5413e12c5d1SDavid du Colombier 		return -1;
5423e12c5d1SDavid du Colombier 
5437dd7cddfSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFENVG)){
5443e12c5d1SDavid du Colombier 	case -1:
5453e12c5d1SDavid du Colombier 		return -1;
5463e12c5d1SDavid du Colombier 	case 0:
5477dd7cddfSDavid du Colombier 		logit("returning", name, av);
5483e12c5d1SDavid du Colombier 		close(pfd[1]);
5493e12c5d1SDavid du Colombier 		close(0);
5503e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
5513e12c5d1SDavid du Colombier 		close(pfd[0]);
5527dd7cddfSDavid du Colombier 		putenv("upasname", "/dev/null");
5537dd7cddfSDavid du Colombier 		snprint(buf, sizeof(buf), "%s/send", UPASBIN);
5547dd7cddfSDavid du Colombier 		execl(buf, "send", "-r", sender, 0);
5553e12c5d1SDavid du Colombier 		error("can't exec", 0);
5563e12c5d1SDavid du Colombier 		break;
5573e12c5d1SDavid du Colombier 	default:
5583e12c5d1SDavid du Colombier 		break;
5593e12c5d1SDavid du Colombier 	}
5603e12c5d1SDavid du Colombier 
5613e12c5d1SDavid du Colombier 	close(pfd[0]);
562*3ff48bf5SDavid du Colombier 	fprint(pfd[1], "\n");	/* get out of headers */
5633e12c5d1SDavid du Colombier 	if(av[1]){
5647dd7cddfSDavid du Colombier 		fprint(pfd[1], "Your request ``%.20s ", av[1]);
5653e12c5d1SDavid du Colombier 		for(n = 3; av[n]; n++)
5663e12c5d1SDavid du Colombier 			fprint(pfd[1], "%s ", av[n]);
5673e12c5d1SDavid du Colombier 	}
5683e12c5d1SDavid du Colombier 	fprint(pfd[1], "'' failed (code %s).\nThe symptom was:\n\n", msg);
5693e12c5d1SDavid du Colombier 	fd = open(file(name, 'E'), OREAD);
5703e12c5d1SDavid du Colombier 	if(fd >= 0){
5713e12c5d1SDavid du Colombier 		for(;;){
5723e12c5d1SDavid du Colombier 			n = read(fd, buf, sizeof(buf));
5733e12c5d1SDavid du Colombier 			if(n <= 0)
5743e12c5d1SDavid du Colombier 				break;
5753e12c5d1SDavid du Colombier 			if(write(pfd[1], buf, n) != n){
5763e12c5d1SDavid du Colombier 				close(fd);
5773e12c5d1SDavid du Colombier 				goto out;
5783e12c5d1SDavid du Colombier 			}
5793e12c5d1SDavid du Colombier 		}
5803e12c5d1SDavid du Colombier 		close(fd);
5813e12c5d1SDavid du Colombier 	}
5823e12c5d1SDavid du Colombier 	fprint(pfd[1], "\nThe request began:\n\n");
5833e12c5d1SDavid du Colombier 	fd = open(file(name, 'D'), OREAD);
5843e12c5d1SDavid du Colombier 	if(fd >= 0){
5853e12c5d1SDavid du Colombier 		for(i=0; i<4*16; i++){
5863e12c5d1SDavid du Colombier 			n = read(fd, buf, sizeof(buf));
5873e12c5d1SDavid du Colombier 			if(n <= 0)
5883e12c5d1SDavid du Colombier 				break;
5893e12c5d1SDavid du Colombier 			if(write(pfd[1], buf, n) != n){
5903e12c5d1SDavid du Colombier 				close(fd);
5913e12c5d1SDavid du Colombier 				goto out;
5923e12c5d1SDavid du Colombier 			}
5933e12c5d1SDavid du Colombier 		}
5943e12c5d1SDavid du Colombier 		close(fd);
5953e12c5d1SDavid du Colombier 	}
5963e12c5d1SDavid du Colombier 	close(pfd[1]);
5973e12c5d1SDavid du Colombier out:
5989a747e4fSDavid du Colombier 	wm = wait();
5999a747e4fSDavid du Colombier 	if(wm == nil)
6009a747e4fSDavid du Colombier 		return -1;
6019a747e4fSDavid du Colombier 	i = wm->msg[0] ? -1 : 0;
6029a747e4fSDavid du Colombier 	free(wm);
6039a747e4fSDavid du Colombier 	return i;
6043e12c5d1SDavid du Colombier }
6053e12c5d1SDavid du Colombier 
6063e12c5d1SDavid du Colombier /*
6073e12c5d1SDavid du Colombier  *  print a warning and continue
6083e12c5d1SDavid du Colombier  */
6093e12c5d1SDavid du Colombier void
6103e12c5d1SDavid du Colombier warning(char *f, void *a)
6113e12c5d1SDavid du Colombier {
6123e12c5d1SDavid du Colombier 	char err[65];
6133e12c5d1SDavid du Colombier 	char buf[256];
6143e12c5d1SDavid du Colombier 
6159a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6167dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6173e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6183e12c5d1SDavid du Colombier }
6193e12c5d1SDavid du Colombier 
6203e12c5d1SDavid du Colombier /*
6213e12c5d1SDavid du Colombier  *  print an error and die
6223e12c5d1SDavid du Colombier  */
6233e12c5d1SDavid du Colombier void
6243e12c5d1SDavid du Colombier error(char *f, void *a)
6253e12c5d1SDavid du Colombier {
6269a747e4fSDavid du Colombier 	char err[Errlen];
6273e12c5d1SDavid du Colombier 	char buf[256];
6283e12c5d1SDavid du Colombier 
6299a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6307dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6313e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6323e12c5d1SDavid du Colombier 	exits(buf);
6333e12c5d1SDavid du Colombier }
6343e12c5d1SDavid du Colombier 
6357dd7cddfSDavid du Colombier void
6367dd7cddfSDavid du Colombier logit(char *msg, char *file, char **av)
6377dd7cddfSDavid du Colombier {
6387dd7cddfSDavid du Colombier 	int n, m;
6397dd7cddfSDavid du Colombier 	char buf[256];
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier 	n = snprint(buf, sizeof(buf), "%s/%s: %s", curdir, file, msg);
6427dd7cddfSDavid du Colombier 	for(; *av; av++){
6437dd7cddfSDavid du Colombier 		m = strlen(*av);
6447dd7cddfSDavid du Colombier 		if(n + m + 4 > sizeof(buf))
6457dd7cddfSDavid du Colombier 			break;
6467dd7cddfSDavid du Colombier 		sprint(buf + n, " '%s'", *av);
6477dd7cddfSDavid du Colombier 		n += m + 3;
6487dd7cddfSDavid du Colombier 	}
6499a747e4fSDavid du Colombier 	syslog(0, runqlog, "%s", buf);
6507dd7cddfSDavid du Colombier }
6517dd7cddfSDavid du Colombier 
6527dd7cddfSDavid du Colombier char *loadfile = ".runqload";
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier /*
6557dd7cddfSDavid du Colombier  *  load balancing
6567dd7cddfSDavid du Colombier  */
6577dd7cddfSDavid du Colombier void
6587dd7cddfSDavid du Colombier doload(int start)
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier 	int fd;
6617dd7cddfSDavid du Colombier 	char buf[32];
6627dd7cddfSDavid du Colombier 	int i, n;
6637dd7cddfSDavid du Colombier 	Mlock *l;
6649a747e4fSDavid du Colombier 	Dir *d;
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier 	if(load <= 0)
6677dd7cddfSDavid du Colombier 		return;
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier 	if(chdir(root) < 0){
6707dd7cddfSDavid du Colombier 		load = 0;
6717dd7cddfSDavid du Colombier 		return;
6727dd7cddfSDavid du Colombier 	}
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	l = syslock(loadfile);
6757dd7cddfSDavid du Colombier 	fd = open(loadfile, ORDWR);
6767dd7cddfSDavid du Colombier 	if(fd < 0){
6777dd7cddfSDavid du Colombier 		fd = create(loadfile, 0666, ORDWR);
6787dd7cddfSDavid du Colombier 		if(fd < 0){
6797dd7cddfSDavid du Colombier 			load = 0;
6807dd7cddfSDavid du Colombier 			sysunlock(l);
6817dd7cddfSDavid du Colombier 			return;
6827dd7cddfSDavid du Colombier 		}
6837dd7cddfSDavid du Colombier 	}
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	/* get current load */
6867dd7cddfSDavid du Colombier 	i = 0;
6877dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof(buf)-1);
6887dd7cddfSDavid du Colombier 	if(n >= 0){
6897dd7cddfSDavid du Colombier 		buf[n] = 0;
6907dd7cddfSDavid du Colombier 		i = atoi(buf);
6917dd7cddfSDavid du Colombier 	}
6927dd7cddfSDavid du Colombier 	if(i < 0)
6937dd7cddfSDavid du Colombier 		i = 0;
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 	/* ignore load if file hasn't been changed in 30 minutes */
6969a747e4fSDavid du Colombier 	d = dirfstat(fd);
6979a747e4fSDavid du Colombier 	if(d != nil){
6989a747e4fSDavid du Colombier 		if(d->mtime + 30*60 < time(0))
6997dd7cddfSDavid du Colombier 			i = 0;
7009a747e4fSDavid du Colombier 		free(d);
7019a747e4fSDavid du Colombier 	}
7027dd7cddfSDavid du Colombier 
7037dd7cddfSDavid du Colombier 	/* if load already too high, give up */
7047dd7cddfSDavid du Colombier 	if(start && i >= load){
7057dd7cddfSDavid du Colombier 		sysunlock(l);
7067dd7cddfSDavid du Colombier 		exits(0);
7077dd7cddfSDavid du Colombier 	}
7087dd7cddfSDavid du Colombier 
7097dd7cddfSDavid du Colombier 	/* increment/decrement load */
7107dd7cddfSDavid du Colombier 	if(start)
7117dd7cddfSDavid du Colombier 		i++;
7127dd7cddfSDavid du Colombier 	else
7137dd7cddfSDavid du Colombier 		i--;
7147dd7cddfSDavid du Colombier 	seek(fd, 0, 0);
7157dd7cddfSDavid du Colombier 	fprint(fd, "%d\n", i);
7167dd7cddfSDavid du Colombier 	sysunlock(l);
7177dd7cddfSDavid du Colombier 	close(fd);
7187dd7cddfSDavid du Colombier }
719