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