xref: /plan9/sys/src/cmd/upas/q/runq.c (revision f19e7b749ec99577072cd8e44030fe810f42c7ad)
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
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
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
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
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
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
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
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
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 *
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
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);
3599a747e4fSDavid du Colombier 		if(etime - dtime < 60*60){
3603e12c5d1SDavid du Colombier 			/* up to the first hour, try every 15 minutes */
3619a747e4fSDavid du Colombier 			if(time(0) - etime < 15*60)
3623e12c5d1SDavid du Colombier 				return;
3633e12c5d1SDavid du Colombier 		} else {
3643e12c5d1SDavid du Colombier 			/* after the first hour, try once an hour */
3659a747e4fSDavid du Colombier 			if(time(0) - etime < 60*60)
3663e12c5d1SDavid du Colombier 				return;
3673e12c5d1SDavid du Colombier 		}
3689a747e4fSDavid du Colombier 
3693e12c5d1SDavid du Colombier 	}
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier 	/*
3723e12c5d1SDavid du Colombier 	 *  open control and data
3733e12c5d1SDavid du Colombier 	 */
3747dd7cddfSDavid du Colombier 	b = sysopen(file(dp->name, 'C'), "rl", 0660);
3757dd7cddfSDavid du Colombier 	if(b == 0) {
3767dd7cddfSDavid du Colombier 		if(debug)
3777dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'C'));
3783e12c5d1SDavid du Colombier 		return;
3797dd7cddfSDavid du Colombier 	}
3803e12c5d1SDavid du Colombier 	dfd = open(file(dp->name, 'D'), OREAD);
3813e12c5d1SDavid du Colombier 	if(dfd < 0){
3827dd7cddfSDavid du Colombier 		if(debug)
3837dd7cddfSDavid du Colombier 			fprint(2, "can't open %s: %r\n", file(dp->name, 'D'));
3847dd7cddfSDavid du Colombier 		Bterm(b);
3857dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3863e12c5d1SDavid du Colombier 		return;
3873e12c5d1SDavid du Colombier 	}
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier 	/*
3903e12c5d1SDavid du Colombier 	 *  make arg list
3913e12c5d1SDavid du Colombier 	 *	- read args into (malloc'd) buffer
3923e12c5d1SDavid du Colombier 	 *	- malloc a vector and copy pointers to args into it
3933e12c5d1SDavid du Colombier 	 */
3943e12c5d1SDavid du Colombier 	buf = malloc(dp->length+1);
3957dd7cddfSDavid du Colombier 	if(buf == 0){
3967dd7cddfSDavid du Colombier 		warning("buffer allocation", 0);
3977dd7cddfSDavid du Colombier 		Bterm(b);
3987dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
3997dd7cddfSDavid du Colombier 		close(dfd);
4007dd7cddfSDavid du Colombier 		return;
4017dd7cddfSDavid du Colombier 	}
4027dd7cddfSDavid du Colombier 	if(Bread(b, buf, dp->length) != dp->length){
4033e12c5d1SDavid du Colombier 		warning("reading control file %s\n", dp->name);
4047dd7cddfSDavid du Colombier 		Bterm(b);
4057dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4067dd7cddfSDavid du Colombier 		close(dfd);
4077dd7cddfSDavid du Colombier 		free(buf);
4087dd7cddfSDavid du Colombier 		return;
4093e12c5d1SDavid du Colombier 	}
4103e12c5d1SDavid du Colombier 	buf[dp->length] = 0;
4117dd7cddfSDavid du Colombier 	av = malloc(2*sizeof(char*));
4127dd7cddfSDavid du Colombier 	if(av == 0){
4137dd7cddfSDavid du Colombier 		warning("argv allocation", 0);
4147dd7cddfSDavid du Colombier 		close(dfd);
4157dd7cddfSDavid du Colombier 		free(buf);
4167dd7cddfSDavid du Colombier 		Bterm(b);
4177dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4187dd7cddfSDavid du Colombier 		return;
4193e12c5d1SDavid du Colombier 	}
4203e12c5d1SDavid du Colombier 	for(ac = 1, cp = buf; *cp; ac++){
4213e12c5d1SDavid du Colombier 		while(isspace(*cp))
4223e12c5d1SDavid du Colombier 			*cp++ = 0;
4237dd7cddfSDavid du Colombier 		if(*cp == 0)
4247dd7cddfSDavid du Colombier 			break;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 		av = realloc(av, (ac+2)*sizeof(char*));
4277dd7cddfSDavid du Colombier 		if(av == 0){
4287dd7cddfSDavid du Colombier 			warning("argv allocation", 0);
4297dd7cddfSDavid du Colombier 			close(dfd);
4307dd7cddfSDavid du Colombier 			free(buf);
4317dd7cddfSDavid du Colombier 			Bterm(b);
4327dd7cddfSDavid du Colombier 			sysunlockfile(Bfildes(b));
4337dd7cddfSDavid du Colombier 			return;
4347dd7cddfSDavid du Colombier 		}
4353e12c5d1SDavid du Colombier 		av[ac] = cp;
4367dd7cddfSDavid du Colombier 		while(*cp && !isspace(*cp)){
4377dd7cddfSDavid du Colombier 			if(*cp++ == '"'){
4383e12c5d1SDavid du Colombier 				while(*cp && *cp != '"')
4393e12c5d1SDavid du Colombier 					cp++;
4403e12c5d1SDavid du Colombier 				if(*cp)
4413e12c5d1SDavid du Colombier 					cp++;
4423e12c5d1SDavid du Colombier 			}
4433e12c5d1SDavid du Colombier 		}
4447dd7cddfSDavid du Colombier 	}
4457dd7cddfSDavid du Colombier 	av[0] = cmd;
4463e12c5d1SDavid du Colombier 	av[ac] = 0;
4473e12c5d1SDavid du Colombier 
44880ee5cbfSDavid du Colombier 	if(!Eflag &&time(0) - dtime > giveup){
449ed250ae1SDavid du Colombier 		if(returnmail(av, dp->name, "Giveup") != 0)
4507dd7cddfSDavid du Colombier 			logit("returnmail failed", dp->name, av);
4517dd7cddfSDavid du Colombier 		remmatch(dp->name);
4527dd7cddfSDavid du Colombier 		goto done;
4537dd7cddfSDavid du Colombier 	}
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	for(i = 0; i < nbad; i++){
4567dd7cddfSDavid du Colombier 		if(strcmp(av[3], badsys[i]) == 0)
4577dd7cddfSDavid du Colombier 			goto done;
458219b2ee8SDavid du Colombier 	}
459219b2ee8SDavid du Colombier 
4603e12c5d1SDavid du Colombier 	/*
4614f281771SDavid du Colombier 	 * Ken's fs, for example, gives us 5 minutes of inactivity before
4624f281771SDavid du Colombier 	 * the lock goes stale, so we have to keep reading it.
4634f281771SDavid du Colombier  	 */
4644f281771SDavid du Colombier 	l = keeplockalive(file(dp->name, 'C'), Bfildes(b));
4654f281771SDavid du Colombier 
4664f281771SDavid du Colombier 	/*
4673e12c5d1SDavid du Colombier 	 *  transfer
4683e12c5d1SDavid du Colombier 	 */
4697dd7cddfSDavid du Colombier 	pid = fork();
4707dd7cddfSDavid du Colombier 	switch(pid){
4713e12c5d1SDavid du Colombier 	case -1:
4724f281771SDavid du Colombier 		sysunlock(l);
4737dd7cddfSDavid du Colombier 		sysunlockfile(Bfildes(b));
4747dd7cddfSDavid du Colombier 		syslog(0, runqlog, "out of procs");
4757dd7cddfSDavid du Colombier 		exits(0);
4763e12c5d1SDavid du Colombier 	case 0:
4777dd7cddfSDavid du Colombier 		if(debug) {
4787dd7cddfSDavid du Colombier 			fprint(2, "Starting %s", cmd);
4797dd7cddfSDavid du Colombier 			for(ac = 0; av[ac]; ac++)
4807dd7cddfSDavid du Colombier 				fprint(2, " %s", av[ac]);
4817dd7cddfSDavid du Colombier 			fprint(2, "\n");
4827dd7cddfSDavid du Colombier 		}
4837dd7cddfSDavid du Colombier 		logit("execing", dp->name, av);
4843e12c5d1SDavid du Colombier 		close(0);
4853e12c5d1SDavid du Colombier 		dup(dfd, 0);
4867dd7cddfSDavid du Colombier 		close(dfd);
4873e12c5d1SDavid du Colombier 		close(2);
4887dd7cddfSDavid du Colombier 		efd = open(file(dp->name, 'E'), OWRITE);
4892b7fd5adSDavid du Colombier 		if(efd < 0){
4902b7fd5adSDavid du Colombier 			if(debug) syslog(0, "runq", "open %s as %s: %r", file(dp->name,'E'), getuser());
4912b7fd5adSDavid du Colombier 			efd = create(file(dp->name, 'E'), OWRITE, 0666);
4922b7fd5adSDavid du Colombier 			if(efd < 0){
4932b7fd5adSDavid du Colombier 				if(debug) syslog(0, "runq", "create %s as %s: %r", file(dp->name, 'E'), getuser());
4942b7fd5adSDavid du Colombier 				exits("could not open error file - Retry");
4952b7fd5adSDavid du Colombier 			}
4962b7fd5adSDavid du Colombier 		}
4973e12c5d1SDavid du Colombier 		seek(efd, 0, 2);
4983e12c5d1SDavid du Colombier 		exec(cmd, av);
4993e12c5d1SDavid du Colombier 		error("can't exec %s", cmd);
5003e12c5d1SDavid du Colombier 		break;
5013e12c5d1SDavid du Colombier 	default:
5029a747e4fSDavid du Colombier 		for(;;){
5039a747e4fSDavid du Colombier 			wm = wait();
5049a747e4fSDavid du Colombier 			if(wm == nil)
5059a747e4fSDavid du Colombier 				error("wait failed: %r", "");
5069a747e4fSDavid du Colombier 			if(wm->pid == pid)
5079a747e4fSDavid du Colombier 				break;
5089a747e4fSDavid du Colombier 			free(wm);
5099a747e4fSDavid du Colombier 		}
5102b7fd5adSDavid du Colombier 		if(debug)
5112b7fd5adSDavid du Colombier 			fprint(2, "wm->pid %d wm->msg == %s\n", wm->pid, wm->msg);
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier 		if(wm->msg[0]){
5143e12c5d1SDavid du Colombier 			if(debug)
5159a747e4fSDavid du Colombier 				fprint(2, "[%d] wm->msg == %s\n", getpid(), wm->msg);
51667031067SDavid du Colombier 			if(!Rflag && strstr(wm->msg, "Retry")==0){
5173e12c5d1SDavid du Colombier 				/* return the message and remove it */
5182b7fd5adSDavid du Colombier 				if(returnmail(av, dp->name, wm->msg) != 0)
519ed250ae1SDavid du Colombier 					logit("returnmail failed", dp->name, av);
520219b2ee8SDavid du Colombier 				remmatch(dp->name);
5213e12c5d1SDavid du Colombier 			} else {
5227dd7cddfSDavid du Colombier 				/* add sys to bad list and try again later */
5237dd7cddfSDavid du Colombier 				nbad++;
5247dd7cddfSDavid du Colombier 				badsys = realloc(badsys, nbad*sizeof(char*));
5257dd7cddfSDavid du Colombier 				badsys[nbad-1] = strdup(av[3]);
5263e12c5d1SDavid du Colombier 			}
5273e12c5d1SDavid du Colombier 		} else {
5283e12c5d1SDavid du Colombier 			/* it worked remove the message */
529219b2ee8SDavid du Colombier 			remmatch(dp->name);
5303e12c5d1SDavid du Colombier 		}
5319a747e4fSDavid du Colombier 		free(wm);
5323e12c5d1SDavid du Colombier 
5333e12c5d1SDavid du Colombier 	}
5347dd7cddfSDavid du Colombier done:
5354f281771SDavid du Colombier 	if (l)
5364f281771SDavid du Colombier 		sysunlock(l);
5377dd7cddfSDavid du Colombier 	Bterm(b);
5387dd7cddfSDavid du Colombier 	sysunlockfile(Bfildes(b));
5397dd7cddfSDavid du Colombier 	free(buf);
5407dd7cddfSDavid du Colombier 	free(av);
5413e12c5d1SDavid du Colombier 	close(dfd);
5423e12c5d1SDavid du Colombier }
5433e12c5d1SDavid du Colombier 
5447dd7cddfSDavid du Colombier 
5453e12c5d1SDavid du Colombier /*
5463e12c5d1SDavid du Colombier  *  return a name starting with the given character
5473e12c5d1SDavid du Colombier  */
5483e12c5d1SDavid du Colombier char*
5493e12c5d1SDavid du Colombier file(char *name, char type)
5503e12c5d1SDavid du Colombier {
5519a747e4fSDavid du Colombier 	static char nname[Elemlen+1];
5523e12c5d1SDavid du Colombier 
5539a747e4fSDavid du Colombier 	strncpy(nname, name, Elemlen);
5549a747e4fSDavid du Colombier 	nname[Elemlen] = 0;
5553e12c5d1SDavid du Colombier 	nname[0] = type;
5563e12c5d1SDavid du Colombier 	return nname;
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier 
5593e12c5d1SDavid du Colombier /*
5603e12c5d1SDavid du Colombier  *  send back the mail with an error message
5613e12c5d1SDavid du Colombier  *
5623e12c5d1SDavid du Colombier  *  return 0 if successful
5633e12c5d1SDavid du Colombier  */
5643e12c5d1SDavid du Colombier int
5653e12c5d1SDavid du Colombier returnmail(char **av, char *name, char *msg)
5663e12c5d1SDavid du Colombier {
5673e12c5d1SDavid du Colombier 	int pfd[2];
5689a747e4fSDavid du Colombier 	Waitmsg *wm;
5693e12c5d1SDavid du Colombier 	int fd;
5703e12c5d1SDavid du Colombier 	char buf[256];
571d9306527SDavid du Colombier 	char attachment[256];
5723e12c5d1SDavid du Colombier 	int i;
5733e12c5d1SDavid du Colombier 	long n;
5747dd7cddfSDavid du Colombier 	String *s;
5757dd7cddfSDavid du Colombier 	char *sender;
5763e12c5d1SDavid du Colombier 
5777dd7cddfSDavid du Colombier 	if(av[1] == 0 || av[2] == 0){
5787dd7cddfSDavid du Colombier 		logit("runq - dumping bad file", name, av);
5797dd7cddfSDavid du Colombier 		return 0;
5807dd7cddfSDavid du Colombier 	}
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	s = unescapespecial(s_copy(av[2]));
5837dd7cddfSDavid du Colombier 	sender = s_to_c(s);
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	if(!returnable(sender) || strcmp(sender, "postmaster") == 0) {
5867dd7cddfSDavid du Colombier 		logit("runq - dumping p to p mail", name, av);
5877dd7cddfSDavid du Colombier 		return 0;
5887dd7cddfSDavid du Colombier 	}
5893e12c5d1SDavid du Colombier 
5902b7fd5adSDavid du Colombier 	if(pipe(pfd) < 0){
5912b7fd5adSDavid du Colombier 		logit("runq - pipe failed", name, av);
5923e12c5d1SDavid du Colombier 		return -1;
5932b7fd5adSDavid du Colombier 	}
5943e12c5d1SDavid du Colombier 
5957dd7cddfSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFENVG)){
5963e12c5d1SDavid du Colombier 	case -1:
5972b7fd5adSDavid du Colombier 		logit("runq - fork failed", name, av);
5983e12c5d1SDavid du Colombier 		return -1;
5993e12c5d1SDavid du Colombier 	case 0:
6007dd7cddfSDavid du Colombier 		logit("returning", name, av);
6013e12c5d1SDavid du Colombier 		close(pfd[1]);
6023e12c5d1SDavid du Colombier 		close(0);
6033e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
6043e12c5d1SDavid du Colombier 		close(pfd[0]);
6057dd7cddfSDavid du Colombier 		putenv("upasname", "/dev/null");
606d9306527SDavid du Colombier 		snprint(buf, sizeof(buf), "%s/marshal", UPASBIN);
607d9306527SDavid du Colombier 		snprint(attachment, sizeof(attachment), "%s", file(name, 'D'));
608*f19e7b74SDavid du Colombier 		execl(buf, "send", "-A", attachment, "-s", "permanent failure", sender, nil);
6093e12c5d1SDavid du Colombier 		error("can't exec", 0);
6103e12c5d1SDavid du Colombier 		break;
6113e12c5d1SDavid du Colombier 	default:
6123e12c5d1SDavid du Colombier 		break;
6133e12c5d1SDavid du Colombier 	}
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier 	close(pfd[0]);
6163ff48bf5SDavid du Colombier 	fprint(pfd[1], "\n");	/* get out of headers */
6173e12c5d1SDavid du Colombier 	if(av[1]){
6187dd7cddfSDavid du Colombier 		fprint(pfd[1], "Your request ``%.20s ", av[1]);
6193e12c5d1SDavid du Colombier 		for(n = 3; av[n]; n++)
6203e12c5d1SDavid du Colombier 			fprint(pfd[1], "%s ", av[n]);
6213e12c5d1SDavid du Colombier 	}
6223e12c5d1SDavid du Colombier 	fprint(pfd[1], "'' failed (code %s).\nThe symptom was:\n\n", msg);
6233e12c5d1SDavid du Colombier 	fd = open(file(name, 'E'), OREAD);
6243e12c5d1SDavid du Colombier 	if(fd >= 0){
6253e12c5d1SDavid du Colombier 		for(;;){
6263e12c5d1SDavid du Colombier 			n = read(fd, buf, sizeof(buf));
6273e12c5d1SDavid du Colombier 			if(n <= 0)
6283e12c5d1SDavid du Colombier 				break;
6293e12c5d1SDavid du Colombier 			if(write(pfd[1], buf, n) != n){
6303e12c5d1SDavid du Colombier 				close(fd);
6313e12c5d1SDavid du Colombier 				goto out;
6323e12c5d1SDavid du Colombier 			}
6333e12c5d1SDavid du Colombier 		}
6343e12c5d1SDavid du Colombier 		close(fd);
6353e12c5d1SDavid du Colombier 	}
6363e12c5d1SDavid du Colombier 	close(pfd[1]);
6373e12c5d1SDavid du Colombier out:
6389a747e4fSDavid du Colombier 	wm = wait();
6392b7fd5adSDavid du Colombier 	if(wm == nil){
6402b7fd5adSDavid du Colombier 		syslog(0, "runq", "wait: %r");
6412b7fd5adSDavid du Colombier 		logit("wait failed", name, av);
6429a747e4fSDavid du Colombier 		return -1;
6432b7fd5adSDavid du Colombier 	}
6442b7fd5adSDavid du Colombier 	i = 0;
6452b7fd5adSDavid du Colombier 	if(wm->msg[0]){
6462b7fd5adSDavid du Colombier 		i = -1;
6472b7fd5adSDavid du Colombier 		syslog(0, "runq", "returnmail child: %s", wm->msg);
6482b7fd5adSDavid du Colombier 		logit("returnmail child failed", name, av);
6492b7fd5adSDavid du Colombier 	}
6509a747e4fSDavid du Colombier 	free(wm);
6519a747e4fSDavid du Colombier 	return i;
6523e12c5d1SDavid du Colombier }
6533e12c5d1SDavid du Colombier 
6543e12c5d1SDavid du Colombier /*
6553e12c5d1SDavid du Colombier  *  print a warning and continue
6563e12c5d1SDavid du Colombier  */
6573e12c5d1SDavid du Colombier void
6583e12c5d1SDavid du Colombier warning(char *f, void *a)
6593e12c5d1SDavid du Colombier {
6603e12c5d1SDavid du Colombier 	char err[65];
6613e12c5d1SDavid du Colombier 	char buf[256];
6623e12c5d1SDavid du Colombier 
6639a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6647dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6653e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6663e12c5d1SDavid du Colombier }
6673e12c5d1SDavid du Colombier 
6683e12c5d1SDavid du Colombier /*
6693e12c5d1SDavid du Colombier  *  print an error and die
6703e12c5d1SDavid du Colombier  */
6713e12c5d1SDavid du Colombier void
6723e12c5d1SDavid du Colombier error(char *f, void *a)
6733e12c5d1SDavid du Colombier {
6749a747e4fSDavid du Colombier 	char err[Errlen];
6753e12c5d1SDavid du Colombier 	char buf[256];
6763e12c5d1SDavid du Colombier 
6779a747e4fSDavid du Colombier 	rerrstr(err, sizeof(err));
6787dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), f, a);
6793e12c5d1SDavid du Colombier 	fprint(2, "runq: %s: %s\n", buf, err);
6803e12c5d1SDavid du Colombier 	exits(buf);
6813e12c5d1SDavid du Colombier }
6823e12c5d1SDavid du Colombier 
6837dd7cddfSDavid du Colombier void
6847dd7cddfSDavid du Colombier logit(char *msg, char *file, char **av)
6857dd7cddfSDavid du Colombier {
6867dd7cddfSDavid du Colombier 	int n, m;
6877dd7cddfSDavid du Colombier 	char buf[256];
6887dd7cddfSDavid du Colombier 
6897dd7cddfSDavid du Colombier 	n = snprint(buf, sizeof(buf), "%s/%s: %s", curdir, file, msg);
6907dd7cddfSDavid du Colombier 	for(; *av; av++){
6917dd7cddfSDavid du Colombier 		m = strlen(*av);
6927dd7cddfSDavid du Colombier 		if(n + m + 4 > sizeof(buf))
6937dd7cddfSDavid du Colombier 			break;
6947dd7cddfSDavid du Colombier 		sprint(buf + n, " '%s'", *av);
6957dd7cddfSDavid du Colombier 		n += m + 3;
6967dd7cddfSDavid du Colombier 	}
6979a747e4fSDavid du Colombier 	syslog(0, runqlog, "%s", buf);
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier 
7007dd7cddfSDavid du Colombier char *loadfile = ".runqload";
7017dd7cddfSDavid du Colombier 
7027dd7cddfSDavid du Colombier /*
7037dd7cddfSDavid du Colombier  *  load balancing
7047dd7cddfSDavid du Colombier  */
7057dd7cddfSDavid du Colombier void
7067dd7cddfSDavid du Colombier doload(int start)
7077dd7cddfSDavid du Colombier {
7087dd7cddfSDavid du Colombier 	int fd;
7097dd7cddfSDavid du Colombier 	char buf[32];
7107dd7cddfSDavid du Colombier 	int i, n;
7117dd7cddfSDavid du Colombier 	Mlock *l;
7129a747e4fSDavid du Colombier 	Dir *d;
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier 	if(load <= 0)
7157dd7cddfSDavid du Colombier 		return;
7167dd7cddfSDavid du Colombier 
7177dd7cddfSDavid du Colombier 	if(chdir(root) < 0){
7187dd7cddfSDavid du Colombier 		load = 0;
7197dd7cddfSDavid du Colombier 		return;
7207dd7cddfSDavid du Colombier 	}
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier 	l = syslock(loadfile);
7237dd7cddfSDavid du Colombier 	fd = open(loadfile, ORDWR);
7247dd7cddfSDavid du Colombier 	if(fd < 0){
7257dd7cddfSDavid du Colombier 		fd = create(loadfile, 0666, ORDWR);
7267dd7cddfSDavid du Colombier 		if(fd < 0){
7277dd7cddfSDavid du Colombier 			load = 0;
7287dd7cddfSDavid du Colombier 			sysunlock(l);
7297dd7cddfSDavid du Colombier 			return;
7307dd7cddfSDavid du Colombier 		}
7317dd7cddfSDavid du Colombier 	}
7327dd7cddfSDavid du Colombier 
7337dd7cddfSDavid du Colombier 	/* get current load */
7347dd7cddfSDavid du Colombier 	i = 0;
7357dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof(buf)-1);
7367dd7cddfSDavid du Colombier 	if(n >= 0){
7377dd7cddfSDavid du Colombier 		buf[n] = 0;
7387dd7cddfSDavid du Colombier 		i = atoi(buf);
7397dd7cddfSDavid du Colombier 	}
7407dd7cddfSDavid du Colombier 	if(i < 0)
7417dd7cddfSDavid du Colombier 		i = 0;
7427dd7cddfSDavid du Colombier 
7437dd7cddfSDavid du Colombier 	/* ignore load if file hasn't been changed in 30 minutes */
7449a747e4fSDavid du Colombier 	d = dirfstat(fd);
7459a747e4fSDavid du Colombier 	if(d != nil){
7469a747e4fSDavid du Colombier 		if(d->mtime + 30*60 < time(0))
7477dd7cddfSDavid du Colombier 			i = 0;
7489a747e4fSDavid du Colombier 		free(d);
7499a747e4fSDavid du Colombier 	}
7507dd7cddfSDavid du Colombier 
7517dd7cddfSDavid du Colombier 	/* if load already too high, give up */
7527dd7cddfSDavid du Colombier 	if(start && i >= load){
7537dd7cddfSDavid du Colombier 		sysunlock(l);
7547dd7cddfSDavid du Colombier 		exits(0);
7557dd7cddfSDavid du Colombier 	}
7567dd7cddfSDavid du Colombier 
7577dd7cddfSDavid du Colombier 	/* increment/decrement load */
7587dd7cddfSDavid du Colombier 	if(start)
7597dd7cddfSDavid du Colombier 		i++;
7607dd7cddfSDavid du Colombier 	else
7617dd7cddfSDavid du Colombier 		i--;
7627dd7cddfSDavid du Colombier 	seek(fd, 0, 0);
7637dd7cddfSDavid du Colombier 	fprint(fd, "%d\n", i);
7647dd7cddfSDavid du Colombier 	sysunlock(l);
7657dd7cddfSDavid du Colombier 	close(fd);
7667dd7cddfSDavid du Colombier }
767