2
* Copyright (c) 1992 Carnegie Mellon University
5
* Permission to use, copy, modify and distribute this software and its
6
* documentation is hereby granted, provided that both the copyright
7
* notice and this permission notice appear in all copies of the
8
* software, derivative works or modified versions, and any portions
9
* thereof, and that both notices appear in supporting documentation.
11
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
12
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
13
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15
* Carnegie Mellon requests users of this software to return to
17
* Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
18
* School of Computer Science
19
* Carnegie Mellon University
20
* Pittsburgh PA 15213-3890
22
* any improvements or extensions that they make and grant Carnegie Mellon
23
* the rights to redistribute these changes.
26
* scan.c - sup list file scanner
28
**********************************************************************
31
* Revision 1.1.1.1 1993/08/21 00:46:33 jkh
32
* Current sup with compression support.
34
* Revision 1.1.1.1 1993/05/21 14:52:17 cgd
35
* initial import of CMU's SUP to NetBSD
37
* Revision 1.8 92/08/11 12:04:28 mrt
38
* Brad's changes: delinted, added forward declarations of static
39
* functions.Added Copyright.
42
* 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
43
* Added host=<hostfile> support to releases file.
45
* 11-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
46
* Added "rsymlink" recursive symbolic link quoting directive.
48
* 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
49
* Added code for "release" support.
51
* 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
52
* Lets see if we'll be able to write the scan file BEFORE
53
* we collect the data for it. Include sys/file.h and use
54
* new definitions for access check codes.
56
* 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
57
* Added type casting information for lint.
59
* 21-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
60
* Added check for newonly upgrade when lasttime is the same as
61
* scantime. This will save us the trouble of parsing the scanfile
62
* when the client has successfully received everything in the
65
* 16-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
66
* Clear Texec pointers in execT so that Tfree of execT will not
67
* free command trees associated with files in listT.
69
* 06-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
70
* Added code to omit scanned files from list if we want new files
71
* only and they are old.
73
* 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
74
* Major rewrite for protocol version 4. Added version numbers to
75
* scan file. Also added mode of file in addition to flags.
76
* Execute commands are now immediately after file information.
78
* 13-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
79
* Added comments to list file format.
81
* 08-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
82
* Added code to implement omitany. Currently doesn't know about
85
* 07-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
88
**********************************************************************
93
#include <sys/types.h>
100
/*************************
102
*************************/
104
#define SPECNUMBER 1000
105
/* number of filenames produced by a single spec in the list file */
107
/*******************************************
108
*** D A T A S T R U C T U R E S ***
109
*******************************************/
111
typedef enum { /* release options */
112
ONEXT, OPREFIX, OLIST, OSCAN,
116
static char *options[] = {
117
"next", "prefix", "list", "scan",
122
typedef enum { /* <collection>/list file lines */
123
LUPGRADE, LOMIT, LBACKUP, LEXECUTE,
124
LINCLUDE, LNOACCT, LOMITANY, LALWAYS,
128
static char *ltname[] = {
129
"upgrade", "omit", "backup", "execute",
130
"include", "noaccount", "omitany", "always",
131
"symlink", "rsymlink",
135
#define FALWAYS FUPDATE
137
/* list file lines */
138
static TREE *upgT; /* files to upgrade */
139
static TREE *flagsT; /* special flags: BACKUP NOACCT */
140
static TREE *omitT; /* recursize file omition list */
141
static TREE *omanyT; /* non-recursize file omition list */
142
static TREE *symT; /* symbolic links to quote */
143
static TREE *rsymT; /* recursive symbolic links to quote */
144
static TREE *execT; /* execute command list */
146
/*************************
148
*************************/
151
static char _argbreak;
153
extern char _argbreak; /* break character from nxtarg */
156
extern TREELIST *listTL; /* list of trees for scanning */
157
extern TREE *listT; /* final list of files in collection */
158
extern TREE *refuseT; /* files refused by client */
160
extern char *collname; /* collection name */
161
extern char *basedir; /* base directory name */
162
extern char *prefix; /* collection pathname prefix */
163
extern long lasttime; /* time of last upgrade */
164
extern long scantime; /* time of this scan */
165
extern int trace; /* trace directories */
166
extern int newonly; /* new files only */
170
/*************************************************
171
*** STATIC R O U T I N E S ***
172
*************************************************/
177
static readlistfile();
185
static int getscanfile();
186
static chkscanfile();
187
static makescanfile();
191
/*************************************************
192
*** L I S T S C A N R O U T I N E S ***
193
*************************************************/
196
passdelim (ptr,delim) /* skip over delimiter */
199
*ptr = skipover (*ptr, " \t");
200
if (_argbreak != delim && **ptr == delim) {
202
*ptr = skipover (*ptr, " \t");
207
char *parserelease(tlp,relname,args)
211
register TREELIST *tl;
213
register OPTION option;
217
tl = (TREELIST *) malloc (sizeof(TREELIST));
218
if ((*tlp = tl) == NULL)
219
goaway ("Couldn't allocate TREELIST");
221
tl->TLname = salloc (relname);
227
args = skipover (args," \t");
228
while (*(arg=nxtarg(&args," \t="))) {
229
for (opno = 0; options[opno] != NULL; opno++)
230
if (strcmp (arg,options[opno]) == 0)
232
if (options[opno] == NULL)
233
goaway ("Invalid release option %s for release %s",
235
option = (OPTION) opno;
238
passdelim (&args,'=');
239
arg = nxtarg (&args," \t");
240
nextrel = salloc (arg);
243
passdelim (&args,'=');
244
arg = nxtarg (&args," \t");
245
tl->TLprefix = salloc (arg);
248
passdelim (&args,'=');
249
arg = nxtarg (&args," \t");
250
tl->TLlist = salloc (arg);
253
passdelim (&args,'=');
254
arg = nxtarg (&args," \t");
255
tl->TLscan = salloc (arg);
258
passdelim (&args,'=');
259
arg = nxtarg (&args," \t");
260
tl->TLhost = salloc (arg);
271
char buf[STRINGLENGTH];
277
release = salloc (DEFRELEASE);
280
(void) sprintf (buf,FILERELEASES,collname);
285
p = fgets (buf,STRINGLENGTH,f);
295
if (index ("#;:",*p)) continue;
296
q = nxtarg (&p," \t");
297
if (strcmp (q,release) != 0)
299
release = parserelease (&tl,release,p);
300
if (tl->TLprefix == NULL)
301
tl->TLprefix = prefix;
302
else if (chdir (tl->TLprefix) < 0)
305
(void) chdir (basedir);
316
if (strcmp (release,DEFRELEASE) != 0)
318
(void) parserelease (&tl,release,"");
319
tl->TLprefix = prefix;
328
char buf[STRINGLENGTH];
331
char *saveprefix = prefix;
334
(void) sprintf (buf,FILERELEASES,collname);
337
while (p = fgets (buf,STRINGLENGTH,f)) {
340
if (index ("#;:",*p)) continue;
341
q = nxtarg (&p," \t");
342
(void) parserelease (&tl,q,p);
343
if ((prefix = tl->TLprefix) == NULL)
345
if (prefix != NULL) {
346
if (chdir (prefix) < 0)
347
goaway ("Can't chdir to %s",prefix);
348
(void) chdir (basedir);
350
makescan (tl->TLlist,tl->TLscan);
357
makescan ((char *)NULL,(char *)NULL);
366
if (newonly && (t->Tflags&FNEW) == 0)
368
newt = Tinsert (&listT,t->Tname,FALSE);
371
newt->Tmode = t->Tmode;
372
newt->Tflags = t->Tflags;
373
newt->Tmtime = t->Tmtime;
383
while ((tl = stl) != NULL) {
384
prefix = tl->TLprefix;
385
getscan (tl->TLlist,tl->TLscan);
392
for (tl = listTL; tl != NULL; tl = tl->TLnext)
393
(void) Tprocess (tl->TLtree,scanone);
397
makescan (listfile,scanfile)
398
char *listfile,*scanfile;
401
chkscanfile (scanfile); /* can we can write a scan file? */
402
doscan (listfile); /* read list file and scan disk */
403
makescanfile (scanfile); /* record names in scan file */
404
Tfree (&listT); /* free file list tree */
408
getscan (listfile,scanfile)
409
char *listfile,*scanfile;
412
if (!getscanfile(scanfile)) { /* check for pre-scanned file list */
413
scantime = time ((long *)NULL);
414
doscan (listfile); /* read list file and scan disk */
422
char buf[STRINGLENGTH];
432
if (listfile == NULL)
433
listfile = FILELISTDEF;
434
(void) sprintf (buf,FILELIST,collname,listfile);
435
readlistfile (buf); /* get contents of list file */
436
(void) Tprocess (upgT,listone); /* build list of files specified */
437
cdprefix ((char *)NULL);
451
char buf[STRINGLENGTH],*p;
454
register int ltn,n,i,flags;
456
register LISTTYPE lt;
457
char *speclist[SPECNUMBER];
459
f = fopen (fname,"r");
460
if (f == NULL) goaway ("Can't read list file %s",fname);
462
while (p = fgets (buf,STRINGLENGTH,f)) {
463
if (q = index (p,'\n')) *q = '\0';
464
if (index ("#;:",*p)) continue;
465
q = nxtarg (&p," \t");
466
if (*q == '\0') continue;
467
for (ltn = 0; ltname[ltn] && strcmp(q,ltname[ltn]) != 0; ltn++);
468
if (ltname[ltn] == NULL)
469
goaway ("Invalid list file keyword %s",q);
501
while (*(q=nxtarg(&p," \t"))) {
502
cdprefix ((char *)NULL);
503
n = expand (q,speclist,SPECNUMBER);
504
for (i = 0; i < n && i < SPECNUMBER; i++) {
505
readlistfile (speclist[i]);
506
cdprefix ((char *)NULL);
513
r = p = q = skipover (p," \t");
515
q = p = skipto (p," \t(");
516
p = skipover (p," \t");
517
} while (*p != '(' && *p != '\0');
521
q = nxtarg (&p," \t)");
525
expTinsert (q,&execT,0,r);
526
} while (_argbreak != ')');
531
goaway ("Error in handling list file keyword %d",ltn);
533
while (*(q=nxtarg(&p," \t"))) {
535
(void) Tinsert (t,q,FALSE);
537
expTinsert (q,t,flags,(char *)NULL);
544
expTinsert (p,t,flags,exec)
552
char *speclist[SPECNUMBER];
553
char buf[STRINGLENGTH];
555
n = expand (p,speclist,SPECNUMBER);
556
for (i = 0; i < n && i < SPECNUMBER; i++) {
557
newt = Tinsert (t,speclist[i],TRUE);
558
newt->Tflags |= flags;
560
(void) sprintf (buf,exec,speclist[i]);
561
(void) Tinsert (&newt->Texec,buf,FALSE);
568
listone (t) /* expand and add one name from upgrade list */
571
listentry(t->Tname,t->Tname,(char *)NULL,(t->Tflags&FALWAYS) != 0);
576
listentry(name,fullname,updir,always)
577
register char *name, *fullname, *updir;
584
if (Tlookup (refuseT,fullname)) return;
586
if (Tsearch (omitT,fullname)) return;
587
if (Tprocess (omanyT,omitanyone,fullname) != SCMOK)
590
if (lstat(name,&statbuf) < 0)
592
if ((statbuf.st_mode&S_IFMT) == S_IFLNK) {
593
if (Tsearch (symT,fullname)) {
594
listname (fullname,&statbuf);
597
if (Tlookup (rsymT,fullname)) {
598
listname (fullname,&statbuf);
602
if (stat(name,&statbuf) < 0) return;
604
if ((statbuf.st_mode&S_IFMT) == S_IFDIR) {
605
if (access(name,R_OK|X_OK) < 0) return;
606
if (chdir(name) < 0) return;
607
listname (fullname,&statbuf);
609
printf ("Scanning directory %s\n",fullname);
610
(void) fflush (stdout);
612
listdir (fullname,always);
613
if (updir == 0 || link) {
614
(void) chdir (basedir);
615
if (prefix) (void) chdir (prefix);
616
if (updir && *updir) (void) chdir (updir);
621
if (access(name,R_OK) < 0) return;
622
listname (fullname,&statbuf);
628
register struct stat *st;
630
register TREE *t,*ts;
632
register TREELIST *tl;
634
new = st->st_ctime > lasttime;
635
if (newonly && !new) {
636
for (tl = listTL; tl != NULL; tl = tl->TLnext)
637
if (ts = Tsearch (tl->TLtree,name))
641
t = Tinsert (&listT,name,FALSE);
642
if (t == NULL) return;
643
t->Tmode = st->st_mode;
644
t->Tctime = st->st_ctime;
645
t->Tmtime = st->st_mtime;
646
if (new) t->Tflags |= FNEW;
647
if (ts = Tsearch (flagsT,name))
648
t->Tflags |= ts->Tflags;
649
if (ts = Tsearch (execT,name)) {
650
t->Texec = ts->Texec;
656
listdir (name,always) /* expand directory */
660
struct direct *dentry;
662
char ename[STRINGLENGTH],newname[STRINGLENGTH],filename[STRINGLENGTH];
663
register char *p,*newp;
666
dirp = opendir (".");
667
if (dirp == 0) return; /* unreadable: probably protected */
669
p = name; /* punt leading ./ and trailing / */
671
if (p[0] == '.' && p[1] == '/') {
673
while (*p == '/') p++;
675
while (*newp++ = *p++) ; /* copy string */
676
--newp; /* trailing null */
677
while (newp > newname && newp[-1] == '/') --newp; /* trailing / */
679
if (strcmp (newname,".") == 0) newname[0] = 0; /* "." ==> "" */
681
while (dentry=readdir(dirp)) {
682
if (dentry->d_ino == 0) continue;
683
if (strcmp(dentry->d_name,".") == 0) continue;
684
if (strcmp(dentry->d_name,"..") == 0) continue;
685
for (i=0; i<=MAXNAMLEN && dentry->d_name[i]; i++)
686
ename[i] = dentry->d_name[i];
689
(void) sprintf (filename,"%s/%s",newname,ename);
691
(void) strcpy (filename,ename);
692
listentry(ename,filename,newname,always);
698
omitanyone (t,filename)
702
if (anyglob (t->Tname,*filename))
708
anyglob (pattern,match)
709
char *pattern,*match;
712
register char *pb,*pe;
716
while (*m && *p == *m ) {
720
if (*p == '\0' && *m == '\0')
733
return (anyglob (p,++m));
736
while (*(++p) != ']')
740
for (p = pb + 1; p != pe; p++) {
743
if (p == pb && *m == '-') {
745
return (anyglob (p,++m));
754
return (anyglob (p,++m));
760
return (anyglob (p,++m));
770
/*****************************************
771
*** R E A D S C A N F I L E ***
772
*****************************************/
775
int getscanfile (scanfile)
778
char buf[STRINGLENGTH];
783
register TREE *tmp, *t = NULL;
785
register TREELIST *tl;
787
if (scanfile == NULL)
788
scanfile = FILESCANDEF;
789
(void) sprintf (buf,FILESCAN,collname,scanfile);
790
if (stat(buf,&sbuf) < 0)
792
if ((f = fopen (buf,"r")) == NULL)
794
if ((p = fgets (buf,STRINGLENGTH,f)) == NULL) {
798
if (q = index (p,'\n')) *q = '\0';
803
if (atoi (p) != SCANVERSION) {
807
scantime = sbuf.st_mtime; /* upgrade time is time of supscan,
808
* i.e. time of creation of scanfile */
809
if (newonly && scantime == lasttime) {
814
while (p = fgets (buf,STRINGLENGTH,f)) {
819
if (notwanted) continue;
821
goaway ("scanfile format inconsistant");
822
(void) Tinsert (&t->Texec,++p,FALSE);
828
ts.Tflags |= FBACKUP;
832
ts.Tflags |= FNOACCT;
834
if ((q = index (p,' ')) == NULL)
835
goaway ("scanfile format inconsistant");
839
if ((q = index (p,' ')) == NULL)
840
goaway ("scanfile format inconsistant");
842
ts.Tctime = atoi (p);
844
if ((q = index (p,' ')) == NULL)
845
goaway ("scanfile format inconsistant");
847
ts.Tmtime = atoi (p);
848
if (ts.Tctime > lasttime)
851
for (tl = listTL; tl != NULL; tl = tl->TLnext)
852
if (tmp = Tsearch (tl->TLtree,q))
853
tmp->Tflags &= ~FNEW;
857
if (Tlookup (refuseT,q)) {
861
t = Tinsert (&listT,q,TRUE);
863
t->Tflags = ts.Tflags;
864
t->Tctime = ts.Tctime;
865
t->Tmtime = ts.Tmtime;
871
/*******************************************
872
*** W R I T E S C A N F I L E ***
873
*******************************************/
875
static chkscanfile (scanfile)
878
char tname[STRINGLENGTH], fname[STRINGLENGTH];
881
if (scanfile == NULL)
882
scanfile = FILESCANDEF;
883
(void) sprintf (fname,FILESCAN,collname,scanfile);
884
(void) sprintf (tname,"%s.temp",fname);
885
if (NULL == (f = fopen (tname, "w")))
886
goaway ("Can't test scan file temp %s for %s",tname,collname);
888
(void) unlink (tname);
893
static makescanfile (scanfile)
896
char tname[STRINGLENGTH],fname[STRINGLENGTH];
897
struct timeval tbuf[2];
898
FILE *scanF; /* output file for scanned file list */
901
if (scanfile == NULL)
902
scanfile = FILESCANDEF;
903
(void) sprintf (fname,FILESCAN,collname,scanfile);
904
(void) sprintf (tname,"%s.temp",fname);
905
scanF = fopen (tname,"w");
907
goaway ("Can't write scan file temp %s for %s",tname,collname);
908
fprintf (scanF,"V%d\n",SCANVERSION);
909
(void) Tprocess (listT,recordone,scanF);
910
(void) fclose (scanF);
911
if (rename (tname,fname) < 0)
912
goaway ("Can't change %s to %s",tname,fname);
913
(void) unlink (tname);
914
tbuf[0].tv_sec = time((long *)NULL); tbuf[0].tv_usec = 0;
915
tbuf[1].tv_sec = scantime; tbuf[1].tv_usec = 0;
916
(void) utimes (fname,tbuf);
926
if (t->Tflags&FBACKUP) fprintf (*scanF,"B");
927
if (t->Tflags&FNOACCT) fprintf (*scanF,"N");
928
fprintf (*scanF,"%o %d %d %s\n",
929
t->Tmode,t->Tctime,t->Tmtime,t->Tname);
930
(void) Tprocess (t->Texec,recordexec,*scanF);
939
fprintf(*scanF,"X%s\n",t->Tname);
946
static char *curprefix = NULL;
948
if (curprefix == NULL) {
951
(void) chdir (prefix);
955
if (prefix == NULL) {
956
(void) chdir (basedir);
960
if (prefix == curprefix)
962
if (strcmp (prefix, curprefix) == 0) {
966
(void) chdir (basedir);
967
(void) chdir (prefix);