--- ray/src/util/ranimate.c 1996/01/18 11:25:11 2.2 +++ ray/src/util/ranimate.c 1996/07/10 15:14:59 2.19 @@ -1,4 +1,4 @@ -/* Copyright (c) 1995 Regents of the University of California */ +/* Copyright (c) 1996 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; @@ -15,6 +15,12 @@ static char SCCSid[] = "$SunId$ LBL"; #include "view.h" #include "vars.h" #include "netproc.h" + /* default remote shell */ +#ifdef _AUX_SOURCE +#define REMSH "remsh" +#else +#define REMSH "rsh" +#endif /* input variables */ #define HOST 0 /* rendering host machine */ #define RENDER 1 /* rendering options */ @@ -38,8 +44,9 @@ static char SCCSid[] = "$SunId$ LBL"; #define DISKSPACE 19 /* how much disk space to use */ #define RESOLUTION 20 /* desired final resolution */ #define EXPOSURE 21 /* how to compute exposure */ +#define RSH 22 /* remote shell script or program */ -int NVARS = 22; /* total number of variables */ +int NVARS = 23; /* total number of variables */ VARIABLE vv[] = { /* variable-value pairs */ {"host", 4, 0, NULL, NULL}, @@ -57,13 +64,14 @@ VARIABLE vv[] = { /* variable-value pairs */ {"ANIMATE", 2, 0, NULL, onevalue}, {"TRANSFER", 2, 0, NULL, onevalue}, {"ARCHIVE", 2, 0, NULL, onevalue}, - {"INTERP", 3, 0, NULL, intvalue}, - {"OVERSAMP", 2, 0, NULL, fltvalue}, + {"INTERPOLATE", 3, 0, NULL, intvalue}, + {"OVERSAMPLE", 2, 0, NULL, fltvalue}, {"MBLUR", 2, 0, NULL, onevalue}, {"RTRACE", 2, 0, NULL, boolvalue}, {"DISKSPACE", 3, 0, NULL, fltvalue}, {"RESOLUTION", 3, 0, NULL, onevalue}, {"EXPOSURE", 3, 0, NULL, onevalue}, + {"RSH", 3, 0, NULL, onevalue}, }; #define SFNAME "STATUS" /* status file name */ @@ -84,11 +92,15 @@ int nowarn = 0; /* turn warnings off? */ int silent = 0; /* silent mode? */ int noaction = 0; /* take no action? */ +char *remsh; /* remote shell program/script */ char rendopt[2048] = ""; /* rendering options */ char rresopt[32]; /* rendering resolution options */ char fresopt[32]; /* filter resolution options */ int pfiltalways; /* always use pfilt? */ +char arcargs[10240]; /* files to archive */ +char *arcfirst, *arcnext; /* pointers to first and next argument */ + struct pslot { int pid; /* process ID (0 if empty) */ int fout; /* output frame number */ @@ -96,15 +108,18 @@ struct pslot { } *pslot; /* process slots */ int npslots; /* number of process slots */ -int lastpid; /* ID of last completed background process */ -PSERVER *lastpserver; /* last process server used */ +#define phostname(ps) ((ps)->hostname[0] ? (ps)->hostname : astat.host) struct pslot *findpslot(); +PSERVER *lastpserver; /* last process server with error */ + VIEW *getview(); char *getexp(); +extern time_t fdate(), time(); + main(argc, argv) int argc; char *argv[]; @@ -161,8 +176,11 @@ char *argv[]; argv[i] = vval(NEXTANIM); /* just change input file */ if (!silent) printargs(argc, argv, stdout); - execvp(progname, argv); /* pass to next */ - quit(1); /* shouldn't return */ + if ((argv[0] = getpath(progname,getenv("PATH"),X_OK)) == NULL) + fprintf(stderr, "%s: command not found\n", progname); + else + execv(progname, argv); + quit(1); } quit(0); userr: @@ -173,13 +191,13 @@ userr: getastat() /* check/set animation status */ { - char buf[256]; + char sfname[256]; FILE *fp; - sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME); - if ((fp = fopen(buf, "r")) == NULL) { + sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME); + if ((fp = fopen(sfname, "r")) == NULL) { if (errno != ENOENT) { - perror(buf); + perror(sfname); return(-1); } astat.rnext = astat.fnext = astat.tnext = 0; @@ -199,8 +217,7 @@ getastat() /* check/set animation status */ goto fmterr; fclose(fp); if (astat.pid != 0) { /* thinks it's still running */ - gethostname(buf, sizeof(buf)); - if (strcmp(buf, astat.host)) { + if (strcmp(myhostname(), astat.host)) { fprintf(stderr, "%s: process %d may still be running on host %s\n", progname, astat.pid, astat.host); @@ -218,14 +235,19 @@ getastat() /* check/set animation status */ progname, astat.cfname); return(-1); } + /* check control file mods. */ + if (!nowarn && fdate(cfname) > fdate(sfname)) + fprintf(stderr, + "%s: warning - control file modified since last run\n", + progname); setours: /* set our values */ - gethostname(astat.host, sizeof(astat.host)); + strcpy(astat.host, myhostname()); astat.pid = getpid(); strcpy(astat.cfname, cfname); return(0); fmterr: fprintf(stderr, "%s: format error in status file \"%s\"\n", - progname, buf); + progname, sfname); fclose(fp); return(-1); } @@ -277,6 +299,8 @@ checkdir() /* make sure we have our directory */ setdefaults() /* set default values */ { + extern char *atos(); + int decades; char buf[256]; if (vdef(ANIMATE)) { @@ -300,12 +324,19 @@ setdefaults() /* set default values */ vdef(START)++; } if (!vdef(END)) { - sprintf(buf, "%d", countviews()); + sprintf(buf, "%d", countviews()+vint(START)-1); vval(END) = savqstr(buf); vdef(END)++; } + if (vint(END) < vint(START)) { + fprintf(stderr, "%s: ending frame less than starting frame\n", + progname); + quit(1); + } if (!vdef(BASENAME)) { - sprintf(buf, "%s/frame%%03d", vval(DIRECTORY)); + decades = (int)log10((double)vint(END)) + 1; + if (decades < 3) decades = 3; + sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades); vval(BASENAME) = savqstr(buf); vdef(BASENAME)++; } @@ -337,6 +368,17 @@ setdefaults() /* set default values */ vval(DISKSPACE) = "100"; vdef(DISKSPACE)++; } + if (!vdef(RSH)) { + vval(RSH) = REMSH; + vdef(RSH)++; + } + /* locate remote shell program */ + atos(buf, sizeof(buf), vval(RSH)); + if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL) + remsh = savqstr(remsh); + else + remsh = vval(RSH); /* will generate error if used */ + /* append rendering options */ if (vdef(RENDER)) sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER)); @@ -399,8 +441,8 @@ sethosts() /* set up process servers */ } -getradfile(rfname) /* run rad and get needed variables */ -char *rfname; +getradfile(rfargs) /* run rad and get needed variables */ +char *rfargs; { static short mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1}; char combuf[256]; @@ -410,7 +452,7 @@ char *rfname; sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY)); sprintf(combuf, "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH", - rfname, rendopt+2); + rfargs, rendopt+2); cp = combuf; while (*cp) cp++; /* match unset variables */ for (i = 0; mvar[i] >= 0; i++) @@ -422,8 +464,8 @@ char *rfname; sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY)); cp += 11; /* point to file name */ if (system(combuf)) { - fprintf(stderr, "%s: bad rad input file \"%s\"\n", - progname, rfname); + fprintf(stderr, "%s: error executing rad command:\n\t%s\n", + progname, combuf); quit(1); } loadvars(cp); /* load variables and remove file */ @@ -442,9 +484,9 @@ animate() /* run animation */ i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa); mult = vflt(OVERSAMP); if (i == 3) { - sprintf(rresopt, "-x %d -y %d -pa %f", (int)(mult*xres), + sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres), (int)(mult*yres), pa); - sprintf(fresopt, "-x %d -y %d -pa %f", xres, yres, pa); + sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa); } else if (i) { if (i == 1) yres = xres; sprintf(rresopt, "-x %d -y %d", (int)(mult*xres), @@ -472,7 +514,7 @@ animate() /* run animation */ /* figure # frames per batch */ d1 = mult*xres*mult*yres*4; /* space for orig. picture */ if ((i=vint(INTERP)) || atoi(vval(MBLUR))) - d1 += mult*xres*mult*yres*4; /* space for z-buffer */ + d1 += mult*xres*mult*yres*sizeof(float); /* Z-buffer */ d2 = xres*yres*4; /* space for final picture */ frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2); if (frames_batch < i+2) { @@ -480,6 +522,11 @@ animate() /* run animation */ progname); quit(1); } + /* initialize archive argument list */ + i = 16; + if (vdef(ARCHIVE) && strlen(vval(ARCHIVE)) > i) + i = strlen(vval(ARCHIVE)); + arcnext = arcfirst = arcargs + i; /* initialize status file */ if (astat.rnext == 0) astat.rnext = astat.fnext = astat.tnext = vint(START); @@ -574,7 +621,7 @@ filterframes() /* catch up with filtering */ dofilt(i, vp, getexp(i), 0); /* filter frame */ } bwait(0); /* wait for filter processes */ - archive(astat.fnext, i-1); /* archive originals */ + archive(); /* archive originals */ astat.fnext = i; /* update status */ putastat(); } @@ -636,6 +683,7 @@ int first, last; char *vfn; { char combuf[2048]; + char *inspoint; register int i; if (!noaction && vint(INTERP)) /* create dummy frames */ @@ -646,13 +694,17 @@ char *vfn; close(open(combuf, O_RDONLY|O_CREAT, 0666)); } /* create command */ - sprintf(combuf, "rpict%s -w0 ", rendopt); + sprintf(combuf, "rpict%s -w0", rendopt); if (vint(INTERP) || atoi(vval(MBLUR))) - sprintf(combuf+strlen(combuf), "-z %s.zbf ", vval(BASENAME)); - sprintf(combuf+strlen(combuf), "-o %s.unf %s -S %d %s < %s", - vval(BASENAME), rresopt, first, vval(OCTREE), vfn); + sprintf(combuf+strlen(combuf), " -z %s.zbf", vval(BASENAME)); + sprintf(combuf+strlen(combuf), " -o %s.unf %s -S %d", + vval(BASENAME), rresopt, first); + inspoint = combuf + strlen(combuf); + sprintf(inspoint, " %s < %s", vval(OCTREE), vfn); /* run in parallel */ - if (pruncom(combuf, (last-first+1)/(vint(INTERP)+1))) { + i = (last-first+1)/(vint(INTERP)+1); + if (i < 1) i = 1; + if (pruncom(combuf, inspoint, i)) { fprintf(stderr, "%s: error rendering frames %d through %d\n", progname, first, last); quit(1); @@ -730,53 +782,27 @@ int frame; } -archive(first, last) /* archive and remove renderings */ -int first, last; +archive() /* archive and remove renderings */ { #define RMCOML (sizeof(rmcom)-1) static char rmcom[] = "rm -f"; - int offset = RMCOML; - char combuf[10240]; - struct stat stb; - register char *cp; register int i; - if (noaction) - return; - if (vdef(ARCHIVE) && strlen(vval(ARCHIVE)) > offset) - offset = strlen(vval(ARCHIVE)); - cp = combuf + offset; - *cp++ = ' '; /* make argument list */ - for (i = first; i <= last; i++) { - sprintf(cp, vval(BASENAME), i); - strcat(cp, ".unf"); - if (stat(cp, &stb) == 0 && stb.st_size > 0) { /* non-zero? */ - while (*cp) cp++; - *cp++ = ' '; - sprintf(cp, vval(BASENAME), i); - strcat(cp, ".zbf"); - if (access(cp, F_OK) == 0) { /* exists? */ - while (*cp) cp++; - *cp++ = ' '; - } - } - } - *--cp = '\0'; - if (cp <= combuf + offset) /* no files? */ - return; + if (arcnext == arcfirst) + return; /* nothing to do */ if (vdef(ARCHIVE)) { /* run archive command */ i = strlen(vval(ARCHIVE)); - strncpy(combuf+offset-i, vval(ARCHIVE), i); - if (runcom(combuf+offset-i)) { - fprintf(stderr, - "%s: error running archive command on frames %d through %d\n", - progname, first, last); + strncpy(arcfirst-i, vval(ARCHIVE), i); + if (runcom(arcfirst-i)) { + fprintf(stderr, "%s: error running archive command\n", + progname); quit(1); } } /* run remove command */ - strncpy(combuf+offset-RMCOML, rmcom, RMCOML); - runcom(combuf+offset-RMCOML); + strncpy(arcfirst-RMCOML, rmcom, RMCOML); + runcom(arcfirst-RMCOML); + arcnext = arcfirst; /* reset argument list */ #undef RMCOML } @@ -789,13 +815,18 @@ char *ep; int rvr; { extern int frecover(); + static int iter = 0; char fnbefore[128], fnafter[128]; - char combuf[1024], fname[128]; - int usepinterp, usepfilt; + char combuf[1024], fname0[128], fname1[128]; + int usepinterp, usepfilt, nora_rgbe; int frseq[2]; /* check what is needed */ usepinterp = atoi(vval(MBLUR)); usepfilt = pfiltalways | ep==NULL; + if (ep != NULL && !strcmp(ep, "1")) + ep = "+0"; + nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL || + *ep != '+' || *ep != '-' || !isint(ep); /* compute rendered views */ frseq[0] = frame - ((frame-1) % (vint(INTERP)+1)); frseq[1] = frseq[0] + vint(INTERP) + 1; @@ -804,11 +835,25 @@ int rvr; if (frseq[1] == frame) { /* pfilt only */ frseq[0] = frseq[1]; usepinterp = 0; /* update what's needed */ - usepfilt |= vflt(OVERSAMP)>1.01 || strcmp(ep,"1"); - } else if (frseq[0] == frame) { /* no interpolation */ - /* update what's needed */ - if (!usepinterp) - usepfilt |= vflt(OVERSAMP)>1.01 || strcmp(ep,"1"); + usepfilt |= nora_rgbe; + } else if (frseq[0] == frame) { /* no interpolation needed */ + if (!rvr && frame > 1+vint(INTERP)) { /* archive previous */ + *arcnext++ = ' '; + sprintf(arcnext, vval(BASENAME), frame-vint(INTERP)-1); + while (*arcnext) arcnext++; + strcpy(arcnext, ".unf"); + arcnext += 4; + if (usepinterp || vint(INTERP)) { /* and Z-buf */ + *arcnext++ = ' '; + sprintf(arcnext, vval(BASENAME), + frame-vint(INTERP)-1); + while (*arcnext) arcnext++; + strcpy(arcnext, ".zbf"); + arcnext += 4; + } + } + if (!usepinterp) /* update what's needed */ + usepfilt |= nora_rgbe; } else /* interpolation needed */ usepinterp++; if (frseq[1] >= astat.rnext) /* next batch unavailable */ @@ -823,9 +868,10 @@ int rvr; return(1); if (atoi(vval(MBLUR))) { FILE *fp; /* motion blurring */ - sprintf(fname, "%s/vw0", vval(DIRECTORY)); - if ((fp = fopen(fname, "w")) == NULL) { - perror(fname); quit(1); + sprintf(fname0, "%s/vw0%c", vval(DIRECTORY), + 'a'+(iter%26)); + if ((fp = fopen(fname0, "w")) == NULL) { + perror(fname0); quit(1); } fputs(VIEWSTR, fp); fprintview(vp, fp); @@ -836,19 +882,20 @@ int rvr; progname, frame+1); quit(1); } - sprintf(fname, "%s/vw1", vval(DIRECTORY)); - if ((fp = fopen(fname, "w")) == NULL) { - perror(fname); quit(1); + sprintf(fname1, "%s/vw1%c", vval(DIRECTORY), + 'a'+(iter%26)); + if ((fp = fopen(fname1, "w")) == NULL) { + perror(fname1); quit(1); } fputs(VIEWSTR, fp); fprintview(vp, fp); putc('\n', fp); fclose(fp); sprintf(combuf, - "(pmblur %s %d %s/vw0 %s/vw1; rm -f %s/vw0 %s/vw1) | pinterp -B", + "(pmblur %s %d %s %s; rm -f %s %s) | pinterp -B", *sskip(vval(MBLUR)) ? sskip2(vval(MBLUR),1) : "1", - atoi(vval(MBLUR)), vval(DIRECTORY), - vval(DIRECTORY), vval(DIRECTORY), - vval(DIRECTORY), vval(DIRECTORY)); + atoi(vval(MBLUR)), + fname0, fname1, fname0, fname1); + iter++; } else /* no blurring */ strcpy(combuf, "pinterp"); strcat(combuf, viewopt(vp)); @@ -895,11 +942,11 @@ int rvr; } else { /* else just check it */ if (rvr == 2) return(1); - sprintf(combuf, "ra_rgbe -r %s.unf", fnbefore); + sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore); } /* output file name */ - sprintf(fname, vval(BASENAME), frame); - sprintf(combuf+strlen(combuf), " > %s.pic", fname); + sprintf(fname0, vval(BASENAME), frame); + sprintf(combuf+strlen(combuf), " > %s.pic", fname0); if (rvr) /* in recovery */ return(runcom(combuf)); bruncom(combuf, frame, frecover); /* else run in background */ @@ -931,6 +978,8 @@ int n; quit(1); } } else if (n < viewnum) { /* rewind file */ + if (viewnum == 1 && feof(viewfp)) + return(&curview); /* just one view */ if (fseek(viewfp, 0L, 0) == EOF) { perror(vval(VIEWFILE)); quit(1); @@ -940,7 +989,7 @@ int n; } while (n > viewnum) { /* scan to desired view */ if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL) - return(NULL); + return(viewnum==1 ? &curview : (VIEW *)NULL); if (isview(linebuf) && sscanview(&curview, linebuf) > 0) viewnum++; } @@ -973,10 +1022,12 @@ int n; if (n == 0) { /* signal to close file */ if (expfp != NULL) { fclose(expfp); + free((char *)exppos); expfp = NULL; } return(NULL); - } + } else if (n > vint(END)) /* request past end (error?) */ + return(NULL); if (!vdef(EXPOSURE)) /* no setting (auto) */ return(NULL); if (isflt(vval(EXPOSURE))) /* always the same */ @@ -1014,13 +1065,15 @@ int n; } curfrm++; cp = fskip(expval); /* check format */ - if (cp == NULL || *cp != '\n') { + if (cp != NULL) + while (isspace(*cp)) + *cp++ = '\0'; + if (cp == NULL || *cp) { fprintf(stderr, "%s: exposure format error on line %d\n", vval(EXPOSURE), curfrm); quit(1); } - *cp = '\0'; } return(expval); /* return value */ } @@ -1050,23 +1103,36 @@ int pn; int status; { register PROC *pp; + register struct pslot *psl; pp = ps->proc + pn; - if (!silent) { /* echo command */ - if (ps->hostname[0]) - printf("On %s:", ps->hostname); - printf("\t%s\n", pp->com); - fflush(stdout); - } if (pp->elen) { /* pass errors */ + if (ps->hostname[0]) + fprintf(stderr, "%s: ", ps->hostname); + fprintf(stderr, "Error output from: %s\n", pp->com); fputs(pp->errs, stderr); fflush(stderr); if (ps->hostname[0]) status = 1; /* because rsh doesn't return status */ } + lastpserver = NULL; + psl = findpslot(pp->pid); /* check for bruncom() slot */ + if (psl->pid) { + if (status) { + if (psl->rcvf != NULL) /* attempt recovery */ + status = (*psl->rcvf)(psl->fout); + if (status) { + fprintf(stderr, + "%s: error rendering frame %d\n", + progname, psl->fout); + quit(1); + } + lastpserver = ps; + } + psl->pid = 0; /* free process slot */ + } else if (status) + lastpserver = ps; freestr(pp->com); /* free command string */ - lastpid = pp->pid; /* record PID for bwait() */ - lastpserver = ps; /* record server for serverdown() */ return(status); } @@ -1074,6 +1140,8 @@ int status; int serverdown() /* check status of last process server */ { + if (lastpserver == NULL || !lastpserver->hostname[0]) + return(0); if (pserverOK(lastpserver)) /* server still up? */ return(0); delpserver(lastpserver); /* else delete it */ @@ -1097,12 +1165,20 @@ int (*rf)(); if (noaction) { if (!silent) - printf("\t%s\n", com); /* just echo it */ + printf("\t%s\n", com); /* echo command */ return(0); } - /* else start it when we can */ - while ((pid = startjob(NULL, savestr(com), donecom)) == -1) + com = savestr(com); /* else start it when we can */ + while ((pid = startjob(NULL, com, donecom)) == -1) bwait(1); + if (!silent) { /* echo command */ + PSERVER *ps; + int psn = pid; + ps = findjob(&psn); + printf("\t%s\n", com); + printf("\tProcess started on %s\n", phostname(ps)); + fflush(stdout); + } psl = findpslot(pid); /* record info. in appropriate slot */ psl->pid = pid; psl->fout = fout; @@ -1115,53 +1191,82 @@ bwait(ncoms) /* wait for batch job(s) to finish */ int ncoms; { int status; - register struct pslot *psl; if (noaction) return; while ((status = wait4job(NULL, -1)) != -1) { - psl = findpslot(lastpid); - if (status) { /* attempt recovery */ - serverdown(); /* check server */ - if (psl->rcvf == NULL || (*psl->rcvf)(psl->fout)) { - fprintf(stderr, - "%s: error rendering frame %d\n", - progname, psl->fout); - quit(1); - } - } - psl->pid = 0; /* free process slot */ - if (!--ncoms) - return; /* done enough */ + serverdown(); /* update server status */ + if (--ncoms == 0) + break; /* done enough */ } } int -pruncom(com, maxcopies) /* run a command in parallel over network */ -char *com; +pruncom(com, ppins, maxcopies) /* run a command in parallel over network */ +char *com, *ppins; int maxcopies; { int retstatus = 0; + int hostcopies; + char buf[10240], *com1, *s; int status; + int pfd; + register int n; register PSERVER *ps; - if (noaction) { - if (!silent) - printf("\t%s\n", com); /* just echo */ + if (!silent) + printf("\t%s\n", com); /* echo command */ + if (noaction) return(0); - } + fflush(stdout); /* start jobs on each server */ - for (ps = pslist; ps != NULL; ps = ps->next) - while (maxcopies > 0 && - startjob(ps, savestr(com), donecom) != -1) { - sleep(10); - maxcopies--; + for (ps = pslist; ps != NULL; ps = ps->next) { + hostcopies = 0; + if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) { + strcpy(com1=buf, com); /* build -PP command */ + sprintf(com1+(ppins-com), " -PP %s/%s.persist", + vval(DIRECTORY), phostname(ps)); + strcat(com1, ppins); + } else + com1 = com; + while (maxcopies > 0) { + s = savestr(com1); + if (startjob(ps, s, donecom) != -1) { + sleep(20); + hostcopies++; + maxcopies--; + } else { + freestr(s); + break; + } } + if (!silent && hostcopies) { + if (hostcopies > 1) + printf("\t%d duplicate processes", hostcopies); + else + printf("\tProcess"); + printf(" started on %s\n", phostname(ps)); + fflush(stdout); + } + } /* wait for jobs to finish */ while ((status = wait4job(NULL, -1)) != -1) - if (status) - retstatus += !serverdown(); /* check server */ + retstatus += status && !serverdown(); + /* terminate parallel rpict's */ + for (ps = pslist; ps != NULL; ps = ps->next) { + sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps)); + if ((pfd = open(buf, O_RDONLY)) >= 0) { + n = read(pfd, buf, sizeof(buf)-1); /* get PID */ + buf[n] = '\0'; + close(pfd); + for (n = 0; buf[n] && !isspace(buf[n]); n++) + ; + /* terminate */ + sprintf(buf, "kill -ALRM %d", atoi(buf+n)); + wait4job(ps, startjob(ps, buf, NULL)); + } + } return(retstatus); }