1/* $NetBSD: scan.c,v 1.29 2011/01/04 10:23:40 wiz Exp $ */ 2 3/* 4 * Copyright (c) 1992 Carnegie Mellon University 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify and distribute this software and its 8 * documentation is hereby granted, provided that both the copyright 9 * notice and this permission notice appear in all copies of the 10 * software, derivative works or modified versions, and any portions 11 * thereof, and that both notices appear in supporting documentation. 12 * 13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 16 * 17 * Carnegie Mellon requests users of this software to return to 18 * 19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 20 * School of Computer Science 21 * Carnegie Mellon University 22 * Pittsburgh PA 15213-3890 23 * 24 * any improvements or extensions that they make and grant Carnegie Mellon 25 * the rights to redistribute these changes. 26 */ 27/* 28 * scan.c - sup list file scanner 29 * 30 ********************************************************************** 31 * HISTORY 32 * Revision 1.8 92/08/11 12:04:28 mrt 33 * Brad's changes: delinted, added forward declarations of static 34 * functions.Added Copyright. 35 * [92/07/24 mrt] 36 * 37 * 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University 38 * Added host=<hostfile> support to releases file. 39 * 40 * 11-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University 41 * Added "rsymlink" recursive symbolic link quoting directive. 42 * 43 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University 44 * Added code for "release" support. 45 * 46 * 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University 47 * Lets see if we'll be able to write the scan file BEFORE 48 * we collect the data for it. Include sys/file.h and use 49 * new definitions for access check codes. 50 * 51 * 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University 52 * Added type casting information for lint. 53 * 54 * 21-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 55 * Added check for newonly upgrade when lasttime is the same as 56 * scantime. This will save us the trouble of parsing the scanfile 57 * when the client has successfully received everything in the 58 * scanfile already. 59 * 60 * 16-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 61 * Clear Texec pointers in execT so that Tfree of execT will not 62 * free command trees associated with files in listT. 63 * 64 * 06-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 65 * Added code to omit scanned files from list if we want new files 66 * only and they are old. 67 * 68 * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 69 * Major rewrite for protocol version 4. Added version numbers to 70 * scan file. Also added mode of file in addition to flags. 71 * Execute commands are now immediately after file information. 72 * 73 * 13-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 74 * Added comments to list file format. 75 * 76 * 08-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 77 * Added code to implement omitany. Currently doesn't know about 78 * {a,b,c} patterns. 79 * 80 * 07-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 81 * Created. 82 * 83 ********************************************************************** 84 */ 85 86#ifdef HAS_VIS 87#include <vis.h> 88#endif 89#include <sys/types.h> 90#include <sys/param.h> 91#include <sys/time.h> 92#include <sys/stat.h> 93#ifdef HAS_POSIX_DIR 94#include <dirent.h> 95#else 96#include <sys/dir.h> 97#endif 98#include <sys/file.h> 99#include <limits.h> 100#include <unistd.h> 101#include "supcdefs.h" 102#include "supextern.h" 103#include "libc.h" 104#include "c.h" 105 106/************************* 107 *** M A C R O S *** 108 *************************/ 109 110#define SPECNUMBER 1000 111 /* number of filenames produced by a single spec in the list file */ 112 113/******************************************* 114 *** D A T A S T R U C T U R E S *** 115 *******************************************/ 116 117typedef enum { /* release options */ 118 ONEXT, OPREFIX, OLIST, OSCAN, 119 OHOST 120} OPTION; 121 122static char *options[] = { 123 "next", "prefix", "list", "scan", 124 "host", 125 0 126}; 127 128typedef enum { /* <collection>/list file lines */ 129 LUPGRADE, LOMIT, LBACKUP, LEXECUTE, 130 LINCLUDE, LNOACCT, LOMITANY, LALWAYS, 131 LSYMLINK, LRSYMLINK 132} LISTTYPE; 133 134static char *ltname[] = { 135 "upgrade", "omit", "backup", "execute", 136 "include", "noaccount", "omitany", "always", 137 "symlink", "rsymlink", 138 0 139}; 140#define FALWAYS FUPDATE 141 142/* list file lines */ 143static TREE *upgT; /* files to upgrade */ 144static TREE *flagsT; /* special flags: BACKUP NOACCT */ 145static TREE *omitT; /* recursize file omition list */ 146static TREE *omanyT; /* non-recursize file omition list */ 147static TREE *symT; /* symbolic links to quote */ 148static TREE *rsymT; /* recursive symbolic links to quote */ 149static TREE *execT; /* execute command list */ 150 151/************************* 152 *** E X T E R N *** 153 *************************/ 154 155extern char _argbreak; /* break character from nxtarg */ 156 157extern TREELIST *listTL; /* list of trees for scanning */ 158extern TREE *listT; /* final list of files in collection */ 159extern TREE *refuseT; /* files refused by client */ 160 161extern char *collname; /* collection name */ 162extern char *basedir; /* base directory name */ 163extern char *prefix; /* collection pathname prefix */ 164extern time_t lasttime; /* time of last upgrade */ 165extern time_t scantime; /* time of this scan */ 166extern int trace; /* trace directories */ 167extern int newonly; /* new files only */ 168 169/************************************************* 170 *** STATIC R O U T I N E S *** 171 *************************************************/ 172static void passdelim(char **, char); 173static char *parserelease(TREELIST **, char *, char *); 174static int scanone(TREE *, void *); 175static void makescan(char *, char *); 176static void getscan(char *, char *); 177static void doscan(char *); 178static void readlistfile(char *); 179static void expTinsert(char *, TREE **, int, char *); 180static int listone(TREE *, void *); 181static void listentry(char *, char *, char *, int); 182static void listname(char *, struct stat *); 183static void listdir(char *, int); 184static int omitanyone(TREE *, void *); 185static int anyglob(char *, char *); 186static int getscanfile(char *); 187static void chkscanfile(char *); 188static void makescanfile(char *); 189static int recordone(TREE *, void *); 190static int recordexec(TREE *, void *); 191 192 193/************************************************* 194 *** L I S T S C A N R O U T I N E S *** 195 *************************************************/ 196 197static void 198passdelim(char **ptr, char delim) 199{ /* skip over delimiter */ 200 *ptr = skipover(*ptr, " \t"); 201 if (_argbreak != delim && **ptr == delim) { 202 (*ptr)++; 203 *ptr = skipover(*ptr, " \t"); 204 } 205} 206 207static char * 208parserelease(TREELIST ** tlp, char *relname, char *args) 209{ 210 TREELIST *tl; 211 char *arg; 212 OPTION option; 213 int opno; 214 char *nextrel; 215 216 tl = (TREELIST *) malloc(sizeof(TREELIST)); 217 if ((*tlp = tl) == NULL) 218 goaway("Couldn't allocate TREELIST"); 219 tl->TLnext = NULL; 220 tl->TLname = estrdup(relname); 221 tl->TLprefix = NULL; 222 tl->TLlist = NULL; 223 tl->TLscan = NULL; 224 tl->TLhost = NULL; 225 nextrel = NULL; 226 args = skipover(args, " \t"); 227 while (*(arg = nxtarg(&args, " \t="))) { 228 for (opno = 0; options[opno] != NULL; opno++) 229 if (strcmp(arg, options[opno]) == 0) 230 break; 231 if (options[opno] == NULL) 232 goaway("Invalid release option %s for release %s", 233 arg, relname); 234 option = (OPTION) opno; 235 switch (option) { 236 case ONEXT: 237 passdelim(&args, '='); 238 arg = nxtarg(&args, " \t"); 239 if (nextrel) 240 free(nextrel); 241 nextrel = estrdup(arg); 242 break; 243 case OPREFIX: 244 passdelim(&args, '='); 245 arg = nxtarg(&args, " \t"); 246 tl->TLprefix = estrdup(arg); 247 break; 248 case OLIST: 249 passdelim(&args, '='); 250 arg = nxtarg(&args, " \t"); 251 tl->TLlist = estrdup(arg); 252 break; 253 case OSCAN: 254 passdelim(&args, '='); 255 arg = nxtarg(&args, " \t"); 256 tl->TLscan = estrdup(arg); 257 break; 258 case OHOST: 259 passdelim(&args, '='); 260 arg = nxtarg(&args, " \t"); 261 tl->TLhost = estrdup(arg); 262 break; 263 } 264 } 265 return (nextrel); 266} 267 268int 269getrelease(char *release) 270{ 271 TREELIST *tl; 272 char buf[STRINGLENGTH]; 273 char *p, *q; 274 int rewound; 275 char *frelease = NULL; 276 FILE *f; 277 278 if (release == NULL) 279 frelease = release = estrdup(DEFRELEASE); 280 listTL = NULL; 281 282 (void) sprintf(buf, FILERELEASES, collname); 283 f = fopen(buf, "r"); 284 if (f != NULL) { 285 rewound = TRUE; 286 for (;;) { 287 p = fgets(buf, sizeof(buf), f); 288 if (p == NULL) { 289 if (rewound) 290 break; 291 rewind(f); 292 rewound = TRUE; 293 continue; 294 } 295 q = strchr(p, '\n'); 296 if (q) 297 *q = 0; 298 if (strchr("#;:", *p)) 299 continue; 300 q = nxtarg(&p, " \t"); 301 if (strcmp(q, release) != 0) 302 continue; 303 release = parserelease(&tl, release, p); 304 if (tl->TLprefix == NULL) 305 tl->TLprefix = prefix; 306 else if (chdir(tl->TLprefix) < 0) { 307 free(tl); 308 fclose(f); 309 if (frelease) 310 free(frelease); 311 return (FALSE); 312 } else 313 (void) chdir(basedir); 314 tl->TLnext = listTL; 315 listTL = tl; 316 if (release == NULL) 317 break; 318 rewound = FALSE; 319 } 320 (void) fclose(f); 321 } 322 if (release == NULL) { 323 if (frelease) 324 free(frelease); 325 return (TRUE); 326 } 327 if (strcmp(release, DEFRELEASE) != 0) { 328 if (frelease) 329 free(frelease); 330 return (FALSE); 331 } 332 (void) parserelease(&tl, release, ""); 333 tl->TLprefix = prefix; 334 tl->TLnext = listTL; 335 listTL = tl; 336 if (frelease) 337 free(frelease); 338 return (TRUE); 339} 340 341void 342makescanlists(void) 343{ 344 TREELIST *tl; 345 char buf[STRINGLENGTH]; 346 char *p, *q; 347 FILE *f; 348 char *saveprefix = prefix; 349 int count = 0; 350 351 (void) sprintf(buf, FILERELEASES, collname); 352 f = fopen(buf, "r"); 353 if (f != NULL) { 354 while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 355 q = strchr(p, '\n'); 356 if (q) 357 *q = 0; 358 if (strchr("#;:", *p)) 359 continue; 360 q = nxtarg(&p, " \t"); 361 (void) parserelease(&tl, q, p); 362 if ((prefix = tl->TLprefix) == NULL) 363 prefix = saveprefix; 364 if (prefix != NULL) { 365 if (chdir(prefix) < 0) 366 goaway("Can't chdir to %s", prefix); 367 (void) chdir(basedir); 368 } 369 makescan(tl->TLlist, tl->TLscan); 370 free(tl); 371 count++; 372 } 373 (void) fclose(f); 374 } 375 if (count == 0) 376 makescan(NULL, NULL); 377} 378 379static int 380scanone(TREE * t, void *v __unused) 381{ 382 TREE *newt; 383 384 if (newonly && (t->Tflags & FNEW) == 0) 385 return (SCMOK); 386 newt = Tinsert(&listT, t->Tname, FALSE); 387 if (newt == NULL) 388 return (SCMOK); 389 newt->Tmode = t->Tmode; 390 newt->Tflags = t->Tflags; 391 newt->Tmtime = t->Tmtime; 392 return (SCMOK); 393} 394 395void 396getscanlists(void) 397{ 398 TREELIST *tl, *stl; 399 400 stl = listTL; 401 listTL = NULL; 402 while ((tl = stl) != NULL) { 403 prefix = tl->TLprefix; 404 getscan(tl->TLlist, tl->TLscan); 405 tl->TLtree = listT; 406 stl = tl->TLnext; 407 tl->TLnext = listTL; 408 listTL = tl; 409 } 410 listT = NULL; 411 for (tl = listTL; tl != NULL; tl = tl->TLnext) 412 (void) Tprocess(tl->TLtree, scanone, NULL); 413} 414 415static void 416makescan(char *listfile, char *scanfile) 417{ 418 listT = NULL; 419 chkscanfile(scanfile); /* can we can write a scan file? */ 420 doscan(listfile); /* read list file and scan disk */ 421 makescanfile(scanfile); /* record names in scan file */ 422 Tfree(&listT); /* free file list tree */ 423} 424 425static void 426getscan(char *listfile, char *scanfile) 427{ 428 listT = NULL; 429 if (!getscanfile(scanfile)) { /* check for pre-scanned file list */ 430 scantime = time(NULL); 431 doscan(listfile); /* read list file and scan disk */ 432 } 433} 434 435static void 436doscan(char *listfile) 437{ 438 char buf[STRINGLENGTH]; 439 440 upgT = NULL; 441 flagsT = NULL; 442 omitT = NULL; 443 omanyT = NULL; 444 execT = NULL; 445 symT = NULL; 446 rsymT = NULL; 447 if (listfile == NULL) 448 listfile = FILELISTDEF; 449 (void) sprintf(buf, FILELIST, collname, listfile); 450 readlistfile(buf); /* get contents of list file */ 451 (void) Tprocess(upgT, listone, NULL); /* build list of files 452 * specified */ 453 cdprefix(NULL); 454 Tfree(&upgT); 455 Tfree(&flagsT); 456 Tfree(&omitT); 457 Tfree(&omanyT); 458 Tfree(&execT); 459 Tfree(&symT); 460 Tfree(&rsymT); 461} 462 463static void 464readlistfile(char *fname) 465{ 466 char buf[STRINGLENGTH + MAXPATHLEN * 4 + 1], *p; 467 char *q, *r; 468 FILE *f; 469 int ltn, n, i, flags; 470 TREE **t = NULL; 471 LISTTYPE lt; 472 char *speclist[SPECNUMBER]; 473 474 f = fopen(fname, "r"); 475 if (f == NULL) 476 goaway("Can't read list file %s", fname); 477 cdprefix(prefix); 478 while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 479 if ((q = strchr(p, '\n')) != NULL) 480 *q = '\0'; 481 if (strchr("#;:", *p)) 482 continue; 483 q = nxtarg(&p, " \t"); 484 if (*q == '\0') 485 continue; 486 for (ltn = 0; ltname[ltn] && strcmp(q, ltname[ltn]) != 0; ltn++); 487 if (ltname[ltn] == NULL) 488 goaway("Invalid list file keyword %s", q); 489 lt = (LISTTYPE) ltn; 490 flags = 0; 491 switch (lt) { 492 case LUPGRADE: 493 t = &upgT; 494 break; 495 case LBACKUP: 496 t = &flagsT; 497 flags = FBACKUP; 498 break; 499 case LNOACCT: 500 t = &flagsT; 501 flags = FNOACCT; 502 break; 503 case LSYMLINK: 504 t = &symT; 505 break; 506 case LRSYMLINK: 507 t = &rsymT; 508 break; 509 case LOMIT: 510 t = &omitT; 511 break; 512 case LOMITANY: 513 t = &omanyT; 514 break; 515 case LALWAYS: 516 t = &upgT; 517 flags = FALWAYS; 518 break; 519 case LINCLUDE: 520 while (*(q = nxtarg(&p, " \t"))) { 521 cdprefix(NULL); 522 n = expand(q, speclist, SPECNUMBER); 523 for (i = 0; i < n && i < SPECNUMBER; i++) { 524 readlistfile(speclist[i]); 525 cdprefix(NULL); 526 free(speclist[i]); 527 } 528 cdprefix(prefix); 529 } 530 continue; 531 case LEXECUTE: 532 r = p = q = skipover(p, " \t"); 533 do { 534 q = p = skipto(p, " \t("); 535 p = skipover(p, " \t"); 536 } while (*p != '(' && *p != '\0'); 537 if (*p++ == '(') { 538 *q = '\0'; 539 do { 540 q = nxtarg(&p, " \t)"); 541 if (*q == 0) 542 _argbreak = ')'; 543 else 544 expTinsert(q, &execT, 0, r); 545 } while (_argbreak != ')'); 546 continue; 547 } 548 /* FALLTHROUGH */ 549 default: 550 goaway("Error in handling list file keyword %d", ltn); 551 } 552 while (*(q = nxtarg(&p, " \t"))) { 553 if (lt == LOMITANY) 554 (void) Tinsert(t, q, FALSE); 555 else 556 expTinsert(q, t, flags, NULL); 557 } 558 } 559 (void) fclose(f); 560} 561 562static void 563expTinsert(char *p, TREE ** t, int flags, char *exec) 564{ 565 int n, i; 566 TREE *newt; 567 char *speclist[SPECNUMBER]; 568 char buf[STRINGLENGTH]; 569 570 n = expand(p, speclist, SPECNUMBER); 571 for (i = 0; i < n && i < SPECNUMBER; i++) { 572 newt = Tinsert(t, speclist[i], TRUE); 573 newt->Tflags |= flags; 574 if (exec) { 575 (void) sprintf(buf, exec, speclist[i]); 576 (void) Tinsert(&newt->Texec, buf, FALSE); 577 } 578 free(speclist[i]); 579 } 580} 581 582static int 583listone(TREE * t, void *v __unused) 584{ /* expand and add one name from upgrade list */ 585 listentry(t->Tname, t->Tname, NULL, (t->Tflags & FALWAYS) != 0); 586 return (SCMOK); 587} 588 589static void 590listentry(char *name, char *fullname, char *updir, int always) 591{ 592 struct stat statbuf; 593 int linkcount = 0; 594 595 if (Tlookup(refuseT, fullname)) 596 return; 597 if (!always) { 598 if (Tsearch(omitT, fullname)) 599 return; 600 if (Tprocess(omanyT, omitanyone, fullname) != SCMOK) 601 return; 602 } 603 if (lstat(name, &statbuf) < 0) 604 return; 605 if (S_ISLNK(statbuf.st_mode)) { 606 if (Tsearch(symT, fullname)) { 607 listname(fullname, &statbuf); 608 return; 609 } 610 if (Tlookup(rsymT, fullname)) { 611 listname(fullname, &statbuf); 612 return; 613 } 614 if (updir) 615 linkcount++; 616 if (stat(name, &statbuf) < 0) 617 return; 618 } 619 if (S_ISDIR(statbuf.st_mode)) { 620 if (access(name, R_OK | X_OK) < 0) 621 return; 622 if (chdir(name) < 0) 623 return; 624 listname(fullname, &statbuf); 625 if (trace) { 626 printf("Scanning directory %s\n", fullname); 627 (void) fflush(stdout); 628 } 629 listdir(fullname, always); 630 if (updir == 0 || linkcount) { 631 (void) chdir(basedir); 632 if (prefix) 633 (void) chdir(prefix); 634 if (updir && *updir) 635 (void) chdir(updir); 636 } else 637 (void) chdir(".."); 638 return; 639 } 640 if (access(name, R_OK) < 0) 641 return; 642 listname(fullname, &statbuf); 643} 644 645static void 646listname(char *name, struct stat * st) 647{ 648 TREE *t, *ts; 649 int new; 650 TREELIST *tl; 651 652 new = st->st_ctime > lasttime; 653 if (newonly && !new) { 654 for (tl = listTL; tl != NULL; tl = tl->TLnext) 655 if ((ts = Tsearch(tl->TLtree, name)) != NULL) 656 ts->Tflags &= ~FNEW; 657 return; 658 } 659 t = Tinsert(&listT, name, FALSE); 660 if (t == NULL) 661 return; 662 t->Tmode = st->st_mode; 663 t->Tctime = st->st_ctime; 664 t->Tmtime = st->st_mtime; 665 if (new) 666 t->Tflags |= FNEW; 667 if ((ts = Tsearch(flagsT, name)) != NULL) 668 t->Tflags |= ts->Tflags; 669 if ((ts = Tsearch(execT, name)) != NULL) { 670 t->Texec = ts->Texec; 671 ts->Texec = NULL; 672 } 673} 674 675static void 676listdir(char *name, int always) 677{ /* expand directory */ 678#ifdef HAS_POSIX_DIR 679 struct dirent *dentry; 680#else 681 struct direct *dentry; 682#endif 683 DIR *dirp; 684 char newname[STRINGLENGTH], filename[STRINGLENGTH]; 685 char *p, *newp; 686 687 dirp = opendir("."); 688 if (dirp == 0) 689 return; /* unreadable: probably protected */ 690 691 p = name; /* punt leading ./ and trailing / */ 692 newp = newname; 693 if (p[0] == '.' && p[1] == '/') { 694 p += 2; 695 while (*p == '/') 696 p++; 697 } 698 while ((*newp++ = *p++) != '\0'); /* copy string */ 699 --newp; /* trailing null */ 700 while (newp > newname && newp[-1] == '/') 701 --newp; /* trailing / */ 702 *newp = 0; 703 if (strcmp(newname, ".") == 0) 704 newname[0] = 0; /* "." ==> "" */ 705 706 while ((dentry = readdir(dirp)) != NULL) { 707 if (dentry->d_ino == 0) 708 continue; 709 if (strcmp(dentry->d_name, ".") == 0) 710 continue; 711 if (strcmp(dentry->d_name, "..") == 0) 712 continue; 713 if (*newname) { 714 (void)snprintf(filename, sizeof(filename), "%s/%s", 715 newname, dentry->d_name); 716 } else { 717 (void)strncpy(filename, dentry->d_name, 718 sizeof(filename) - 1); 719 filename[sizeof(filename) - 1] = '\0'; 720 } 721 listentry(dentry->d_name, filename, newname, always); 722 } 723 closedir(dirp); 724} 725 726static int 727omitanyone(TREE * t, void *fv) 728{ 729 char *filename = fv; 730 if (anyglob(t->Tname, filename)) 731 return (SCMERR); 732 return (SCMOK); 733} 734 735static int 736anyglob(char *pattern, char *match) 737{ 738 char *p, *m; 739 char *pb, *pe; 740 741 p = pattern; 742 m = match; 743 while (*m && *p == *m) { 744 p++; 745 m++; 746 } 747 if (*p == '\0' && *m == '\0') 748 return (TRUE); 749 switch (*p++) { 750 case '*': 751 for (;;) { 752 if (*p == '\0') 753 return (TRUE); 754 if (*m == '\0') 755 return (*p == '\0'); 756 if (anyglob(p, ++m)) 757 return (TRUE); 758 } 759 case '?': 760 return (anyglob(p, ++m)); 761 case '[': 762 pb = p; 763 while (*(++p) != ']') 764 if (*p == '\0') 765 return (FALSE); 766 pe = p; 767 for (p = pb + 1; p != pe; p++) { 768 switch (*p) { 769 case '-': 770 if (p == pb && *m == '-') { 771 p = pe + 1; 772 return (anyglob(p, ++m)); 773 } 774 if (p == pb) 775 continue; 776 if ((p + 1) == pe) 777 return (FALSE); 778 if (*m > *(p - 1) && 779 *m <= *(p + 1)) { 780 p = pe + 1; 781 return (anyglob(p, ++m)); 782 } 783 continue; 784 default: 785 if (*m == *p) { 786 p = pe + 1; 787 return (anyglob(p, ++m)); 788 } 789 } 790 } 791 return (FALSE); 792 default: 793 return (FALSE); 794 } 795} 796/***************************************** 797 *** R E A D S C A N F I L E *** 798 *****************************************/ 799 800static int 801getscanfile(char *scanfile) 802{ 803 char buf[STRINGLENGTH]; 804#ifdef HAS_VIS 805 char fname[MAXPATHLEN]; 806#else 807 char *fname; 808#endif 809 struct stat sbuf; 810 FILE *f; 811 TREE ts; 812 char *p, *q; 813 TREE *tmp, *t = NULL; 814 int notwanted; 815 TREELIST *tl; 816 817 if (scanfile == NULL) 818 scanfile = FILESCANDEF; 819 (void) sprintf(buf, FILESCAN, collname, scanfile); 820 if (stat(buf, &sbuf) < 0) 821 return (FALSE); 822 if ((f = fopen(buf, "r")) == NULL) 823 return (FALSE); 824 if ((p = fgets(buf, sizeof(buf), f)) == NULL) { 825 (void) fclose(f); 826 return (FALSE); 827 } 828 if ((q = strchr(p, '\n')) != NULL) 829 *q = '\0'; 830 if (*p++ != 'V') { 831 (void) fclose(f); 832 return (FALSE); 833 } 834 if (atoi(p) != SCANVERSION) { 835 (void) fclose(f); 836 return (FALSE); 837 } 838 scantime = sbuf.st_mtime; /* upgrade time is time of supscan, 839 * i.e. time of creation of scanfile */ 840 if (newonly && scantime == lasttime) { 841 (void) fclose(f); 842 return (TRUE); 843 } 844 notwanted = FALSE; 845 while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 846 q = strchr(p, '\n'); 847 if (q) 848 *q = 0; 849 ts.Tflags = 0; 850 if (*p == 'X') { 851 if (notwanted) 852 continue; 853 if (t == NULL) 854 goaway("scanfile format inconsistent"); 855 (void) Tinsert(&t->Texec, ++p, FALSE); 856 continue; 857 } 858 notwanted = FALSE; 859 if (*p == 'B') { 860 p++; 861 ts.Tflags |= FBACKUP; 862 } 863 if (*p == 'N') { 864 p++; 865 ts.Tflags |= FNOACCT; 866 } 867 if ((q = strchr(p, ' ')) == NULL) 868 goaway("scanfile format inconsistent"); 869 *q++ = '\0'; 870 ts.Tmode = atoo(p); 871 p = q; 872 if ((q = strchr(p, ' ')) == NULL) 873 goaway("scanfile format inconsistent"); 874 *q++ = '\0'; 875 ts.Tctime = atoi(p); 876 p = q; 877 if ((q = strchr(p, ' ')) == NULL) 878 goaway("scanfile format inconsistent"); 879 *q++ = 0; 880 ts.Tmtime = atoi(p); 881#ifdef HAS_VIS 882 (void) strunvis(fname, q); 883#else 884 fname = q; 885#endif 886 if (ts.Tctime > lasttime) 887 ts.Tflags |= FNEW; 888 else if (newonly) { 889 for (tl = listTL; tl != NULL; tl = tl->TLnext) 890 if ((tmp = Tsearch(tl->TLtree, fname)) != NULL) 891 tmp->Tflags &= ~FNEW; 892 notwanted = TRUE; 893 continue; 894 } 895 if (Tlookup(refuseT, fname)) { 896 notwanted = TRUE; 897 continue; 898 } 899 t = Tinsert(&listT, fname, TRUE); 900 t->Tmode = ts.Tmode; 901 t->Tflags = ts.Tflags; 902 t->Tctime = ts.Tctime; 903 t->Tmtime = ts.Tmtime; 904 } 905 (void) fclose(f); 906 return (TRUE); 907} 908/******************************************* 909 *** W R I T E S C A N F I L E *** 910 *******************************************/ 911 912static void 913chkscanfile(char *scanfile) 914{ 915 char tname[STRINGLENGTH], fname[STRINGLENGTH]; 916 FILE *f; 917 918 if (scanfile == NULL) 919 scanfile = FILESCANDEF; 920 (void) sprintf(fname, FILESCAN, collname, scanfile); 921 (void) sprintf(tname, "%s.temp", fname); 922 if (NULL == (f = fopen(tname, "w"))) 923 goaway("Can't test scan file temp %s for %s", tname, collname); 924 else { 925 (void) unlink(tname); 926 (void) fclose(f); 927 } 928} 929 930static void 931makescanfile(char *scanfile) 932{ 933 char tname[STRINGLENGTH], fname[STRINGLENGTH]; 934 struct timeval tbuf[2]; 935 FILE *scanF; /* output file for scanned file list */ 936 937 if (scanfile == NULL) 938 scanfile = FILESCANDEF; 939 (void) sprintf(fname, FILESCAN, collname, scanfile); 940 (void) sprintf(tname, "%s.temp", fname); 941 scanF = fopen(tname, "w"); 942 if (scanF == NULL) 943 goto out; 944 if (fprintf(scanF, "V%d\n", SCANVERSION) < 0) 945 goto closeout; 946 if (Tprocess(listT, recordone, scanF) != SCMOK) 947 goto closeout; 948 if (fclose(scanF) != 0) 949 goto out; 950 if (rename(tname, fname) < 0) { 951 (void)unlink(tname); 952 goaway("Can't change %s to %s", tname, fname); 953 } 954 tbuf[0].tv_sec = time(NULL); 955 tbuf[0].tv_usec = 0; 956 tbuf[1].tv_sec = scantime; 957 tbuf[1].tv_usec = 0; 958 (void) utimes(fname, tbuf); 959 return; 960closeout: 961 (void) fclose(scanF); 962out: 963 goaway("Can't write scan file temp %s for %s", tname, collname); 964} 965 966static int 967recordone(TREE * t, void *v) 968{ 969 FILE *scanF = v; 970#ifdef HAS_VIS 971 char fname[MAXPATHLEN * 4 + 1]; 972 strvis(fname, t->Tname, VIS_WHITE); 973#else 974 char *fname = t->Tname; 975#endif 976 977 if (t->Tflags & FBACKUP) 978 if (fprintf(scanF, "B") < 0) 979 return SCMERR; 980 if (t->Tflags & FNOACCT) 981 if (fprintf(scanF, "N") < 0) 982 return SCMERR; 983 if (fprintf(scanF, "%o %d %d %s\n", 984 t->Tmode, t->Tctime, t->Tmtime, fname) < 0) 985 return SCMERR; 986 return Tprocess(t->Texec, recordexec, scanF); 987} 988 989static int 990recordexec(TREE * t, void *v) 991{ 992 FILE *scanF = v; 993#ifdef HAS_VIS 994 char fname[MAXPATHLEN * 4 + 1]; 995 strvis(fname, t->Tname, VIS_WHITE); 996#else 997 char *fname = t->Tname; 998#endif 999 if (fprintf(scanF, "X%s\n", fname) < 0) 1000 return SCMERR; 1001 return (SCMOK); 1002} 1003 1004void 1005cdprefix(char *prefix) 1006{ 1007 static char *curprefix = NULL; 1008 1009 if (curprefix == NULL) { 1010 if (prefix == NULL) 1011 return; 1012 (void) chdir(prefix); 1013 curprefix = prefix; 1014 return; 1015 } 1016 if (prefix == NULL) { 1017 (void) chdir(basedir); 1018 curprefix = NULL; 1019 return; 1020 } 1021 if (prefix == curprefix) 1022 return; 1023 if (strcmp(prefix, curprefix) == 0) { 1024 curprefix = prefix; 1025 return; 1026 } 1027 (void) chdir(basedir); 1028 (void) chdir(prefix); 1029 curprefix = prefix; 1030} 1031