1: #ifndef lint 2: static char sccsid[] = "@(#)anlwrk.c 5.2 (Berkeley) 7/2/83"; 3: #endif 4: 5: #include "uucp.h" 6: #include <sys/types.h> 7: #include <sys/stat.h> 8: #ifdef NDIR 9: #include "ndir.h" 10: #else 11: #include <sys/dir.h> 12: #endif 13: 14: /* Re-written to be reasonable 15: * Mon Nov 15 17:19:52 EST 1982 16: * Alan S. Watt (ittvax!swatt) 17: * 18: * Tom Truscott (rti!trt): 19: * Priority ordering cleaned up. New 'pcompar' subroutine. 20: * 'stat' removed (speeds things up). 21: * Possible infinite loop in gtwvec defended against. 22: * Feb 23, 1983 23: * 24: * Changes: 25: * 26: * 1) The check for work is much faster; the first filename 27: * that matches the prefix causes a "yes" return. 28: * 29: * 2) The filename is not "stat" ed , so 30: * there is no massive delay while the list of potential 31: * names is built. 32: * 33: * 3) Requesting work for a new system is now detected so 34: * internal variables are re-initialized properly. In 35: * particular, the stream pointer for the current work 36: * file is properly closed so work for a system which 37: * hangs up will not be sent to the next system called. 38: * 39: * Fri Dec 3 09:31:45 EST 1982 40: * 41: * 5) As new work files are requested, a check is made 42: * every TLIMIT seconds (5 minutes at present) to see 43: * if new files have entered the spool area. Since 44: * work file names are now cached up to LLEN, this can 45: * represent a very long transmission time before new 46: * work enters the list to be processed. If people want 47: * to use the "grade" character to specify a higher 48: * priority, the list must be re-built and re-sorted for 49: * higher priority stuff to have an immediate effect. 50: */ 51: 52: 53: #define LLEN 20 54: #define MAXRQST 250 55: #define TLIMIT (5*60L) 56: #define NITEMS(X) (sizeof (X) / sizeof ((X)[0])) 57: 58: /* These are all used only locally 59: */ 60: static int Nfiles = 0; 61: static char Filent[LLEN][NAMESIZE]; 62: 63: /******* 64: * anlwrk(file, wvec) create a vector of command arguments 65: * char *file, **wvec; 66: * 67: * return codes: 68: * 0 - no more work in this file 69: * positive number - number of arguments 70: */ 71: 72: /* LOCAL only */ 73: int 74: anlwrk(file, wvec) 75: register char *file, **wvec; 76: { 77: static char str[MAXRQST]; 78: static FILE *fp = NULL; 79: 80: /* If called with a null string, force a shutdown 81: * of the current work file. 82: * John Levine, ima.247, related change in cntl.c 83: */ 84: if (file[0] == '\0') { 85: if (fp != NULL) 86: fclose (fp); 87: fp = NULL; 88: return(0); 89: } 90: if (fp == NULL) { 91: fp = fopen(subfile(file), "r"); 92: if (fp == NULL) { 93: unlink(subfile(file)); /* Try to zap the thing. rti!trt */ 94: return(0); 95: } 96: } 97: 98: /* This is what deletes the current work file when EOF 99: * is reached. As this is called from gtwvec, which is 100: * in turn called externally, it is not possible to save 101: * "C." files in case of error, except for line errors, 102: * which shuts down the whole system. 103: */ 104: if (fgets(str, MAXRQST, fp) == NULL) { 105: fclose(fp); 106: unlink(subfile(file)); 107: file[0] = '\0'; 108: fp = NULL; 109: return(0); 110: } 111: return(getargs(str, wvec)); 112: } 113: 114: 115: /*** 116: * bldflst - build list of work files for given system 117: * Nfiles, Filent are global 118: * 119: * return value - 1 if work was found, else 0 120: * 121: * Jul 26 19:17 1982 (ittvax!swatt). fixed this obnoxious 122: * routine to NOT read all the way through the damned directory 123: * "stat"'ing every file in sight just to get 10 names!!! 124: * 125: * It still reads through the directory from the beginning until 126: * the list is filled, but this is only once every LLEN names. 127: */ 128: 129: /* LOCAL only */ 130: int 131: bldflst (reqst, dir, pre) 132: char *reqst; 133: register char *dir, *pre; 134: { 135: static DIR *dirp = NULL; 136: register nfound; 137: char filename[NAMESIZE]; /* @@@ NB: this needs new dir stuff */ 138: int plen = strlen (pre); 139: 140: if (dirp == NULL) { 141: if ((dirp = opendir(subdir(dir,pre[0]), "r")) == NULL) 142: return(0); 143: } 144: else 145: rewinddir(dirp); 146: for (nfound = 0, Nfiles = 0; gnamef(dirp, filename);) { 147: /* Check for two systems with the same prefix. 148: * Magic number "5" is 1 for "grade" character plus 149: * 4 for sequence number. The point here is to not 150: * send work for a system which has as a prefix the 151: * name of the system called for. 152: * Special case: prefix "X." does not do this check 153: * so uuxqt can use bldflst. 154: */ 155: if (!prefix(pre, filename) 156: || (plen != 2 && strlen(filename)-plen != 5)) 157: continue; 158: nfound++; 159: if (*reqst == 'c') 160: return (1); 161: entflst(filename); 162: } 163: return (nfound? 1: 0); 164: } 165: 166: /*** 167: * entflst - put new name if list is not full 168: * or new name is less than the MAX 169: * now in the list. 170: * Nfiles, Filent[] are modified. 171: * return value - none 172: * 173: */ 174: 175: /* LOCAL only */ 176: int 177: entflst(file) 178: char *file; 179: { 180: register int i; 181: register char *p; 182: 183: /* If there is room in the table, just add it. */ 184: if (Nfiles < LLEN) { 185: strcpy(Filent[Nfiles++], file); 186: return; 187: } 188: 189: /* Find lowest priority file in table */ 190: p = Filent[0]; 191: for (i = 1; i < Nfiles; i++) 192: if (pcompar(Filent[i], p) < 0) 193: p = Filent[i]; 194: 195: /* 196: * If new candidate is of higher priority 197: * that the lowest priority file in the table, 198: * replace the table entry. 199: */ 200: if (pcompar(p, file) < 0) 201: strcpy(p, file); 202: } 203: 204: /* 205: Compare priority of filenames p1 and p2. Return: 206: * < 0 if p1 "has lower priority than" p2. 207: * = 0 if p1 "has priority equal to" p2. 208: * > 0 if p1 "has greater priority than" p2. 209: * Priority: 210: * lower grade wins. 211: * lower sequence number wins (unless wrap-around is suspected). 212: * 213: */ 214: /* LOCAL only */ 215: int 216: pcompar(p1, p2) 217: register char *p1, *p2; 218: { 219: register int rc; 220: 221: /* assert: strlen(p1) and strlen(p2) are >= 5 */ 222: p1 += strlen(p1)-5; 223: p2 += strlen(p2)-5; 224: /* check 'grade' */ 225: if (rc = *p2++ - *p1++) 226: return(rc); 227: /* check for sequence wrap-around */ 228: if (rc = *p2++ - *p1++) 229: if (rc < -10 || rc > 10) 230: return(-rc); 231: else 232: return(rc); 233: /* check remaining digits */ 234: return(strcmp(p2, p1)); 235: } 236: 237: /*** 238: * gtwrkf - get next work file 239: * Nfiles, Filent[] are modified. 240: * 241: * return value: 242: * 243: * 0 - No file gotten 244: * 1 - File successfully gotten. 245: * 246: */ 247: 248: /* LOCAL only */ 249: gtwrkf(dir, file) 250: char *file, *dir; 251: { 252: register char *p; 253: register int i; 254: 255: if (Nfiles == 0) 256: return(0); 257: /* Find highest priority file in table */ 258: p = Filent[0]; 259: for (i = 1; i < Nfiles; i++) 260: if (pcompar(Filent[i], p) > 0) 261: p = Filent[i]; 262: sprintf(file, "%s/%s", dir, p); 263: strcpy(p, Filent[--Nfiles]); 264: return(1); 265: } 266: 267: /*** 268: * gtwvec(file, dir, wkpre, wrkvec) get work vector 269: * char *file, *dir, *wkpre, **wrkvec; 270: * 271: * return codes: 272: * positive number - number of arguments 273: * 0 - no arguments - fail 274: */ 275: 276: /* EXTERNALLY CALLED */ 277: int 278: gtwvec(file, dir, wkpre, wrkvec) 279: char *dir, *wkpre, **wrkvec; 280: register char *file; 281: { 282: register int nargs, n; 283: 284: n = 0; /* Break possible infinite loop. rti!trt */ 285: while ((nargs = anlwrk(file, wrkvec)) == 0) { 286: if (++n > 3 || !iswrk(file, "get", dir, wkpre)) 287: return(0); 288: } 289: return(nargs); 290: } 291: 292: /*** 293: * iswrk(file, reqst, dir, pre) 294: * char *file, *reqst, *dir, *pre; 295: * 296: * iswrk - this routine will check the work list (list). 297: * If it is empty or the present work is exhausted, it 298: * will call bldflst to generate a new list. 299: * The "reqst" field will be the string "chk" or "get" to 300: * check for work, or get the next work file respectively. 301: * 302: * return codes: 303: * 0 - no more work (or some error) 304: * 1 - there is work 305: * 306: */ 307: 308: /* EXTERNALLY CALLED */ 309: int 310: iswrk(file, reqst, dir, pre) 311: register char *file, *reqst, *dir, *pre; 312: { 313: static char *lastpre = 0; 314: register ret; 315: 316: /* Starting new system; re-init */ 317: if (lastpre == 0 || strcmp(lastpre,pre) != 0) { 318: anlwrk ("", (char **)0); /* Force close of work file */ 319: 320: /* Save last worked-on prefix */ 321: if (lastpre != 0) 322: free (lastpre); 323: lastpre = malloc((unsigned)(strlen(pre)+1)); 324: strcpy (lastpre, pre); 325: 326: /* Set the external indexes properly 327: */ 328: Nfiles = 0; 329: } 330: 331: /* If the list is empty or new files have entered 332: * the spool area, call "bldflst" to read 333: * some file names into it. Because names can 334: * be put in the list that later turn out to 335: * be unusable (from "gtwrkf"), this operation 336: * continues until either "bldflst" can't find 337: * any new files, or "gtwrkf" signals success. 338: */ 339: for (;;) { 340: ret = 0; 341: if (Nfiles == 0 || newspool((time_t)TLIMIT)) 342: ret = bldflst (reqst, dir, pre); 343: 344: /* If they only wanted to check, return 345: * boolean list not empty. NB: the list 346: * will be forcibly emptied as soon as 347: * a new system name is mentioned. 348: */ 349: if (*reqst == 'c') 350: return (ret); 351: 352: if (Nfiles == 0) 353: return(0); 354: 355: if (gtwrkf(dir, file)) 356: return (1); 357: } 358: } 359: 360: /* Return non-zero if there is new work in the spool 361: * area since last check. Assumes that if the sequence 362: * file has been modified, there is new work. This is 363: * not absolutely correct, but should be close enough. 364: * Only checks every <limit> seconds at most. Called 365: * from "iswrk()" when a new work file is requested. 366: */ 367: /* LOCAL only */ 368: int 369: newspool(limit) 370: time_t limit; 371: { 372: static time_t lastcheck = 0, lastmod = 0; 373: time_t check; 374: struct stat mod; 375: register int ret = 0; 376: 377: /* (void) */ time (&check); 378: if (check - lastcheck > limit || lastcheck - check > limit) { 379: mod.st_mtime = 0; 380: /* (void) */ stat (SEQFILE, &mod); 381: if (mod.st_mtime != lastmod) 382: ret = 1; 383: lastmod = mod.st_mtime; 384: } 385: lastcheck = check; 386: return (ret); 387: }