1055 lines
24 KiB
C
1055 lines
24 KiB
C
/* $NetBSD: scan.c,v 1.27 2009/10/17 20:46:03 christos Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1992 Carnegie Mellon University
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission to use, copy, modify and distribute this software and its
|
|
* documentation is hereby granted, provided that both the copyright
|
|
* notice and this permission notice appear in all copies of the
|
|
* software, derivative works or modified versions, and any portions
|
|
* thereof, and that both notices appear in supporting documentation.
|
|
*
|
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
|
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
*
|
|
* Carnegie Mellon requests users of this software to return to
|
|
*
|
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
* School of Computer Science
|
|
* Carnegie Mellon University
|
|
* Pittsburgh PA 15213-3890
|
|
*
|
|
* any improvements or extensions that they make and grant Carnegie Mellon
|
|
* the rights to redistribute these changes.
|
|
*/
|
|
/*
|
|
* scan.c - sup list file scanner
|
|
*
|
|
**********************************************************************
|
|
* HISTORY
|
|
* Revision 1.8 92/08/11 12:04:28 mrt
|
|
* Brad's changes: delinted, added forward declarations of static
|
|
* functions.Added Copyright.
|
|
* [92/07/24 mrt]
|
|
*
|
|
* 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added host=<hostfile> support to releases file.
|
|
*
|
|
* 11-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added "rsymlink" recursive symbolic link quoting directive.
|
|
*
|
|
* 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added code for "release" support.
|
|
*
|
|
* 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
|
|
* Lets see if we'll be able to write the scan file BEFORE
|
|
* we collect the data for it. Include sys/file.h and use
|
|
* new definitions for access check codes.
|
|
*
|
|
* 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added type casting information for lint.
|
|
*
|
|
* 21-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added check for newonly upgrade when lasttime is the same as
|
|
* scantime. This will save us the trouble of parsing the scanfile
|
|
* when the client has successfully received everything in the
|
|
* scanfile already.
|
|
*
|
|
* 16-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Clear Texec pointers in execT so that Tfree of execT will not
|
|
* free command trees associated with files in listT.
|
|
*
|
|
* 06-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added code to omit scanned files from list if we want new files
|
|
* only and they are old.
|
|
*
|
|
* 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Major rewrite for protocol version 4. Added version numbers to
|
|
* scan file. Also added mode of file in addition to flags.
|
|
* Execute commands are now immediately after file information.
|
|
*
|
|
* 13-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added comments to list file format.
|
|
*
|
|
* 08-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Added code to implement omitany. Currently doesn't know about
|
|
* {a,b,c} patterns.
|
|
*
|
|
* 07-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
|
* Created.
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
#ifdef HAS_VIS
|
|
#include <vis.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#ifdef HAS_POSIX_DIR
|
|
#include <dirent.h>
|
|
#else
|
|
#include <sys/dir.h>
|
|
#endif
|
|
#include <sys/file.h>
|
|
#include <limits.h>
|
|
#include <unistd.h>
|
|
#include "supcdefs.h"
|
|
#include "supextern.h"
|
|
#include "libc.h"
|
|
#include "c.h"
|
|
|
|
/*************************
|
|
*** M A C R O S ***
|
|
*************************/
|
|
|
|
#define SPECNUMBER 1000
|
|
/* number of filenames produced by a single spec in the list file */
|
|
|
|
/*******************************************
|
|
*** D A T A S T R U C T U R E S ***
|
|
*******************************************/
|
|
|
|
typedef enum { /* release options */
|
|
ONEXT, OPREFIX, OLIST, OSCAN,
|
|
OHOST
|
|
} OPTION;
|
|
|
|
static char *options[] = {
|
|
"next", "prefix", "list", "scan",
|
|
"host",
|
|
0
|
|
};
|
|
|
|
typedef enum { /* <collection>/list file lines */
|
|
LUPGRADE, LOMIT, LBACKUP, LEXECUTE,
|
|
LINCLUDE, LNOACCT, LOMITANY, LALWAYS,
|
|
LSYMLINK, LRSYMLINK
|
|
} LISTTYPE;
|
|
|
|
static char *ltname[] = {
|
|
"upgrade", "omit", "backup", "execute",
|
|
"include", "noaccount", "omitany", "always",
|
|
"symlink", "rsymlink",
|
|
0
|
|
};
|
|
#define FALWAYS FUPDATE
|
|
|
|
/* list file lines */
|
|
static TREE *upgT; /* files to upgrade */
|
|
static TREE *flagsT; /* special flags: BACKUP NOACCT */
|
|
static TREE *omitT; /* recursize file omition list */
|
|
static TREE *omanyT; /* non-recursize file omition list */
|
|
static TREE *symT; /* symbolic links to quote */
|
|
static TREE *rsymT; /* recursive symbolic links to quote */
|
|
static TREE *execT; /* execute command list */
|
|
|
|
/*************************
|
|
*** E X T E R N ***
|
|
*************************/
|
|
|
|
extern char _argbreak; /* break character from nxtarg */
|
|
|
|
extern TREELIST *listTL; /* list of trees for scanning */
|
|
extern TREE *listT; /* final list of files in collection */
|
|
extern TREE *refuseT; /* files refused by client */
|
|
|
|
extern char *collname; /* collection name */
|
|
extern char *basedir; /* base directory name */
|
|
extern char *prefix; /* collection pathname prefix */
|
|
extern time_t lasttime; /* time of last upgrade */
|
|
extern time_t scantime; /* time of this scan */
|
|
extern int trace; /* trace directories */
|
|
extern int newonly; /* new files only */
|
|
|
|
#ifdef RCSSTAT
|
|
extern char *rcs_branch;
|
|
extern int candorcs;
|
|
#endif
|
|
|
|
/*************************************************
|
|
*** STATIC R O U T I N E S ***
|
|
*************************************************/
|
|
static void passdelim(char **, char);
|
|
static char *parserelease(TREELIST **, char *, char *);
|
|
static int scanone(TREE *, void *);
|
|
static void makescan(char *, char *);
|
|
static void getscan(char *, char *);
|
|
static void doscan(char *);
|
|
static void readlistfile(char *);
|
|
static void expTinsert(char *, TREE **, int, char *);
|
|
static int listone(TREE *, void *);
|
|
static void listentry(char *, char *, char *, int);
|
|
static void listname(char *, struct stat *);
|
|
static void listdir(char *, int);
|
|
static int omitanyone(TREE *, void *);
|
|
static int anyglob(char *, char *);
|
|
static int getscanfile(char *);
|
|
static void chkscanfile(char *);
|
|
static void makescanfile(char *);
|
|
static int recordone(TREE *, void *);
|
|
static int recordexec(TREE *, void *);
|
|
|
|
|
|
/*************************************************
|
|
*** L I S T S C A N R O U T I N E S ***
|
|
*************************************************/
|
|
|
|
static void
|
|
passdelim(char **ptr, char delim)
|
|
{ /* skip over delimiter */
|
|
*ptr = skipover(*ptr, " \t");
|
|
if (_argbreak != delim && **ptr == delim) {
|
|
(*ptr)++;
|
|
*ptr = skipover(*ptr, " \t");
|
|
}
|
|
}
|
|
|
|
static char *
|
|
parserelease(TREELIST ** tlp, char *relname, char *args)
|
|
{
|
|
TREELIST *tl;
|
|
char *arg;
|
|
OPTION option;
|
|
int opno;
|
|
char *nextrel;
|
|
|
|
tl = (TREELIST *) malloc(sizeof(TREELIST));
|
|
if ((*tlp = tl) == NULL)
|
|
goaway("Couldn't allocate TREELIST");
|
|
tl->TLnext = NULL;
|
|
tl->TLname = estrdup(relname);
|
|
tl->TLprefix = NULL;
|
|
tl->TLlist = NULL;
|
|
tl->TLscan = NULL;
|
|
tl->TLhost = NULL;
|
|
nextrel = NULL;
|
|
args = skipover(args, " \t");
|
|
while (*(arg = nxtarg(&args, " \t="))) {
|
|
for (opno = 0; options[opno] != NULL; opno++)
|
|
if (strcmp(arg, options[opno]) == 0)
|
|
break;
|
|
if (options[opno] == NULL)
|
|
goaway("Invalid release option %s for release %s",
|
|
arg, relname);
|
|
option = (OPTION) opno;
|
|
switch (option) {
|
|
case ONEXT:
|
|
passdelim(&args, '=');
|
|
arg = nxtarg(&args, " \t");
|
|
if (nextrel)
|
|
free(nextrel);
|
|
nextrel = estrdup(arg);
|
|
break;
|
|
case OPREFIX:
|
|
passdelim(&args, '=');
|
|
arg = nxtarg(&args, " \t");
|
|
tl->TLprefix = estrdup(arg);
|
|
break;
|
|
case OLIST:
|
|
passdelim(&args, '=');
|
|
arg = nxtarg(&args, " \t");
|
|
tl->TLlist = estrdup(arg);
|
|
break;
|
|
case OSCAN:
|
|
passdelim(&args, '=');
|
|
arg = nxtarg(&args, " \t");
|
|
tl->TLscan = estrdup(arg);
|
|
break;
|
|
case OHOST:
|
|
passdelim(&args, '=');
|
|
arg = nxtarg(&args, " \t");
|
|
tl->TLhost = estrdup(arg);
|
|
break;
|
|
}
|
|
}
|
|
return (nextrel);
|
|
}
|
|
|
|
int
|
|
getrelease(char *release)
|
|
{
|
|
TREELIST *tl;
|
|
char buf[STRINGLENGTH];
|
|
char *p, *q;
|
|
int rewound;
|
|
char *frelease = NULL;
|
|
FILE *f;
|
|
|
|
if (release == NULL)
|
|
frelease = release = estrdup(DEFRELEASE);
|
|
listTL = NULL;
|
|
|
|
(void) sprintf(buf, FILERELEASES, collname);
|
|
f = fopen(buf, "r");
|
|
if (f != NULL) {
|
|
rewound = TRUE;
|
|
for (;;) {
|
|
p = fgets(buf, sizeof(buf), f);
|
|
if (p == NULL) {
|
|
if (rewound)
|
|
break;
|
|
rewind(f);
|
|
rewound = TRUE;
|
|
continue;
|
|
}
|
|
q = strchr(p, '\n');
|
|
if (q)
|
|
*q = 0;
|
|
if (strchr("#;:", *p))
|
|
continue;
|
|
q = nxtarg(&p, " \t");
|
|
if (strcmp(q, release) != 0)
|
|
continue;
|
|
release = parserelease(&tl, release, p);
|
|
if (tl->TLprefix == NULL)
|
|
tl->TLprefix = prefix;
|
|
else if (chdir(tl->TLprefix) < 0) {
|
|
free(tl);
|
|
fclose(f);
|
|
if (frelease)
|
|
free(frelease);
|
|
return (FALSE);
|
|
} else
|
|
(void) chdir(basedir);
|
|
tl->TLnext = listTL;
|
|
listTL = tl;
|
|
if (release == NULL)
|
|
break;
|
|
rewound = FALSE;
|
|
}
|
|
(void) fclose(f);
|
|
}
|
|
if (release == NULL) {
|
|
if (frelease)
|
|
free(frelease);
|
|
return (TRUE);
|
|
}
|
|
if (strcmp(release, DEFRELEASE) != 0) {
|
|
if (frelease)
|
|
free(frelease);
|
|
return (FALSE);
|
|
}
|
|
(void) parserelease(&tl, release, "");
|
|
tl->TLprefix = prefix;
|
|
tl->TLnext = listTL;
|
|
listTL = tl;
|
|
if (frelease)
|
|
free(frelease);
|
|
return (TRUE);
|
|
}
|
|
|
|
void
|
|
makescanlists(void)
|
|
{
|
|
TREELIST *tl;
|
|
char buf[STRINGLENGTH];
|
|
char *p, *q;
|
|
FILE *f;
|
|
char *saveprefix = prefix;
|
|
int count = 0;
|
|
|
|
(void) sprintf(buf, FILERELEASES, collname);
|
|
f = fopen(buf, "r");
|
|
if (f != NULL) {
|
|
while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
|
|
q = strchr(p, '\n');
|
|
if (q)
|
|
*q = 0;
|
|
if (strchr("#;:", *p))
|
|
continue;
|
|
q = nxtarg(&p, " \t");
|
|
(void) parserelease(&tl, q, p);
|
|
if ((prefix = tl->TLprefix) == NULL)
|
|
prefix = saveprefix;
|
|
if (prefix != NULL) {
|
|
if (chdir(prefix) < 0)
|
|
goaway("Can't chdir to %s", prefix);
|
|
(void) chdir(basedir);
|
|
}
|
|
makescan(tl->TLlist, tl->TLscan);
|
|
free(tl);
|
|
count++;
|
|
}
|
|
(void) fclose(f);
|
|
}
|
|
if (count == 0)
|
|
makescan((char *) NULL, (char *) NULL);
|
|
}
|
|
|
|
static int
|
|
scanone(TREE * t, void *v __unused)
|
|
{
|
|
TREE *newt;
|
|
|
|
if (newonly && (t->Tflags & FNEW) == 0)
|
|
return (SCMOK);
|
|
newt = Tinsert(&listT, t->Tname, FALSE);
|
|
if (newt == NULL)
|
|
return (SCMOK);
|
|
newt->Tmode = t->Tmode;
|
|
newt->Tflags = t->Tflags;
|
|
newt->Tmtime = t->Tmtime;
|
|
return (SCMOK);
|
|
}
|
|
|
|
void
|
|
getscanlists(void)
|
|
{
|
|
TREELIST *tl, *stl;
|
|
|
|
stl = listTL;
|
|
listTL = NULL;
|
|
while ((tl = stl) != NULL) {
|
|
prefix = tl->TLprefix;
|
|
getscan(tl->TLlist, tl->TLscan);
|
|
tl->TLtree = listT;
|
|
stl = tl->TLnext;
|
|
tl->TLnext = listTL;
|
|
listTL = tl;
|
|
}
|
|
listT = NULL;
|
|
for (tl = listTL; tl != NULL; tl = tl->TLnext)
|
|
(void) Tprocess(tl->TLtree, scanone, NULL);
|
|
}
|
|
|
|
static void
|
|
makescan(char *listfile, char *scanfile)
|
|
{
|
|
listT = NULL;
|
|
chkscanfile(scanfile); /* can we can write a scan file? */
|
|
doscan(listfile); /* read list file and scan disk */
|
|
makescanfile(scanfile); /* record names in scan file */
|
|
Tfree(&listT); /* free file list tree */
|
|
}
|
|
|
|
static void
|
|
getscan(char *listfile, char *scanfile)
|
|
{
|
|
listT = NULL;
|
|
if (!getscanfile(scanfile)) { /* check for pre-scanned file list */
|
|
scantime = time((time_t *) NULL);
|
|
doscan(listfile); /* read list file and scan disk */
|
|
}
|
|
}
|
|
|
|
static void
|
|
doscan(char *listfile)
|
|
{
|
|
char buf[STRINGLENGTH];
|
|
|
|
upgT = NULL;
|
|
flagsT = NULL;
|
|
omitT = NULL;
|
|
omanyT = NULL;
|
|
execT = NULL;
|
|
symT = NULL;
|
|
rsymT = NULL;
|
|
if (listfile == NULL)
|
|
listfile = FILELISTDEF;
|
|
(void) sprintf(buf, FILELIST, collname, listfile);
|
|
readlistfile(buf); /* get contents of list file */
|
|
(void) Tprocess(upgT, listone, NULL); /* build list of files
|
|
* specified */
|
|
cdprefix((char *) NULL);
|
|
Tfree(&upgT);
|
|
Tfree(&flagsT);
|
|
Tfree(&omitT);
|
|
Tfree(&omanyT);
|
|
Tfree(&execT);
|
|
Tfree(&symT);
|
|
Tfree(&rsymT);
|
|
}
|
|
|
|
static void
|
|
readlistfile(char *fname)
|
|
{
|
|
char buf[STRINGLENGTH + MAXPATHLEN * 4 + 1], *p;
|
|
char *q, *r;
|
|
FILE *f;
|
|
int ltn, n, i, flags;
|
|
TREE **t = NULL;
|
|
LISTTYPE lt;
|
|
char *speclist[SPECNUMBER];
|
|
|
|
f = fopen(fname, "r");
|
|
if (f == NULL)
|
|
goaway("Can't read list file %s", fname);
|
|
cdprefix(prefix);
|
|
while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
|
|
if ((q = strchr(p, '\n')) != NULL)
|
|
*q = '\0';
|
|
if (strchr("#;:", *p))
|
|
continue;
|
|
q = nxtarg(&p, " \t");
|
|
if (*q == '\0')
|
|
continue;
|
|
for (ltn = 0; ltname[ltn] && strcmp(q, ltname[ltn]) != 0; ltn++);
|
|
if (ltname[ltn] == NULL)
|
|
goaway("Invalid list file keyword %s", q);
|
|
lt = (LISTTYPE) ltn;
|
|
flags = 0;
|
|
switch (lt) {
|
|
case LUPGRADE:
|
|
t = &upgT;
|
|
break;
|
|
case LBACKUP:
|
|
t = &flagsT;
|
|
flags = FBACKUP;
|
|
break;
|
|
case LNOACCT:
|
|
t = &flagsT;
|
|
flags = FNOACCT;
|
|
break;
|
|
case LSYMLINK:
|
|
t = &symT;
|
|
break;
|
|
case LRSYMLINK:
|
|
t = &rsymT;
|
|
break;
|
|
case LOMIT:
|
|
t = &omitT;
|
|
break;
|
|
case LOMITANY:
|
|
t = &omanyT;
|
|
break;
|
|
case LALWAYS:
|
|
t = &upgT;
|
|
flags = FALWAYS;
|
|
break;
|
|
case LINCLUDE:
|
|
while (*(q = nxtarg(&p, " \t"))) {
|
|
cdprefix((char *) NULL);
|
|
n = expand(q, speclist, SPECNUMBER);
|
|
for (i = 0; i < n && i < SPECNUMBER; i++) {
|
|
readlistfile(speclist[i]);
|
|
cdprefix((char *) NULL);
|
|
free(speclist[i]);
|
|
}
|
|
cdprefix(prefix);
|
|
}
|
|
continue;
|
|
case LEXECUTE:
|
|
r = p = q = skipover(p, " \t");
|
|
do {
|
|
q = p = skipto(p, " \t(");
|
|
p = skipover(p, " \t");
|
|
} while (*p != '(' && *p != '\0');
|
|
if (*p++ == '(') {
|
|
*q = '\0';
|
|
do {
|
|
q = nxtarg(&p, " \t)");
|
|
if (*q == 0)
|
|
_argbreak = ')';
|
|
else
|
|
expTinsert(q, &execT, 0, r);
|
|
} while (_argbreak != ')');
|
|
continue;
|
|
}
|
|
/* FALLTHROUGH */
|
|
default:
|
|
goaway("Error in handling list file keyword %d", ltn);
|
|
}
|
|
while (*(q = nxtarg(&p, " \t"))) {
|
|
if (lt == LOMITANY)
|
|
(void) Tinsert(t, q, FALSE);
|
|
else
|
|
expTinsert(q, t, flags, (char *) NULL);
|
|
}
|
|
}
|
|
(void) fclose(f);
|
|
}
|
|
|
|
static void
|
|
expTinsert(char *p, TREE ** t, int flags, char *exec)
|
|
{
|
|
int n, i;
|
|
TREE *newt;
|
|
char *speclist[SPECNUMBER];
|
|
char buf[STRINGLENGTH];
|
|
|
|
n = expand(p, speclist, SPECNUMBER);
|
|
for (i = 0; i < n && i < SPECNUMBER; i++) {
|
|
newt = Tinsert(t, speclist[i], TRUE);
|
|
newt->Tflags |= flags;
|
|
if (exec) {
|
|
(void) sprintf(buf, exec, speclist[i]);
|
|
(void) Tinsert(&newt->Texec, buf, FALSE);
|
|
}
|
|
free(speclist[i]);
|
|
}
|
|
}
|
|
|
|
static int
|
|
listone(TREE * t, void *v __unused)
|
|
{ /* expand and add one name from upgrade list */
|
|
listentry(t->Tname, t->Tname, (char *) NULL, (t->Tflags & FALWAYS) != 0);
|
|
return (SCMOK);
|
|
}
|
|
|
|
static void
|
|
listentry(char *name, char *fullname, char *updir, int always)
|
|
{
|
|
struct stat statbuf;
|
|
int linkcount = 0;
|
|
|
|
if (Tlookup(refuseT, fullname))
|
|
return;
|
|
if (!always) {
|
|
if (Tsearch(omitT, fullname))
|
|
return;
|
|
if (Tprocess(omanyT, omitanyone, fullname) != SCMOK)
|
|
return;
|
|
}
|
|
if (lstat(name, &statbuf) < 0)
|
|
return;
|
|
if (S_ISLNK(statbuf.st_mode)) {
|
|
if (Tsearch(symT, fullname)) {
|
|
listname(fullname, &statbuf);
|
|
return;
|
|
}
|
|
if (Tlookup(rsymT, fullname)) {
|
|
listname(fullname, &statbuf);
|
|
return;
|
|
}
|
|
if (updir)
|
|
linkcount++;
|
|
if (stat(name, &statbuf) < 0)
|
|
return;
|
|
}
|
|
if (S_ISDIR(statbuf.st_mode)) {
|
|
if (access(name, R_OK | X_OK) < 0)
|
|
return;
|
|
if (chdir(name) < 0)
|
|
return;
|
|
listname(fullname, &statbuf);
|
|
if (trace) {
|
|
printf("Scanning directory %s\n", fullname);
|
|
(void) fflush(stdout);
|
|
}
|
|
listdir(fullname, always);
|
|
if (updir == 0 || linkcount) {
|
|
(void) chdir(basedir);
|
|
if (prefix)
|
|
(void) chdir(prefix);
|
|
if (updir && *updir)
|
|
(void) chdir(updir);
|
|
} else
|
|
(void) chdir("..");
|
|
return;
|
|
}
|
|
if (access(name, R_OK) < 0)
|
|
return;
|
|
#ifdef RCSSTAT
|
|
if (candorcs) {
|
|
char rcs_release[STRINGLENGTH];
|
|
int status;
|
|
if (rcs_branch != NULL)
|
|
#ifdef CVS
|
|
sprintf(rcs_release, "-r %s", rcs_branch);
|
|
#else
|
|
sprintf(rcs_release, "-r%s", rcs_branch);
|
|
#endif
|
|
else
|
|
rcs_release[0] = '\0';
|
|
#ifdef CVS
|
|
sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, name, rcs_file);
|
|
#else
|
|
status = runp("rcsstat", "rcsstat", "-q", rcs_release, name, 0);
|
|
#endif
|
|
if (status != 0)
|
|
return;
|
|
}
|
|
#endif
|
|
listname(fullname, &statbuf);
|
|
}
|
|
|
|
static void
|
|
listname(char *name, struct stat * st)
|
|
{
|
|
TREE *t, *ts;
|
|
int new;
|
|
TREELIST *tl;
|
|
|
|
new = st->st_ctime > lasttime;
|
|
if (newonly && !new) {
|
|
for (tl = listTL; tl != NULL; tl = tl->TLnext)
|
|
if ((ts = Tsearch(tl->TLtree, name)) != NULL)
|
|
ts->Tflags &= ~FNEW;
|
|
return;
|
|
}
|
|
t = Tinsert(&listT, name, FALSE);
|
|
if (t == NULL)
|
|
return;
|
|
t->Tmode = st->st_mode;
|
|
t->Tctime = st->st_ctime;
|
|
t->Tmtime = st->st_mtime;
|
|
if (new)
|
|
t->Tflags |= FNEW;
|
|
if ((ts = Tsearch(flagsT, name)) != NULL)
|
|
t->Tflags |= ts->Tflags;
|
|
if ((ts = Tsearch(execT, name)) != NULL) {
|
|
t->Texec = ts->Texec;
|
|
ts->Texec = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
listdir(char *name, int always)
|
|
{ /* expand directory */
|
|
#ifdef HAS_POSIX_DIR
|
|
struct dirent *dentry;
|
|
#else
|
|
struct direct *dentry;
|
|
#endif
|
|
DIR *dirp;
|
|
char newname[STRINGLENGTH], filename[STRINGLENGTH];
|
|
char *p, *newp;
|
|
|
|
dirp = opendir(".");
|
|
if (dirp == 0)
|
|
return; /* unreadable: probably protected */
|
|
|
|
p = name; /* punt leading ./ and trailing / */
|
|
newp = newname;
|
|
if (p[0] == '.' && p[1] == '/') {
|
|
p += 2;
|
|
while (*p == '/')
|
|
p++;
|
|
}
|
|
while ((*newp++ = *p++) != '\0'); /* copy string */
|
|
--newp; /* trailing null */
|
|
while (newp > newname && newp[-1] == '/')
|
|
--newp; /* trailing / */
|
|
*newp = 0;
|
|
if (strcmp(newname, ".") == 0)
|
|
newname[0] = 0; /* "." ==> "" */
|
|
|
|
while ((dentry = readdir(dirp)) != NULL) {
|
|
if (dentry->d_ino == 0)
|
|
continue;
|
|
if (strcmp(dentry->d_name, ".") == 0)
|
|
continue;
|
|
if (strcmp(dentry->d_name, "..") == 0)
|
|
continue;
|
|
if (*newname) {
|
|
(void)snprintf(filename, sizeof(filename), "%s/%s",
|
|
newname, dentry->d_name);
|
|
} else {
|
|
(void)strncpy(filename, dentry->d_name,
|
|
sizeof(filename) - 1);
|
|
filename[sizeof(filename) - 1] = '\0';
|
|
}
|
|
listentry(dentry->d_name, filename, newname, always);
|
|
}
|
|
closedir(dirp);
|
|
}
|
|
|
|
static int
|
|
omitanyone(TREE * t, void *fv)
|
|
{
|
|
char *filename = fv;
|
|
if (anyglob(t->Tname, filename))
|
|
return (SCMERR);
|
|
return (SCMOK);
|
|
}
|
|
|
|
static int
|
|
anyglob(char *pattern, char *match)
|
|
{
|
|
char *p, *m;
|
|
char *pb, *pe;
|
|
|
|
p = pattern;
|
|
m = match;
|
|
while (*m && *p == *m) {
|
|
p++;
|
|
m++;
|
|
}
|
|
if (*p == '\0' && *m == '\0')
|
|
return (TRUE);
|
|
switch (*p++) {
|
|
case '*':
|
|
for (;;) {
|
|
if (*p == '\0')
|
|
return (TRUE);
|
|
if (*m == '\0')
|
|
return (*p == '\0');
|
|
if (anyglob(p, ++m))
|
|
return (TRUE);
|
|
}
|
|
case '?':
|
|
return (anyglob(p, ++m));
|
|
case '[':
|
|
pb = p;
|
|
while (*(++p) != ']')
|
|
if (*p == '\0')
|
|
return (FALSE);
|
|
pe = p;
|
|
for (p = pb + 1; p != pe; p++) {
|
|
switch (*p) {
|
|
case '-':
|
|
if (p == pb && *m == '-') {
|
|
p = pe + 1;
|
|
return (anyglob(p, ++m));
|
|
}
|
|
if (p == pb)
|
|
continue;
|
|
if ((p + 1) == pe)
|
|
return (FALSE);
|
|
if (*m > *(p - 1) &&
|
|
*m <= *(p + 1)) {
|
|
p = pe + 1;
|
|
return (anyglob(p, ++m));
|
|
}
|
|
continue;
|
|
default:
|
|
if (*m == *p) {
|
|
p = pe + 1;
|
|
return (anyglob(p, ++m));
|
|
}
|
|
}
|
|
}
|
|
return (FALSE);
|
|
default:
|
|
return (FALSE);
|
|
}
|
|
}
|
|
/*****************************************
|
|
*** R E A D S C A N F I L E ***
|
|
*****************************************/
|
|
|
|
static int
|
|
getscanfile(char *scanfile)
|
|
{
|
|
char buf[STRINGLENGTH];
|
|
#ifdef HAS_VIS
|
|
char fname[MAXPATHLEN];
|
|
#else
|
|
char *fname;
|
|
#endif
|
|
struct stat sbuf;
|
|
FILE *f;
|
|
TREE ts;
|
|
char *p, *q;
|
|
TREE *tmp, *t = NULL;
|
|
int notwanted;
|
|
TREELIST *tl;
|
|
|
|
if (scanfile == NULL)
|
|
scanfile = FILESCANDEF;
|
|
(void) sprintf(buf, FILESCAN, collname, scanfile);
|
|
if (stat(buf, &sbuf) < 0)
|
|
return (FALSE);
|
|
if ((f = fopen(buf, "r")) == NULL)
|
|
return (FALSE);
|
|
if ((p = fgets(buf, sizeof(buf), f)) == NULL) {
|
|
(void) fclose(f);
|
|
return (FALSE);
|
|
}
|
|
if ((q = strchr(p, '\n')) != NULL)
|
|
*q = '\0';
|
|
if (*p++ != 'V') {
|
|
(void) fclose(f);
|
|
return (FALSE);
|
|
}
|
|
if (atoi(p) != SCANVERSION) {
|
|
(void) fclose(f);
|
|
return (FALSE);
|
|
}
|
|
scantime = sbuf.st_mtime; /* upgrade time is time of supscan,
|
|
* i.e. time of creation of scanfile */
|
|
if (newonly && scantime == lasttime) {
|
|
(void) fclose(f);
|
|
return (TRUE);
|
|
}
|
|
notwanted = FALSE;
|
|
while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
|
|
q = strchr(p, '\n');
|
|
if (q)
|
|
*q = 0;
|
|
ts.Tflags = 0;
|
|
if (*p == 'X') {
|
|
if (notwanted)
|
|
continue;
|
|
if (t == NULL)
|
|
goaway("scanfile format inconsistent");
|
|
(void) Tinsert(&t->Texec, ++p, FALSE);
|
|
continue;
|
|
}
|
|
notwanted = FALSE;
|
|
if (*p == 'B') {
|
|
p++;
|
|
ts.Tflags |= FBACKUP;
|
|
}
|
|
if (*p == 'N') {
|
|
p++;
|
|
ts.Tflags |= FNOACCT;
|
|
}
|
|
if ((q = strchr(p, ' ')) == NULL)
|
|
goaway("scanfile format inconsistent");
|
|
*q++ = '\0';
|
|
ts.Tmode = atoo(p);
|
|
p = q;
|
|
if ((q = strchr(p, ' ')) == NULL)
|
|
goaway("scanfile format inconsistent");
|
|
*q++ = '\0';
|
|
ts.Tctime = atoi(p);
|
|
p = q;
|
|
if ((q = strchr(p, ' ')) == NULL)
|
|
goaway("scanfile format inconsistent");
|
|
*q++ = 0;
|
|
ts.Tmtime = atoi(p);
|
|
#ifdef HAS_VIS
|
|
(void) strunvis(fname, q);
|
|
#else
|
|
fname = q;
|
|
#endif
|
|
if (ts.Tctime > lasttime)
|
|
ts.Tflags |= FNEW;
|
|
else if (newonly) {
|
|
for (tl = listTL; tl != NULL; tl = tl->TLnext)
|
|
if ((tmp = Tsearch(tl->TLtree, fname)) != NULL)
|
|
tmp->Tflags &= ~FNEW;
|
|
notwanted = TRUE;
|
|
continue;
|
|
}
|
|
if (Tlookup(refuseT, fname)) {
|
|
notwanted = TRUE;
|
|
continue;
|
|
}
|
|
t = Tinsert(&listT, fname, TRUE);
|
|
t->Tmode = ts.Tmode;
|
|
t->Tflags = ts.Tflags;
|
|
t->Tctime = ts.Tctime;
|
|
t->Tmtime = ts.Tmtime;
|
|
}
|
|
(void) fclose(f);
|
|
return (TRUE);
|
|
}
|
|
/*******************************************
|
|
*** W R I T E S C A N F I L E ***
|
|
*******************************************/
|
|
|
|
static void
|
|
chkscanfile(char *scanfile)
|
|
{
|
|
char tname[STRINGLENGTH], fname[STRINGLENGTH];
|
|
FILE *f;
|
|
|
|
if (scanfile == NULL)
|
|
scanfile = FILESCANDEF;
|
|
(void) sprintf(fname, FILESCAN, collname, scanfile);
|
|
(void) sprintf(tname, "%s.temp", fname);
|
|
if (NULL == (f = fopen(tname, "w")))
|
|
goaway("Can't test scan file temp %s for %s", tname, collname);
|
|
else {
|
|
(void) unlink(tname);
|
|
(void) fclose(f);
|
|
}
|
|
}
|
|
|
|
static void
|
|
makescanfile(char *scanfile)
|
|
{
|
|
char tname[STRINGLENGTH], fname[STRINGLENGTH];
|
|
struct timeval tbuf[2];
|
|
FILE *scanF; /* output file for scanned file list */
|
|
|
|
if (scanfile == NULL)
|
|
scanfile = FILESCANDEF;
|
|
(void) sprintf(fname, FILESCAN, collname, scanfile);
|
|
(void) sprintf(tname, "%s.temp", fname);
|
|
scanF = fopen(tname, "w");
|
|
if (scanF == NULL)
|
|
goto out;
|
|
if (fprintf(scanF, "V%d\n", SCANVERSION) < 0)
|
|
goto out;
|
|
if (Tprocess(listT, recordone, scanF) != SCMOK)
|
|
goto out;
|
|
if (fclose(scanF) != 0)
|
|
goto out;
|
|
if (rename(tname, fname) < 0) {
|
|
(void)unlink(tname);
|
|
goaway("Can't change %s to %s", tname, fname);
|
|
}
|
|
tbuf[0].tv_sec = time((time_t *) NULL);
|
|
tbuf[0].tv_usec = 0;
|
|
tbuf[1].tv_sec = scantime;
|
|
tbuf[1].tv_usec = 0;
|
|
(void) utimes(fname, tbuf);
|
|
return;
|
|
out:
|
|
goaway("Can't write scan file temp %s for %s", tname, collname);
|
|
}
|
|
|
|
static int
|
|
recordone(TREE * t, void *v)
|
|
{
|
|
FILE *scanF = v;
|
|
#ifdef HAS_VIS
|
|
char fname[MAXPATHLEN * 4 + 1];
|
|
strvis(fname, t->Tname, VIS_WHITE);
|
|
#else
|
|
char *fname = t->Tname;
|
|
#endif
|
|
|
|
if (t->Tflags & FBACKUP)
|
|
if (fprintf(scanF, "B") < 0)
|
|
return SCMERR;
|
|
if (t->Tflags & FNOACCT)
|
|
if (fprintf(scanF, "N") < 0)
|
|
return SCMERR;
|
|
if (fprintf(scanF, "%o %d %d %s\n",
|
|
t->Tmode, t->Tctime, t->Tmtime, fname) < 0)
|
|
return SCMERR;
|
|
return Tprocess(t->Texec, recordexec, scanF);
|
|
}
|
|
|
|
static int
|
|
recordexec(TREE * t, void *v)
|
|
{
|
|
FILE *scanF = v;
|
|
#ifdef HAS_VIS
|
|
char fname[MAXPATHLEN * 4 + 1];
|
|
strvis(fname, t->Tname, VIS_WHITE);
|
|
#else
|
|
char *fname = t->Tname;
|
|
#endif
|
|
if (fprintf(scanF, "X%s\n", fname) < 0)
|
|
return SCMERR;
|
|
return (SCMOK);
|
|
}
|
|
|
|
void
|
|
cdprefix(char *prefix)
|
|
{
|
|
static char *curprefix = NULL;
|
|
|
|
if (curprefix == NULL) {
|
|
if (prefix == NULL)
|
|
return;
|
|
(void) chdir(prefix);
|
|
curprefix = prefix;
|
|
return;
|
|
}
|
|
if (prefix == NULL) {
|
|
(void) chdir(basedir);
|
|
curprefix = NULL;
|
|
return;
|
|
}
|
|
if (prefix == curprefix)
|
|
return;
|
|
if (strcmp(prefix, curprefix) == 0) {
|
|
curprefix = prefix;
|
|
return;
|
|
}
|
|
(void) chdir(basedir);
|
|
(void) chdir(prefix);
|
|
curprefix = prefix;
|
|
}
|