1055 lines
26 KiB
C
1055 lines
26 KiB
C
/*
|
|
* 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
|
|
* $Log: scan.c,v $
|
|
* Revision 1.7 1996/12/31 18:08:01 christos
|
|
* 64 bit patches (mostly long -> time_t) from Matthew Jacob (?)
|
|
* sup now works on the alpha!
|
|
*
|
|
* Revision 1.6 1996/12/23 19:42:11 christos
|
|
* - add missing prototypes.
|
|
* - fix function call inconsistencies
|
|
* - fix int <-> long and pointer conversions
|
|
* It should run now on 64 bit machines...
|
|
*
|
|
* Revision 1.5 1996/09/05 16:50:04 christos
|
|
* - for portability make sure that we never use "" as a pathname, always convert
|
|
* it to "."
|
|
* - include sockio.h if needed to define SIOCGIFCONF (for svr4)
|
|
* - use POSIX signals and wait macros
|
|
* - add -S silent flag, so that the client does not print messages unless there
|
|
* is something wrong
|
|
* - use flock or lockf as appropriate
|
|
* - use fstatfs or fstatvfs to find out if a filesystem is mounted over nfs,
|
|
* don't depend on the major() = 255 hack; it only works on legacy systems.
|
|
* - use gzip -cf to make sure that gzip compresses the file even when the file
|
|
* would expand.
|
|
* - punt on defining vsnprintf if _IOSTRG is not defined; use sprintf...
|
|
*
|
|
* To compile sup on systems other than NetBSD, you'll need a copy of daemon.c,
|
|
* vis.c, vis.h and sys/cdefs.h. Maybe we should keep those in the distribution?
|
|
*
|
|
* Revision 1.4 1995/10/29 23:54:45 christos
|
|
* - runio fails when result != 0 not only < 0
|
|
* - print vis-encoded file in the scanner.
|
|
*
|
|
* Revision 1.3 1995/06/24 16:21:42 christos
|
|
* - Don't use system(3) to fork processes. It is a big security hole.
|
|
* - Encode the filenames in the scan files using strvis(3), so filenames
|
|
* that contain newlines or other weird characters don't break the scanner.
|
|
*
|
|
* Revision 1.2 1994/01/03 14:47:25 brezak
|
|
* Change <sys/dir.h> to <dirent.h>
|
|
*
|
|
* Revision 1.1.1.1 1993/05/21 14:52:17 cgd
|
|
* initial import of CMU's SUP to NetBSD
|
|
*
|
|
* 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.
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
#include <libc.h>
|
|
#include <c.h>
|
|
#include <vis.h>
|
|
#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 <unistd.h>
|
|
#include "supcdefs.h"
|
|
#include "supextern.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 ***
|
|
*************************/
|
|
|
|
#ifdef lint
|
|
static char _argbreak;
|
|
#else
|
|
extern char _argbreak; /* break character from nxtarg */
|
|
#endif
|
|
|
|
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 __P((char **, int ));
|
|
static char *parserelease __P((TREELIST **, char *, char *));
|
|
static int scanone __P((TREE *, void *));
|
|
static void makescan __P((char *, char *));
|
|
static void getscan __P((char *, char *));
|
|
static void doscan __P((char *));
|
|
static void readlistfile __P((char *));
|
|
static void expTinsert __P((char *, TREE **, int, char *));
|
|
static int listone __P((TREE *, void *));
|
|
static void listentry __P((char *, char *, char *, int));
|
|
static void listname __P((char *, struct stat *));
|
|
static void listdir __P((char *, int));
|
|
static int omitanyone __P((TREE *, void *));
|
|
static int anyglob __P((char *, char *));
|
|
static int getscanfile __P((char *));
|
|
static void chkscanfile __P((char *));
|
|
static void makescanfile __P((char *));
|
|
static int recordone __P((TREE *, void *));
|
|
static int recordexec __P((TREE *, void *));
|
|
|
|
|
|
/*************************************************
|
|
*** L I S T S C A N R O U T I N E S ***
|
|
*************************************************/
|
|
|
|
static void
|
|
passdelim (ptr,delim) /* skip over delimiter */
|
|
char **ptr,delim;
|
|
{
|
|
*ptr = skipover (*ptr, " \t");
|
|
if (_argbreak != delim && **ptr == delim) {
|
|
(*ptr)++;
|
|
*ptr = skipover (*ptr, " \t");
|
|
}
|
|
}
|
|
|
|
static
|
|
char *parserelease(tlp,relname,args)
|
|
TREELIST **tlp;
|
|
char *relname,*args;
|
|
{
|
|
register TREELIST *tl;
|
|
register char *arg;
|
|
register 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 = salloc (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");
|
|
nextrel = salloc (arg);
|
|
break;
|
|
case OPREFIX:
|
|
passdelim (&args,'=');
|
|
arg = nxtarg (&args," \t");
|
|
tl->TLprefix = salloc (arg);
|
|
break;
|
|
case OLIST:
|
|
passdelim (&args,'=');
|
|
arg = nxtarg (&args," \t");
|
|
tl->TLlist = salloc (arg);
|
|
break;
|
|
case OSCAN:
|
|
passdelim (&args,'=');
|
|
arg = nxtarg (&args," \t");
|
|
tl->TLscan = salloc (arg);
|
|
break;
|
|
case OHOST:
|
|
passdelim (&args,'=');
|
|
arg = nxtarg (&args," \t");
|
|
tl->TLhost = salloc (arg);
|
|
break;
|
|
}
|
|
}
|
|
return (nextrel);
|
|
}
|
|
|
|
int
|
|
getrelease (release)
|
|
char *release;
|
|
{
|
|
TREELIST *tl;
|
|
char buf[STRINGLENGTH];
|
|
char *p,*q;
|
|
int rewound;
|
|
FILE *f;
|
|
|
|
if (release == NULL)
|
|
release = salloc (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 = index (p,'\n');
|
|
if (q) *q = 0;
|
|
if (index ("#;:",*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)
|
|
return (FALSE);
|
|
else
|
|
(void) chdir (basedir);
|
|
tl->TLnext = listTL;
|
|
listTL = tl;
|
|
if (release == NULL)
|
|
break;
|
|
rewound = FALSE;
|
|
}
|
|
(void) fclose (f);
|
|
}
|
|
if (release == NULL)
|
|
return (TRUE);
|
|
if (strcmp (release,DEFRELEASE) != 0)
|
|
return (FALSE);
|
|
(void) parserelease (&tl,release,"");
|
|
tl->TLprefix = prefix;
|
|
tl->TLnext = listTL;
|
|
listTL = tl;
|
|
return (TRUE);
|
|
}
|
|
|
|
void
|
|
makescanlists ()
|
|
{
|
|
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 = index (p,'\n');
|
|
if (q) *q = 0;
|
|
if (index ("#;:",*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 ((char *)tl);
|
|
count++;
|
|
}
|
|
(void) fclose (f);
|
|
}
|
|
if (count == 0)
|
|
makescan ((char *)NULL,(char *)NULL);
|
|
}
|
|
|
|
static int
|
|
scanone (t, v)
|
|
register TREE *t;
|
|
void *v;
|
|
{
|
|
register 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 ()
|
|
{
|
|
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 (listfile,scanfile)
|
|
char *listfile,*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 (listfile,scanfile)
|
|
char *listfile,*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 (listfile)
|
|
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 (fname)
|
|
char *fname;
|
|
{
|
|
char buf[STRINGLENGTH+MAXPATHLEN*4+1],*p;
|
|
register char *q,*r;
|
|
register FILE *f;
|
|
register int ltn,n,i,flags;
|
|
register TREE **t = NULL;
|
|
register 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 = index (p,'\n')) != NULL) *q = '\0';
|
|
if (index ("#;:",*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;
|
|
}
|
|
/* fall through */
|
|
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 (p,t,flags,exec)
|
|
char *p;
|
|
TREE **t;
|
|
int flags;
|
|
char *exec;
|
|
{
|
|
register int n, i;
|
|
register 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 (t, v) /* expand and add one name from upgrade list */
|
|
TREE *t;
|
|
void *v;
|
|
{
|
|
listentry(t->Tname,t->Tname,(char *)NULL,(t->Tflags&FALWAYS) != 0);
|
|
return (SCMOK);
|
|
}
|
|
|
|
static void
|
|
listentry(name,fullname,updir,always)
|
|
register char *name, *fullname, *updir;
|
|
int always;
|
|
{
|
|
struct stat statbuf;
|
|
int link = 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 ((statbuf.st_mode&S_IFMT) == S_IFLNK) {
|
|
if (Tsearch (symT,fullname)) {
|
|
listname (fullname,&statbuf);
|
|
return;
|
|
}
|
|
if (Tlookup (rsymT,fullname)) {
|
|
listname (fullname,&statbuf);
|
|
return;
|
|
}
|
|
if (updir) link++;
|
|
if (stat(name,&statbuf) < 0) return;
|
|
}
|
|
if ((statbuf.st_mode&S_IFMT) == S_IFDIR) {
|
|
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 || link) {
|
|
(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 (name,st)
|
|
register char *name;
|
|
register struct stat *st;
|
|
{
|
|
register TREE *t,*ts;
|
|
register int new;
|
|
register 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 (name,always) /* expand directory */
|
|
char *name;
|
|
int always;
|
|
{
|
|
#ifdef HAS_POSIX_DIR
|
|
struct dirent *dentry;
|
|
#else
|
|
struct direct *dentry;
|
|
#endif
|
|
register DIR *dirp;
|
|
char ename[STRINGLENGTH],newname[STRINGLENGTH],filename[STRINGLENGTH];
|
|
register char *p,*newp;
|
|
register int i;
|
|
|
|
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;
|
|
for (i=0; i<=MAXNAMLEN && dentry->d_name[i]; i++)
|
|
ename[i] = dentry->d_name[i];
|
|
ename[i] = 0;
|
|
if (*newname)
|
|
(void) sprintf (filename,"%s/%s",newname,ename);
|
|
else
|
|
(void) strcpy (filename,ename);
|
|
listentry(ename,filename,newname,always);
|
|
}
|
|
closedir (dirp);
|
|
}
|
|
|
|
static int
|
|
omitanyone (t,fv)
|
|
TREE *t;
|
|
void *fv;
|
|
{
|
|
char *filename = fv;
|
|
if (anyglob (t->Tname,filename))
|
|
return (SCMERR);
|
|
return (SCMOK);
|
|
}
|
|
|
|
static int
|
|
anyglob (pattern,match)
|
|
char *pattern,*match;
|
|
{
|
|
register char *p,*m;
|
|
register 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 (scanfile)
|
|
char *scanfile;
|
|
{
|
|
char buf[STRINGLENGTH];
|
|
char fname[MAXPATHLEN];
|
|
struct stat sbuf;
|
|
register FILE *f;
|
|
TREE ts;
|
|
register char *p,*q;
|
|
register TREE *tmp, *t = NULL;
|
|
register notwanted;
|
|
register 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 = index (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 = index (p,'\n');
|
|
if (q) *q = 0;
|
|
ts.Tflags = 0;
|
|
if (*p == 'X') {
|
|
if (notwanted) continue;
|
|
if (t == NULL)
|
|
goaway ("scanfile format inconsistant");
|
|
(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 = index (p,' ')) == NULL)
|
|
goaway ("scanfile format inconsistant");
|
|
*q++ = '\0';
|
|
ts.Tmode = atoo (p);
|
|
p = q;
|
|
if ((q = index (p,' ')) == NULL)
|
|
goaway ("scanfile format inconsistant");
|
|
*q++ = '\0';
|
|
ts.Tctime = atoi (p);
|
|
p = q;
|
|
if ((q = index (p,' ')) == NULL)
|
|
goaway ("scanfile format inconsistant");
|
|
*q++ = 0;
|
|
ts.Tmtime = atoi (p);
|
|
(void) strunvis(fname, q);
|
|
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 (scanfile)
|
|
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 (scanfile)
|
|
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)
|
|
goaway ("Can't write scan file temp %s for %s",tname,collname);
|
|
fprintf (scanF,"V%d\n",SCANVERSION);
|
|
(void) Tprocess (listT,recordone,scanF);
|
|
(void) fclose (scanF);
|
|
if (rename (tname,fname) < 0)
|
|
goaway ("Can't change %s to %s",tname,fname);
|
|
(void) unlink (tname);
|
|
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);
|
|
}
|
|
|
|
static int
|
|
recordone (t,v)
|
|
TREE *t;
|
|
void *v;
|
|
{
|
|
FILE *scanF = v;
|
|
char fname[MAXPATHLEN*4+1];
|
|
|
|
if (t->Tflags&FBACKUP) fprintf (scanF,"B");
|
|
if (t->Tflags&FNOACCT) fprintf (scanF,"N");
|
|
strvis(fname, t->Tname, VIS_WHITE);
|
|
fprintf (scanF,"%o %d %d %s\n",
|
|
t->Tmode,t->Tctime,t->Tmtime,fname);
|
|
(void) Tprocess (t->Texec,recordexec, scanF);
|
|
return (SCMOK);
|
|
}
|
|
|
|
static int
|
|
recordexec (t,v)
|
|
TREE *t;
|
|
void *v;
|
|
{
|
|
FILE *scanF = v;
|
|
char fname[MAXPATHLEN*4+1];
|
|
strvis(fname, t->Tname, VIS_WHITE);
|
|
fprintf(scanF,"X%s\n",fname);
|
|
return (SCMOK);
|
|
}
|
|
|
|
void
|
|
cdprefix (prefix)
|
|
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;
|
|
}
|