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