1 #ifndef lint 2 static char sccsid[] = "@(#)anlwrk.c 5.2 (Berkeley) 07/02/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 } 388