Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / scan.c
blobb7c3532f25ff514e5eb3e3851d7b8da326d47063
1 /* $NetBSD: scan.c,v 1.26 2007/12/20 20:15:59 christos Exp $ */
3 /*
4 * Copyright (c) 1992 Carnegie Mellon University
5 * All Rights Reserved.
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.
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.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
28 * scan.c - sup list file scanner
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]
37 * 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
38 * Added host=<hostfile> support to releases file.
40 * 11-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
41 * Added "rsymlink" recursive symbolic link quoting directive.
43 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
44 * Added code for "release" support.
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.
51 * 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
52 * Added type casting information for lint.
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.
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.
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.
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.
73 * 13-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
74 * Added comments to list file format.
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.
80 * 07-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
81 * Created.
83 **********************************************************************
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"
106 /*************************
107 *** M A C R O S ***
108 *************************/
110 #define SPECNUMBER 1000
111 /* number of filenames produced by a single spec in the list file */
113 /*******************************************
114 *** D A T A S T R U C T U R E S ***
115 *******************************************/
117 typedef enum { /* release options */
118 ONEXT, OPREFIX, OLIST, OSCAN,
119 OHOST
120 } OPTION;
122 static char *options[] = {
123 "next", "prefix", "list", "scan",
124 "host",
128 typedef enum { /* <collection>/list file lines */
129 LUPGRADE, LOMIT, LBACKUP, LEXECUTE,
130 LINCLUDE, LNOACCT, LOMITANY, LALWAYS,
131 LSYMLINK, LRSYMLINK
132 } LISTTYPE;
134 static char *ltname[] = {
135 "upgrade", "omit", "backup", "execute",
136 "include", "noaccount", "omitany", "always",
137 "symlink", "rsymlink",
140 #define FALWAYS FUPDATE
142 /* list file lines */
143 static TREE *upgT; /* files to upgrade */
144 static TREE *flagsT; /* special flags: BACKUP NOACCT */
145 static TREE *omitT; /* recursize file omition list */
146 static TREE *omanyT; /* non-recursize file omition list */
147 static TREE *symT; /* symbolic links to quote */
148 static TREE *rsymT; /* recursive symbolic links to quote */
149 static TREE *execT; /* execute command list */
151 /*************************
152 *** E X T E R N ***
153 *************************/
155 extern char _argbreak; /* break character from nxtarg */
157 extern TREELIST *listTL; /* list of trees for scanning */
158 extern TREE *listT; /* final list of files in collection */
159 extern TREE *refuseT; /* files refused by client */
161 extern char *collname; /* collection name */
162 extern char *basedir; /* base directory name */
163 extern char *prefix; /* collection pathname prefix */
164 extern time_t lasttime; /* time of last upgrade */
165 extern time_t scantime; /* time of this scan */
166 extern int trace; /* trace directories */
167 extern int newonly; /* new files only */
169 #ifdef RCSSTAT
170 extern char *rcs_branch;
171 extern int candorcs;
172 #endif
174 /*************************************************
175 *** STATIC R O U T I N E S ***
176 *************************************************/
177 static void passdelim(char **, char);
178 static char *parserelease(TREELIST **, char *, char *);
179 static int scanone(TREE *, void *);
180 static void makescan(char *, char *);
181 static void getscan(char *, char *);
182 static void doscan(char *);
183 static void readlistfile(char *);
184 static void expTinsert(char *, TREE **, int, char *);
185 static int listone(TREE *, void *);
186 static void listentry(char *, char *, char *, int);
187 static void listname(char *, struct stat *);
188 static void listdir(char *, int);
189 static int omitanyone(TREE *, void *);
190 static int anyglob(char *, char *);
191 static int getscanfile(char *);
192 static void chkscanfile(char *);
193 static void makescanfile(char *);
194 static int recordone(TREE *, void *);
195 static int recordexec(TREE *, void *);
198 /*************************************************
199 *** L I S T S C A N R O U T I N E S ***
200 *************************************************/
202 static void
203 passdelim(char **ptr, char delim)
204 { /* skip over delimiter */
205 *ptr = skipover(*ptr, " \t");
206 if (_argbreak != delim && **ptr == delim) {
207 (*ptr)++;
208 *ptr = skipover(*ptr, " \t");
212 static char *
213 parserelease(TREELIST ** tlp, char *relname, char *args)
215 TREELIST *tl;
216 char *arg;
217 OPTION option;
218 int opno;
219 char *nextrel;
221 tl = (TREELIST *) malloc(sizeof(TREELIST));
222 if ((*tlp = tl) == NULL)
223 goaway("Couldn't allocate TREELIST");
224 tl->TLnext = NULL;
225 tl->TLname = estrdup(relname);
226 tl->TLprefix = NULL;
227 tl->TLlist = NULL;
228 tl->TLscan = NULL;
229 tl->TLhost = NULL;
230 nextrel = NULL;
231 args = skipover(args, " \t");
232 while (*(arg = nxtarg(&args, " \t="))) {
233 for (opno = 0; options[opno] != NULL; opno++)
234 if (strcmp(arg, options[opno]) == 0)
235 break;
236 if (options[opno] == NULL)
237 goaway("Invalid release option %s for release %s",
238 arg, relname);
239 option = (OPTION) opno;
240 switch (option) {
241 case ONEXT:
242 passdelim(&args, '=');
243 arg = nxtarg(&args, " \t");
244 if (nextrel)
245 free(nextrel);
246 nextrel = estrdup(arg);
247 break;
248 case OPREFIX:
249 passdelim(&args, '=');
250 arg = nxtarg(&args, " \t");
251 tl->TLprefix = estrdup(arg);
252 break;
253 case OLIST:
254 passdelim(&args, '=');
255 arg = nxtarg(&args, " \t");
256 tl->TLlist = estrdup(arg);
257 break;
258 case OSCAN:
259 passdelim(&args, '=');
260 arg = nxtarg(&args, " \t");
261 tl->TLscan = estrdup(arg);
262 break;
263 case OHOST:
264 passdelim(&args, '=');
265 arg = nxtarg(&args, " \t");
266 tl->TLhost = estrdup(arg);
267 break;
270 return (nextrel);
274 getrelease(char *release)
276 TREELIST *tl;
277 char buf[STRINGLENGTH];
278 char *p, *q;
279 int rewound;
280 char *frelease = NULL;
281 FILE *f;
283 if (release == NULL)
284 frelease = release = estrdup(DEFRELEASE);
285 listTL = NULL;
287 (void) sprintf(buf, FILERELEASES, collname);
288 f = fopen(buf, "r");
289 if (f != NULL) {
290 rewound = TRUE;
291 for (;;) {
292 p = fgets(buf, sizeof(buf), f);
293 if (p == NULL) {
294 if (rewound)
295 break;
296 rewind(f);
297 rewound = TRUE;
298 continue;
300 q = strchr(p, '\n');
301 if (q)
302 *q = 0;
303 if (strchr("#;:", *p))
304 continue;
305 q = nxtarg(&p, " \t");
306 if (strcmp(q, release) != 0)
307 continue;
308 release = parserelease(&tl, release, p);
309 if (tl->TLprefix == NULL)
310 tl->TLprefix = prefix;
311 else if (chdir(tl->TLprefix) < 0) {
312 free(tl);
313 fclose(f);
314 if (frelease)
315 free(frelease);
316 return (FALSE);
317 } else
318 (void) chdir(basedir);
319 tl->TLnext = listTL;
320 listTL = tl;
321 if (release == NULL)
322 break;
323 rewound = FALSE;
325 (void) fclose(f);
327 if (release == NULL) {
328 if (frelease)
329 free(frelease);
330 return (TRUE);
332 if (strcmp(release, DEFRELEASE) != 0) {
333 if (frelease)
334 free(frelease);
335 return (FALSE);
337 (void) parserelease(&tl, release, "");
338 tl->TLprefix = prefix;
339 tl->TLnext = listTL;
340 listTL = tl;
341 if (frelease)
342 free(frelease);
343 return (TRUE);
346 void
347 makescanlists(void)
349 TREELIST *tl;
350 char buf[STRINGLENGTH];
351 char *p, *q;
352 FILE *f;
353 char *saveprefix = prefix;
354 int count = 0;
356 (void) sprintf(buf, FILERELEASES, collname);
357 f = fopen(buf, "r");
358 if (f != NULL) {
359 while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
360 q = strchr(p, '\n');
361 if (q)
362 *q = 0;
363 if (strchr("#;:", *p))
364 continue;
365 q = nxtarg(&p, " \t");
366 (void) parserelease(&tl, q, p);
367 if ((prefix = tl->TLprefix) == NULL)
368 prefix = saveprefix;
369 if (prefix != NULL) {
370 if (chdir(prefix) < 0)
371 goaway("Can't chdir to %s", prefix);
372 (void) chdir(basedir);
374 makescan(tl->TLlist, tl->TLscan);
375 free(tl);
376 count++;
378 (void) fclose(f);
380 if (count == 0)
381 makescan((char *) NULL, (char *) NULL);
384 static int
385 scanone(TREE * t, void *v __unused)
387 TREE *newt;
389 if (newonly && (t->Tflags & FNEW) == 0)
390 return (SCMOK);
391 newt = Tinsert(&listT, t->Tname, FALSE);
392 if (newt == NULL)
393 return (SCMOK);
394 newt->Tmode = t->Tmode;
395 newt->Tflags = t->Tflags;
396 newt->Tmtime = t->Tmtime;
397 return (SCMOK);
400 void
401 getscanlists(void)
403 TREELIST *tl, *stl;
405 stl = listTL;
406 listTL = NULL;
407 while ((tl = stl) != NULL) {
408 prefix = tl->TLprefix;
409 getscan(tl->TLlist, tl->TLscan);
410 tl->TLtree = listT;
411 stl = tl->TLnext;
412 tl->TLnext = listTL;
413 listTL = tl;
415 listT = NULL;
416 for (tl = listTL; tl != NULL; tl = tl->TLnext)
417 (void) Tprocess(tl->TLtree, scanone, NULL);
420 static void
421 makescan(char *listfile, char *scanfile)
423 listT = NULL;
424 chkscanfile(scanfile); /* can we can write a scan file? */
425 doscan(listfile); /* read list file and scan disk */
426 makescanfile(scanfile); /* record names in scan file */
427 Tfree(&listT); /* free file list tree */
430 static void
431 getscan(char *listfile, char *scanfile)
433 listT = NULL;
434 if (!getscanfile(scanfile)) { /* check for pre-scanned file list */
435 scantime = time((time_t *) NULL);
436 doscan(listfile); /* read list file and scan disk */
440 static void
441 doscan(char *listfile)
443 char buf[STRINGLENGTH];
445 upgT = NULL;
446 flagsT = NULL;
447 omitT = NULL;
448 omanyT = NULL;
449 execT = NULL;
450 symT = NULL;
451 rsymT = NULL;
452 if (listfile == NULL)
453 listfile = FILELISTDEF;
454 (void) sprintf(buf, FILELIST, collname, listfile);
455 readlistfile(buf); /* get contents of list file */
456 (void) Tprocess(upgT, listone, NULL); /* build list of files
457 * specified */
458 cdprefix((char *) NULL);
459 Tfree(&upgT);
460 Tfree(&flagsT);
461 Tfree(&omitT);
462 Tfree(&omanyT);
463 Tfree(&execT);
464 Tfree(&symT);
465 Tfree(&rsymT);
468 static void
469 readlistfile(char *fname)
471 char buf[STRINGLENGTH + MAXPATHLEN * 4 + 1], *p;
472 char *q, *r;
473 FILE *f;
474 int ltn, n, i, flags;
475 TREE **t = NULL;
476 LISTTYPE lt;
477 char *speclist[SPECNUMBER];
479 f = fopen(fname, "r");
480 if (f == NULL)
481 goaway("Can't read list file %s", fname);
482 cdprefix(prefix);
483 while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
484 if ((q = strchr(p, '\n')) != NULL)
485 *q = '\0';
486 if (strchr("#;:", *p))
487 continue;
488 q = nxtarg(&p, " \t");
489 if (*q == '\0')
490 continue;
491 for (ltn = 0; ltname[ltn] && strcmp(q, ltname[ltn]) != 0; ltn++);
492 if (ltname[ltn] == NULL)
493 goaway("Invalid list file keyword %s", q);
494 lt = (LISTTYPE) ltn;
495 flags = 0;
496 switch (lt) {
497 case LUPGRADE:
498 t = &upgT;
499 break;
500 case LBACKUP:
501 t = &flagsT;
502 flags = FBACKUP;
503 break;
504 case LNOACCT:
505 t = &flagsT;
506 flags = FNOACCT;
507 break;
508 case LSYMLINK:
509 t = &symT;
510 break;
511 case LRSYMLINK:
512 t = &rsymT;
513 break;
514 case LOMIT:
515 t = &omitT;
516 break;
517 case LOMITANY:
518 t = &omanyT;
519 break;
520 case LALWAYS:
521 t = &upgT;
522 flags = FALWAYS;
523 break;
524 case LINCLUDE:
525 while (*(q = nxtarg(&p, " \t"))) {
526 cdprefix((char *) NULL);
527 n = expand(q, speclist, SPECNUMBER);
528 for (i = 0; i < n && i < SPECNUMBER; i++) {
529 readlistfile(speclist[i]);
530 cdprefix((char *) NULL);
531 free(speclist[i]);
533 cdprefix(prefix);
535 continue;
536 case LEXECUTE:
537 r = p = q = skipover(p, " \t");
538 do {
539 q = p = skipto(p, " \t(");
540 p = skipover(p, " \t");
541 } while (*p != '(' && *p != '\0');
542 if (*p++ == '(') {
543 *q = '\0';
544 do {
545 q = nxtarg(&p, " \t)");
546 if (*q == 0)
547 _argbreak = ')';
548 else
549 expTinsert(q, &execT, 0, r);
550 } while (_argbreak != ')');
551 continue;
553 /* FALLTHROUGH */
554 default:
555 goaway("Error in handling list file keyword %d", ltn);
557 while (*(q = nxtarg(&p, " \t"))) {
558 if (lt == LOMITANY)
559 (void) Tinsert(t, q, FALSE);
560 else
561 expTinsert(q, t, flags, (char *) NULL);
564 (void) fclose(f);
567 static void
568 expTinsert(char *p, TREE ** t, int flags, char *exec)
570 int n, i;
571 TREE *newt;
572 char *speclist[SPECNUMBER];
573 char buf[STRINGLENGTH];
575 n = expand(p, speclist, SPECNUMBER);
576 for (i = 0; i < n && i < SPECNUMBER; i++) {
577 newt = Tinsert(t, speclist[i], TRUE);
578 newt->Tflags |= flags;
579 if (exec) {
580 (void) sprintf(buf, exec, speclist[i]);
581 (void) Tinsert(&newt->Texec, buf, FALSE);
583 free(speclist[i]);
587 static int
588 listone(TREE * t, void *v __unused)
589 { /* expand and add one name from upgrade list */
590 listentry(t->Tname, t->Tname, (char *) NULL, (t->Tflags & FALWAYS) != 0);
591 return (SCMOK);
594 static void
595 listentry(char *name, char *fullname, char *updir, int always)
597 struct stat statbuf;
598 int linkcount = 0;
600 if (Tlookup(refuseT, fullname))
601 return;
602 if (!always) {
603 if (Tsearch(omitT, fullname))
604 return;
605 if (Tprocess(omanyT, omitanyone, fullname) != SCMOK)
606 return;
608 if (lstat(name, &statbuf) < 0)
609 return;
610 if (S_ISLNK(statbuf.st_mode)) {
611 if (Tsearch(symT, fullname)) {
612 listname(fullname, &statbuf);
613 return;
615 if (Tlookup(rsymT, fullname)) {
616 listname(fullname, &statbuf);
617 return;
619 if (updir)
620 linkcount++;
621 if (stat(name, &statbuf) < 0)
622 return;
624 if (S_ISDIR(statbuf.st_mode)) {
625 if (access(name, R_OK | X_OK) < 0)
626 return;
627 if (chdir(name) < 0)
628 return;
629 listname(fullname, &statbuf);
630 if (trace) {
631 printf("Scanning directory %s\n", fullname);
632 (void) fflush(stdout);
634 listdir(fullname, always);
635 if (updir == 0 || linkcount) {
636 (void) chdir(basedir);
637 if (prefix)
638 (void) chdir(prefix);
639 if (updir && *updir)
640 (void) chdir(updir);
641 } else
642 (void) chdir("..");
643 return;
645 if (access(name, R_OK) < 0)
646 return;
647 #ifdef RCSSTAT
648 if (candorcs) {
649 char rcs_release[STRINGLENGTH];
650 int status;
651 if (rcs_branch != NULL)
652 #ifdef CVS
653 sprintf(rcs_release, "-r %s", rcs_branch);
654 #else
655 sprintf(rcs_release, "-r%s", rcs_branch);
656 #endif
657 else
658 rcs_release[0] = '\0';
659 #ifdef CVS
660 sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, name, rcs_file);
661 #else
662 status = runp("rcsstat", "rcsstat", "-q", rcs_release, name, 0);
663 #endif
664 if (status != 0)
665 return;
667 #endif
668 listname(fullname, &statbuf);
671 static void
672 listname(char *name, struct stat * st)
674 TREE *t, *ts;
675 int new;
676 TREELIST *tl;
678 new = st->st_ctime > lasttime;
679 if (newonly && !new) {
680 for (tl = listTL; tl != NULL; tl = tl->TLnext)
681 if ((ts = Tsearch(tl->TLtree, name)) != NULL)
682 ts->Tflags &= ~FNEW;
683 return;
685 t = Tinsert(&listT, name, FALSE);
686 if (t == NULL)
687 return;
688 t->Tmode = st->st_mode;
689 t->Tctime = st->st_ctime;
690 t->Tmtime = st->st_mtime;
691 if (new)
692 t->Tflags |= FNEW;
693 if ((ts = Tsearch(flagsT, name)) != NULL)
694 t->Tflags |= ts->Tflags;
695 if ((ts = Tsearch(execT, name)) != NULL) {
696 t->Texec = ts->Texec;
697 ts->Texec = NULL;
701 static void
702 listdir(char *name, int always)
703 { /* expand directory */
704 #ifdef HAS_POSIX_DIR
705 struct dirent *dentry;
706 #else
707 struct direct *dentry;
708 #endif
709 DIR *dirp;
710 char newname[STRINGLENGTH], filename[STRINGLENGTH];
711 char *p, *newp;
713 dirp = opendir(".");
714 if (dirp == 0)
715 return; /* unreadable: probably protected */
717 p = name; /* punt leading ./ and trailing / */
718 newp = newname;
719 if (p[0] == '.' && p[1] == '/') {
720 p += 2;
721 while (*p == '/')
722 p++;
724 while ((*newp++ = *p++) != '\0'); /* copy string */
725 --newp; /* trailing null */
726 while (newp > newname && newp[-1] == '/')
727 --newp; /* trailing / */
728 *newp = 0;
729 if (strcmp(newname, ".") == 0)
730 newname[0] = 0; /* "." ==> "" */
732 while ((dentry = readdir(dirp)) != NULL) {
733 if (dentry->d_ino == 0)
734 continue;
735 if (strcmp(dentry->d_name, ".") == 0)
736 continue;
737 if (strcmp(dentry->d_name, "..") == 0)
738 continue;
739 if (*newname) {
740 (void)snprintf(filename, sizeof(filename), "%s/%s",
741 newname, dentry->d_name);
742 } else {
743 (void)strncpy(filename, dentry->d_name,
744 sizeof(filename) - 1);
745 filename[sizeof(filename) - 1] = '\0';
747 listentry(dentry->d_name, filename, newname, always);
749 closedir(dirp);
752 static int
753 omitanyone(TREE * t, void *fv)
755 char *filename = fv;
756 if (anyglob(t->Tname, filename))
757 return (SCMERR);
758 return (SCMOK);
761 static int
762 anyglob(char *pattern, char *match)
764 char *p, *m;
765 char *pb, *pe;
767 p = pattern;
768 m = match;
769 while (*m && *p == *m) {
770 p++;
771 m++;
773 if (*p == '\0' && *m == '\0')
774 return (TRUE);
775 switch (*p++) {
776 case '*':
777 for (;;) {
778 if (*p == '\0')
779 return (TRUE);
780 if (*m == '\0')
781 return (*p == '\0');
782 if (anyglob(p, ++m))
783 return (TRUE);
785 case '?':
786 return (anyglob(p, ++m));
787 case '[':
788 pb = p;
789 while (*(++p) != ']')
790 if (*p == '\0')
791 return (FALSE);
792 pe = p;
793 for (p = pb + 1; p != pe; p++) {
794 switch (*p) {
795 case '-':
796 if (p == pb && *m == '-') {
797 p = pe + 1;
798 return (anyglob(p, ++m));
800 if (p == pb)
801 continue;
802 if ((p + 1) == pe)
803 return (FALSE);
804 if (*m > *(p - 1) &&
805 *m <= *(p + 1)) {
806 p = pe + 1;
807 return (anyglob(p, ++m));
809 continue;
810 default:
811 if (*m == *p) {
812 p = pe + 1;
813 return (anyglob(p, ++m));
817 return (FALSE);
818 default:
819 return (FALSE);
822 /*****************************************
823 *** R E A D S C A N F I L E ***
824 *****************************************/
826 static int
827 getscanfile(char *scanfile)
829 char buf[STRINGLENGTH];
830 #ifdef HAS_VIS
831 char fname[MAXPATHLEN];
832 #else
833 char *fname;
834 #endif
835 struct stat sbuf;
836 FILE *f;
837 TREE ts;
838 char *p, *q;
839 TREE *tmp, *t = NULL;
840 int notwanted;
841 TREELIST *tl;
843 if (scanfile == NULL)
844 scanfile = FILESCANDEF;
845 (void) sprintf(buf, FILESCAN, collname, scanfile);
846 if (stat(buf, &sbuf) < 0)
847 return (FALSE);
848 if ((f = fopen(buf, "r")) == NULL)
849 return (FALSE);
850 if ((p = fgets(buf, sizeof(buf), f)) == NULL) {
851 (void) fclose(f);
852 return (FALSE);
854 if ((q = strchr(p, '\n')) != NULL)
855 *q = '\0';
856 if (*p++ != 'V') {
857 (void) fclose(f);
858 return (FALSE);
860 if (atoi(p) != SCANVERSION) {
861 (void) fclose(f);
862 return (FALSE);
864 scantime = sbuf.st_mtime; /* upgrade time is time of supscan,
865 * i.e. time of creation of scanfile */
866 if (newonly && scantime == lasttime) {
867 (void) fclose(f);
868 return (TRUE);
870 notwanted = FALSE;
871 while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
872 q = strchr(p, '\n');
873 if (q)
874 *q = 0;
875 ts.Tflags = 0;
876 if (*p == 'X') {
877 if (notwanted)
878 continue;
879 if (t == NULL)
880 goaway("scanfile format inconsistent");
881 (void) Tinsert(&t->Texec, ++p, FALSE);
882 continue;
884 notwanted = FALSE;
885 if (*p == 'B') {
886 p++;
887 ts.Tflags |= FBACKUP;
889 if (*p == 'N') {
890 p++;
891 ts.Tflags |= FNOACCT;
893 if ((q = strchr(p, ' ')) == NULL)
894 goaway("scanfile format inconsistent");
895 *q++ = '\0';
896 ts.Tmode = atoo(p);
897 p = q;
898 if ((q = strchr(p, ' ')) == NULL)
899 goaway("scanfile format inconsistent");
900 *q++ = '\0';
901 ts.Tctime = atoi(p);
902 p = q;
903 if ((q = strchr(p, ' ')) == NULL)
904 goaway("scanfile format inconsistent");
905 *q++ = 0;
906 ts.Tmtime = atoi(p);
907 #ifdef HAS_VIS
908 (void) strunvis(fname, q);
909 #else
910 fname = q;
911 #endif
912 if (ts.Tctime > lasttime)
913 ts.Tflags |= FNEW;
914 else if (newonly) {
915 for (tl = listTL; tl != NULL; tl = tl->TLnext)
916 if ((tmp = Tsearch(tl->TLtree, fname)) != NULL)
917 tmp->Tflags &= ~FNEW;
918 notwanted = TRUE;
919 continue;
921 if (Tlookup(refuseT, fname)) {
922 notwanted = TRUE;
923 continue;
925 t = Tinsert(&listT, fname, TRUE);
926 t->Tmode = ts.Tmode;
927 t->Tflags = ts.Tflags;
928 t->Tctime = ts.Tctime;
929 t->Tmtime = ts.Tmtime;
931 (void) fclose(f);
932 return (TRUE);
934 /*******************************************
935 *** W R I T E S C A N F I L E ***
936 *******************************************/
938 static void
939 chkscanfile(char *scanfile)
941 char tname[STRINGLENGTH], fname[STRINGLENGTH];
942 FILE *f;
944 if (scanfile == NULL)
945 scanfile = FILESCANDEF;
946 (void) sprintf(fname, FILESCAN, collname, scanfile);
947 (void) sprintf(tname, "%s.temp", fname);
948 if (NULL == (f = fopen(tname, "w")))
949 goaway("Can't test scan file temp %s for %s", tname, collname);
950 else {
951 (void) unlink(tname);
952 (void) fclose(f);
956 static void
957 makescanfile(char *scanfile)
959 char tname[STRINGLENGTH], fname[STRINGLENGTH];
960 struct timeval tbuf[2];
961 FILE *scanF; /* output file for scanned file list */
963 if (scanfile == NULL)
964 scanfile = FILESCANDEF;
965 (void) sprintf(fname, FILESCAN, collname, scanfile);
966 (void) sprintf(tname, "%s.temp", fname);
967 scanF = fopen(tname, "w");
968 if (scanF == NULL)
969 goto out;
970 if (fprintf(scanF, "V%d\n", SCANVERSION) < 0)
971 goto out;
972 if (Tprocess(listT, recordone, scanF) != SCMOK)
973 goto out;
974 if (fclose(scanF) != 0)
975 goto out;
976 if (rename(tname, fname) < 0) {
977 (void)unlink(tname);
978 goaway("Can't change %s to %s", tname, fname);
980 tbuf[0].tv_sec = time((time_t *) NULL);
981 tbuf[0].tv_usec = 0;
982 tbuf[1].tv_sec = scantime;
983 tbuf[1].tv_usec = 0;
984 (void) utimes(fname, tbuf);
985 return;
986 out:
987 goaway("Can't write scan file temp %s for %s", tname, collname);
990 static int
991 recordone(TREE * t, void *v)
993 FILE *scanF = v;
994 #ifdef HAS_VIS
995 char fname[MAXPATHLEN * 4 + 1];
996 strvis(fname, t->Tname, VIS_WHITE);
997 #else
998 char *fname = t->Tname;
999 #endif
1001 if (t->Tflags & FBACKUP)
1002 if (fprintf(scanF, "B") < 0)
1003 return SCMERR;
1004 if (t->Tflags & FNOACCT)
1005 if (fprintf(scanF, "N") < 0)
1006 return SCMERR;
1007 if (fprintf(scanF, "%o %d %d %s\n",
1008 t->Tmode, t->Tctime, t->Tmtime, fname) < 0)
1009 return SCMERR;
1010 return Tprocess(t->Texec, recordexec, scanF);
1013 static int
1014 recordexec(TREE * t, void *v)
1016 FILE *scanF = v;
1017 #ifdef HAS_VIS
1018 char fname[MAXPATHLEN * 4 + 1];
1019 strvis(fname, t->Tname, VIS_WHITE);
1020 #else
1021 char *fname = t->Tname;
1022 #endif
1023 if (fprintf(scanF, "X%s\n", fname) < 0)
1024 return SCMERR;
1025 return (SCMOK);
1028 void
1029 cdprefix(char *prefix)
1031 static char *curprefix = NULL;
1033 if (curprefix == NULL) {
1034 if (prefix == NULL)
1035 return;
1036 (void) chdir(prefix);
1037 curprefix = prefix;
1038 return;
1040 if (prefix == NULL) {
1041 (void) chdir(basedir);
1042 curprefix = NULL;
1043 return;
1045 if (prefix == curprefix)
1046 return;
1047 if (strcmp(prefix, curprefix) == 0) {
1048 curprefix = prefix;
1049 return;
1051 (void) chdir(basedir);
1052 (void) chdir(prefix);
1053 curprefix = prefix;