Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 04 Aug 1996 22:29:44 +0200
From:      Poul-Henning Kamp <phk@critter.tfs.com>
To:        ctm-announce@freebsd.org
Subject:   patches to CTM, please test.
Message-ID:  <2400.839190584@critter.tfs.com>

next in thread | raw e-mail | index | archive | help

Please try these patches to CTM and send me email with feedback.

I'v manipulated the patch to try to create a new file "ctm_passb.c"
it may or may not work, if it fails, just edit it by hand.

Poul-Henning

Index: Makefile
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/Makefile,v
retrieving revision 1.9
diff -u -r1.9 Makefile
--- Makefile	1995/07/12 18:35:22	1.9
+++ Makefile	1996/07/29 08:23:49
@@ -12,7 +12,7 @@
 PROG=		ctm
 NOTYET=		ctm_ed.c
 SRCS=   	ctm.c ctm_input.c ctm_pass1.c ctm_pass2.c ctm_pass3.c \
-		ctm_syntax.c ctm_ed.c
+		ctm_passb.c ctm_syntax.c ctm_ed.c
 LDADD+=		-lmd
 DPADD+=		${LIBMD}
 MAN1=		ctm.1
Index: ctm.1
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm.1,v
retrieving revision 1.7
diff -u -r1.7 ctm.1
--- ctm.1	1996/07/24 21:36:48	1.7
+++ ctm.1	1996/07/29 10:51:06
@@ -20,11 +20,15 @@
 .Nd source code mirror program
 .Sh SYNOPSIS
 .Nm ctm
-.Op Fl cFpPquv
+.Op Fl cFklquv
 .Op Fl b Ar basedir
+.Op Fl B Ar backup-file
+.Op Fl e Ar include-regex
+.Op Fl t Ar tar-command
 .Op Fl T Ar tmpdir
 .Op Fl V Ar level
-.Ar file Op ...
+.Op Fl x Ar exclude-regex
+.Ar file...
 .Sh DESCRIPTION
 .Nm Ctm
 was originally
@@ -55,7 +59,7 @@
 command runs in a number of passes.  It will process the entire
 input file in each pass, before commencing with the next pass.
 
-Before working one a file
+Before working on a file
 .Ar name
 .Nm ctm
 first checks for the existence of the file
@@ -64,17 +68,45 @@
 .Nm ctm
 works on it instead.
 
-Pass 1 will validate that the input file is OK.  The syntax, the data
+Pass 1 will verify that the input file is OK.  The syntax, the data
 and the global MD5 checksum will be checked.  If any of these fail,
 .Nm ctm
-will never be able to do anything with the file, so it will simply
-reject it.
+will simply reject the input file.
 
 Pass 2 will validate that the directory tree is in the state expected by
 the CTM delta.  This is done by looking for files and directories which
-should/should not exists and by checking the MD5 checksums of files.  
+should/should not exist and by checking the MD5 checksums of files.  
 
-Pass 3 will actually apply the delta.
+If a
+.Ar backup-file
+had been specified using the 
+.Fl B
+option, all files that would be modified by this 
+.Nm ctm
+invocation are backed up
+to this file using the archiver command specified by the 
+.Fl t
+option.  The default archiver command is
+.Nm "tar -rf %s -T -" .
+
+Pass 3 will actually apply the delta. 
+
+The list of files that would be modified by
+.Nm ctm 
+is subject to filtering regular expressions specified
+using the
+.Fl e
+and
+.Fl x
+options.
+The
+.Fl e
+and 
+.Fl x
+options are applied in order of appearance on the command line.  The last
+filter that matched a given file name determines whether the file would be 
+operated on or left alone by
+.Nm ctm .
 
 .Nm Ctm
 will extract the file hierarchy below its working directory.  Absolute
@@ -91,23 +123,76 @@
 .It Fl b Ar basedir
 Prepend the path
 .Ar basedir
-on every filename.
+to every filename.
+
+.It Fl B Ar backup-file
+Backup all files that would be modified by this CTM run to
+.Ar backup-file .
+If any filters are specified using the
+.Fl e
+and
+.Fl x
+options, then the final set of files backed up are those that would be
+modified by CTM after the filters are applied.
 
 .It Fl c
 Check it out, don't do anything.
 
+.It Fl e Ar regular_expression
+Match each name in the CTM file against
+.Ar regular_expression ,
+and if it matches process the file, otherwise leave it alone.  There may be
+any number of these options.  Use of this option disables the
+.Pa .ctm_status
+sequence number checks.  For example, the expression 
+.Ic ^usr.sbin/ctm 
+for example, will select the
+.Nm usr.sbin/ctm
+source directory and all pathnames under it. 
+
+Pathnames can be disabled from being considered by CTM using the 
+.Fl x
+option.
+
 .It Fl F
 Force.
 
-.It Fl p
-Less paranoid.
+.It Fl k
+Keep files and directories and don't remove them even if the CTM file
+specifies they are to be removed.  If the
+.Fl B
+option is specified, these files and directories will not be backed up.
+
+.It Fl l
+List files that would be modified by this invocation of CTM and the
+actions that would be performed on them.  Use of the
+.Fl l
+option disables the
+.Pa .ctm_status
+checks and integrity checks on the source tree being operated on.  The
+.Fl l
+option can be combined with the 
+.Fl e
+and
+.Fl x
+options to determine which files would be modified by the given set of
+command line options.
 
-.It Fl P
-Paranoid.
 
 .It Fl q
 Tell us less.
 
+.It Fl t Ar tar-command
+Use
+.Ar tar-command
+instead of the default archiver
+.Nm tar .
+This option takes effect only if a backup file had been specified using the
+.Fl B
+option.  A %s in the tar command will be replaced by the name of the backup 
+file.
+
+
 .It Fl T Ar tmpdir
 Put temporary files under
 .Ar tmpdir .
@@ -124,6 +209,18 @@
 .Ar Level
 is the level of verbosity.
 
+.It Fl x Ar regular_expression
+Match each name in the CTM file against
+.Ar regular_expression
+and if it matches, leave the file alone.  There may be any number of these
+options.  Use of this option disables the
+.Pa .ctm_status
+sequence number checks.   
+
+Pathnames can be selected for CTM's consideration using the
+.Fl e
+option.
+
 .El
 
 .Sh ENVIRONMENT
@@ -144,6 +241,14 @@
 or removing this file will greatly confuse
 .Nm ctm .
 
+Using the
+.Fl e
+and
+.Fl x
+options can update a partial subset of the source tree and causes sources
+to be in an inconsistent state.  It is assumed that you know what you are
+doing when you use these options.
+
 .Sh EXAMPLES
 
 .Bd -literal
@@ -153,14 +258,20 @@
 
 .Ed
 
+To extract and patch all sources under `lib'
+.Bd -literal
+cd ~/lib-srcs
+/usr/sbin/ctm -e '^lib' ~ctm/src-cur*
+.Ed
 .Sh DIAGNOSTICS
 
-Numerous messages, hopefully self-explaining.  The
+Numerous messages, hopefully self-explanatory.  The
 .Dq noise level
 can be adjusted with the
-.Fl q
-and
+.Fl q ,
 .Fl v
+and
+.Fl V
 options.
 
 .Sh SEE ALSO
@@ -169,7 +280,7 @@
 
 .Sh HISTORY
 
-Initial trials ran during the FreeBSD 1.1.5, and many bugs and 
+Initial trials were run during the work on FreeBSD 1.1.5, and many bugs and 
 methods were hashed out.
 
 The
Index: ctm.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm.c,v
retrieving revision 1.13
diff -u -r1.13 ctm.c
--- ctm.c	1996/04/29 21:02:28	1.13
+++ ctm.c	1996/07/29 08:23:50
@@ -14,7 +14,6 @@
  * Options we'd like to see:
  *
  * -a 			Attempt best effort.
- * -B <file>		Backup to tar-file.
  * -d <int>		Debug TBD.
  * -m <mail-addr>	Email me instead.
  * -r <name>		Reconstruct file.
@@ -22,16 +21,21 @@
  *
  * Options we have:
  * -b <dir>		Base-dir
+ * -B <file>		Backup to tar-file.
+ * -t 			Tar command (default as in TARCMD).
  * -c			Check it out, don't do anything.
  * -F      		Force
- * -p			Less paranoid.
- * -P			Paranoid.
  * -q 			Tell us less.
  * -T <tmpdir>.		Temporary files.
  * -u			Set all file modification times to the timestamp
  * -v 			Tell us more.
  * -V <level>		Tell us more level = number of -v
+ * -k			Keep files and directories that would have been removed.
+ * -l			List actions.
  *
+ * Options we don't actually use:
+ * -p			Less paranoid.
+ * -P			Paranoid.
  */
 
 #define EXTERN /* */
@@ -44,35 +48,82 @@
 int
 main(int argc, char **argv)
 {
-    int stat=0;
+    int stat=0, err=0;
     int c;
     extern int optopt,optind;
     extern char * optarg;
     unsigned applied = 0;
     FILE *statfile;
+    struct CTM_Filter *nfilter = NULL;	/* new filter */
     u_char * basedir;
 
     basedir = NULL;
     Verbose = 1;
     Paranoid = 1;
     SetTime = 0;
+    KeepIt = 0;
+    ListIt = 0;
+    BackupFile = NULL;
+    TarCmd = TARCMD;
+    LastFilter = FilterList = NULL;
     setbuf(stderr,0);
     setbuf(stdout,0);
 
-    while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:uV:v")) != -1) {
+    while((c=getopt(argc,argv,"ab:B:cd:e:Fklm:pPqr:R:t:T:uV:vx:")) != -1) {
 	switch (c) {
 	    case 'b': basedir = optarg;	break; /* Base Directory */
+	    case 'B': BackupFile = optarg;	break;
 	    case 'c': CheckIt++;	break; /* Only check it */
+	    case 'F': Force = 1;	break; 
+	    case 'k': KeepIt++;		break; /* Don't do removes */
+	    case 'l': ListIt++;		break; /* Only list actions and files */
 	    case 'p': Paranoid--;	break; /* Less Paranoid */
 	    case 'P': Paranoid++;	break; /* More Paranoid */
 	    case 'q': Verbose--;	break; /* Quiet */
-	    case 'v': Verbose++;	break; /* Verbose */
-	    case 'T': TmpDir = optarg;	break;
-	    case 'F': Force = 1;	break;
+	    case 't': TarCmd = optarg;	break; /* archiver command */
+	    case 'T': TmpDir = optarg;	break; /* set temporary directory */
 	    case 'u': SetTime++;	break; /* Set timestamp on files */
+	    case 'v': Verbose++;	break; /* Verbose */
 	    case 'V': sscanf(optarg,"%d", &c); /* Verbose */
 		      Verbose += c;
 		      break;
+	    case 'e':				/* filter expressions */
+	    case 'x':
+		if (NULL == (nfilter =  Malloc(sizeof(struct CTM_Filter)))) {
+			fprintf(stderr, 
+				"Out of memory for expressions: \"%s\"\n",
+			  	optarg);
+			 stat++;
+			break;
+		}
+
+		(void) memset(nfilter, 0, sizeof(struct CTM_Filter));
+
+		if (0 != (err = 
+			regcomp(&nfilter->CompiledRegex, optarg, REG_NOSUB))) {
+
+			char errmsg[128];
+
+			regerror(err, &nfilter->CompiledRegex, errmsg, 
+				sizeof(errmsg));
+			fprintf(stderr, "Regular expression: \"%s\"\n", errmsg);
+			stat++;
+			break;
+		}
+
+		/* note whether the filter enables or disables on match */
+		nfilter->Action = 
+			(('e' == c) ? CTM_FILTER_ENABLE : CTM_FILTER_DISABLE);
+
+		/* link in the expression into the list */
+	        nfilter->Next = NULL;
+		if (NULL == FilterList) {
+		  LastFilter = FilterList = nfilter; /* init head and tail */
+		} else {    /* place at tail */
+		  LastFilter->Next = nfilter;
+		  LastFilter = nfilter;	
+		}
+		break;
 	    case ':':
 		fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
 		stat++;
@@ -110,26 +161,37 @@
     }
     strcat(Buffer, CTM_STATUS);
 
-    if((statfile = fopen(Buffer, "r")) == NULL)
-	fprintf(stderr, "Warning: %s not found.\n", Buffer);
-    else {
-	fscanf(statfile, "%*s %u", &applied);
-	fclose(statfile);
-    }
+    if(ListIt) 
+	applied = 0;
+    else
+	if((statfile = fopen(Buffer, "r")) == NULL) {
+	    if (Verbose > 0)
+	    	fprintf(stderr, "Warning: %s not found.\n", Buffer);
+	} else {
+	    fscanf(statfile, "%*s %u", &applied);
+	    fclose(statfile);
+	}
 
     if(!argc)
 	stat |= Proc("-", applied);
 
     while(argc-- && stat == Exit_Done) {
 	stat |= Proc(*argv++, applied);
-	stat &= ~Exit_Version;
+	stat &= ~(Exit_Version | Exit_NoMatch);
     }
 
     if(stat == Exit_Done)
 	stat = Exit_OK;
 
-    if(Verbose)
+    if(Verbose > 0)
 	fprintf(stderr,"Exit(%d)\n",stat);
+
+    if (FilterList)
+	for (nfilter = FilterList; nfilter; ) {
+	    struct CTM_Filter *tmp = nfilter->Next;
+	    Free(nfilter);
+	    nfilter = tmp;
+	}
     return stat;
 }
 
@@ -176,7 +238,8 @@
 	    return Exit_Broke;
 	}
 	unlink(fn);
-	fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
+	if (Verbose > 0)
+	    fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
 	while(EOF != (i=getc(f)))
 	    if(EOF == putc(i,f2)) {
 		fclose(f2);
@@ -192,6 +255,11 @@
     if((i=Pass1(f, applied)))
 	goto exit_and_close;
 
+    if(ListIt) {
+	i = Exit_Done;
+	goto exit_and_close;
+    }
+
     if(!p) {
         rewind(f);
     } else {
@@ -216,10 +284,25 @@
     }
 
     if(CheckIt) {
-        fprintf(stderr,"All checks out ok.\n");
+	if (Verbose > 0) 
+	    fprintf(stderr,"All checks out ok.\n");
 	i = Exit_Done;
 	goto exit_and_close;
     }
+   
+    /* backup files if requested */
+    if(BackupFile) {
+
+	i = PassB(f);
+
+	if(!p) {
+	    rewind(f);
+	} else {
+	    pclose(f);
+	    f = popen(p,"r");
+	    if(!f) { perror(p); return Exit_Broke; }
+	}
+    }
 
     i=Pass3(f);
 
@@ -232,6 +315,8 @@
     if(i)
 	return i;
 
-    fprintf(stderr,"All done ok\n");
+    if (Verbose > 0)
+	fprintf(stderr,"All done ok\n");
+
     return Exit_Done;
 }
Index: ctm.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm.h,v
retrieving revision 1.9
diff -u -r1.9 ctm.h
--- ctm.h	1996/04/29 21:02:29	1.9
+++ ctm.h	1996/07/29 08:23:50
@@ -22,12 +22,14 @@
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/time.h>
+#include <regex.h>
 
 #define VERSION "2.0"
 #define MAXSIZE (1024*1024*10)
 
 #define SUBSUFF ".ctm"
 #define TMPSUFF ".ctmtmp"
+#define TARCMD  "tar -rf %s -T -"
 
 /* The fields... */
 #define CTM_F_MASK		0xff
@@ -51,12 +53,21 @@
 #define CTM_Q_MD5_Force		0x0800
 
 struct CTM_Syntax {
-    char	*Key;
-    int		*List;
+    char	*Key;		/* CTM key for operation */
+    int		*List;		/* List of operations */
     };
 
 extern struct CTM_Syntax Syntax[];
 
+struct CTM_Filter {
+    struct CTM_Filter	*Next;	/* next filter in the list */
+    int 		Action;	/* enable or disable */
+    regex_t 		CompiledRegex;	/* compiled regex */
+};
+
+#define	CTM_FILTER_DISABLE	0
+#define	CTM_FILTER_ENABLE	1
+
 #define Malloc malloc
 #define Free free
 #define Delete(foo) if (!foo) ; else {Free(foo); foo = 0; }
@@ -74,6 +85,8 @@
 EXTERN u_char *TmpDir;
 EXTERN u_char *CatPtr;
 EXTERN u_char *Buffer;
+EXTERN u_char *BackupFile;
+EXTERN u_char *TarCmd;
 
 /*
  * Paranoid -- Just in case they should be after us...
@@ -106,8 +119,12 @@
 EXTERN int Exit;
 EXTERN int Force;
 EXTERN int CheckIt;
+EXTERN int KeepIt;
+EXTERN int ListIt;
 EXTERN int SetTime;
 EXTERN struct timeval Times[2];
+EXTERN struct CTM_Filter	*FilterList;
+EXTERN struct CTM_Filter	*LastFilter;
 
 #define Exit_OK		0
 #define Exit_Garbage	1
@@ -118,6 +135,7 @@
 #define Exit_Mess	32
 #define Exit_Done	64
 #define Exit_Version	128
+#define Exit_NoMatch	256
 
 void Fatal_(int ln, char *fn, char *kind);
 #define Fatal(foo) Fatal_(__LINE__,__FILE__,foo)
@@ -139,6 +157,7 @@
 
 int Pass1(FILE *fd, unsigned applied);
 int Pass2(FILE *fd);
+int PassB(FILE *fd);
 int Pass3(FILE *fd);
 
 int ctm_edit(u_char *script, int length, char *filein, char *fileout);
Index: ctm_pass1.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm_pass1.c,v
retrieving revision 1.12
diff -u -r1.12 ctm_pass1.c
--- ctm_pass1.c	1996/02/05 16:06:50	1.12
+++ ctm_pass1.c	1996/07/29 08:23:50
@@ -23,9 +23,9 @@
     u_char *p,*q;
     MD5_CTX ctx;
     int i,j,sep,cnt;
-    u_char *md5=0,*trash=0;
+    u_char *md5=0,*name=0,*trash=0;
     struct CTM_Syntax *sp;
-    int slashwarn=0;
+    int slashwarn=0, match=0, total_matches=0;
     unsigned current;
     char md5_1[33];
 
@@ -55,8 +55,10 @@
     GETFIELDCOPY(Prefix,'\n');				/* <Prefix> */
 
     sscanf(Nbr, "%u", &current);
+    if (FilterList || ListIt)
+	current = 0;	/* ignore if -l or if filters are present */
     if(current && current <= applied) {
-	if(Verbose)
+	if(Verbose > 0)
 	    fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
 		    current);
 	return Exit_Version;
@@ -64,8 +66,14 @@
 
     for(;;) {
 	Delete(md5);
+	Delete(name);
 	Delete(trash);
 	cnt = -1;
+	/* if a filter list is defined we assume that all pathnames require
+	   an action opposite to that requested by the first filter in the
+	   list.
+	   If no filter is defined, all pathnames are assumed to match. */
+	match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
 
 	GETFIELD(p,' ');			/* CTM_something */
 
@@ -92,31 +100,61 @@
 		sep = ' ';
 	    else
 		sep = '\n';
-	if(Verbose > 5)
-	    fprintf(stderr," %x(%d)",sp->List[i],sep);
+
+	    if(Verbose > 5)
+	        fprintf(stderr," %x(%d)",sp->List[i],sep);
 
 	    switch (j & CTM_F_MASK) {
 		case CTM_F_Name: /* XXX check for garbage and .. */
-		    GETFIELD(p,sep);
-		    j = strlen(p);
-		    if(p[j-1] == '/' && !slashwarn)  {
+		    GETFIELDCOPY(name,sep);
+		    j = strlen(name);
+		    if(name[j-1] == '/' && !slashwarn)  {
 			fprintf(stderr,"Warning: contains trailing slash\n");
 			slashwarn++;
 		    }
-		    if (p[0] == '/') {
+		    if (name[0] == '/') {
 			Fatal("Absolute paths are illegal.");
 			return Exit_Mess;
 		    }
+		    q = name;
 		    for (;;) {
-			if (p[0] == '.' && p[1] == '.')
-			    if (p[2] == '/' || p[2] == '\0') {
+			if (q[0] == '.' && q[1] == '.')
+			    if (q[2] == '/' || q[2] == '\0') {
 				Fatal("Paths containing '..' are illegal.");
 				return Exit_Mess;
 			    }
-			if ((p = strchr(p, '/')) == NULL)
+			if ((q = strchr(q, '/')) == NULL)
 			    break;
-			p++;
+			q++;
+		    }
+
+		    /* if we have been asked to `keep' files then skip
+		       removes; i.e. we don't match these entries at
+		       all. */
+		    if (KeepIt &&
+			(!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
+			match = CTM_FILTER_DISABLE;
+			break;
+		    }
+
+		    /* If filter expression have been defined, match the
+		       path name against the expression list.  */
+		    
+		    if (FilterList) {
+			struct CTM_Filter *filter;
+
+			for (filter = FilterList; filter; 
+			     filter = filter->Next) {
+				if (0 == regexec(&filter->CompiledRegex, name,
+					0, 0, 0))
+					/* if the name matches, adopt the 
+					   action */
+					match = filter->Action;
+			}
 		    }
+
+		    /* Add up the total number of matches */
+		    total_matches += match;
 		    break;
 		case CTM_F_Uid:
 		    GETFIELD(p,sep);
@@ -170,22 +208,22 @@
 		    p = MD5Data(trash,cnt,md5_1);
 		    if(md5 && strcmp(md5,p)) {
 			Fatal("Internal MD5 failed.");
-			return 1;
+			return Exit_Garbage;
 		default:
 			fprintf(stderr,"List = 0x%x\n",j);
 			Fatal("List had garbage.");
-			return 1;
-
+			return Exit_Garbage;
 		    }
-
-		}
 	    }
+	}
 	if(Verbose > 5)
 	    putc('\n',stderr);
-	continue;
+	if(ListIt && match)
+	    printf("> %s %s\n", sp->Key, name);
     }
 
     Delete(md5);
+    Delete(name);
     Delete(trash);
 
     q = MD5End (&ctx,md5_1);
@@ -198,7 +236,7 @@
 	Fatal("MD5 sum doesn't match.");
 	fprintf(stderr,"\tI have:<%s>\n",q);
 	fprintf(stderr,"\tShould have been:<%s>\n",p);
-	return 1;
+	return Exit_Garbage;
     }
     if (-1 != getc(fd)) {
 	if(!Force) {
@@ -206,5 +244,7 @@
 	    return 16;
 	}
     }
-    return 0;
+    if ((Verbose > 1) && (0 == total_matches))
+	printf("No matches in \"%s\"\n", FileName);
+    return (total_matches ? Exit_OK : Exit_NoMatch);
 }
Index: ctm_pass2.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm_pass2.c,v
retrieving revision 1.12
diff -u -r1.12 ctm_pass2.c
--- ctm_pass2.c	1996/04/29 21:02:30	1.12
+++ ctm_pass2.c	1996/07/29 08:23:50
@@ -27,7 +27,10 @@
     struct CTM_Syntax *sp;
     struct stat st;
     int ret = 0;
+    int match = 0;
     char md5_1[33];
+    struct CTM_Filter *filter;
+    FILE *ed = NULL;
 
     if(Verbose>3)
 	printf("Pass2 -- Checking if CTM-patch will apply\n");
@@ -49,6 +52,12 @@
 	Delete(md5);
 	cnt = -1;
 
+	/* if a filter list was specified, check file name against
+	   the filters specified 
+	   if no filter was given operate on all files. */
+	match = (FilterList ? 
+		    !(FilterList->Action) : CTM_FILTER_ENABLE);
+
 	GETFIELD(p,' ');
 
 	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
@@ -70,6 +79,22 @@
 	    switch (j & CTM_F_MASK) {
 		case CTM_F_Name:
 		    GETNAMECOPY(name,sep,j,0);
+		    /* If `keep' was specified, we won't remove any files,
+		       so don't check if the file exists */
+		    if (KeepIt &&
+			(!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
+			match = CTM_FILTER_DISABLE;
+			break;
+		    }
+
+		    for (filter = FilterList; filter; filter = filter->Next)				if (0 == regexec(&filter->CompiledRegex, name,
+				    0, 0, 0)) {
+				    match = filter->Action;
+			    }
+
+		    if (CTM_FILTER_DISABLE == match)
+			    break;	/* should ignore this file */
+
 		    /* XXX Check DR DM rec's for parent-dir */
 		    if(j & CTM_Q_Name_New) {
 			/* XXX Check DR FR rec's for item */
@@ -124,7 +149,7 @@
 		    if(j & CTM_Q_MD5_Before) {
 		        char *tmp;
 			GETFIELD(p,sep);
-			if((st.st_mode & S_IFMT) == S_IFREG &&
+			if(match && (st.st_mode & S_IFMT) == S_IFREG &&
 			  (tmp = MD5File(name,md5_1)) != NULL &&
 			  strcmp(tmp,p)) {
 			    fprintf(stderr,"  %s: %s md5 mismatch.\n",
@@ -154,6 +179,8 @@
 		case CTM_F_Bytes:
 		    if(cnt < 0) WRONG
 		    GETDATA(trash,cnt);
+		    if (!match)
+			break;
 		    if(!strcmp(sp->Key,"FN")) {
 			p = tempnam(TmpDir,"CTMclient");
 			j = ctm_edit(trash,cnt,name,p);
@@ -171,6 +198,30 @@
 			    unlink(p);
 			    Free(p);
 			    return ret;
+			}
+		        unlink(p);
+			Free(p);
+		    } else if (!strcmp(sp->Key,"FE")) {
+			p = tempnam(TmpDir,"CTMclient");
+			ed = popen("ed","w");
+			if (!ed) {
+			    WRONG
+			}
+			fprintf(ed,"e %s\n", name);
+			if (cnt != fwrite(trash,1,cnt,ed)) {
+			    perror(name);
+			    pclose(ed);
+			    WRONG
+			}
+			fprintf(ed,"w %s\n",p);
+			if (pclose(ed)) {
+			    perror(p);
+			    WRONG
+			}
+			if(strcmp(md5,MD5File(p,md5_1))) {
+			    fprintf(stderr,"%s %s MD5 didn't come out right\n",
+				sp->Key, name);
+			    WRONG
 			}
 		        unlink(p);
 			Free(p);
Index: ctm_pass3.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm_pass3.c,v
retrieving revision 1.13
diff -u -r1.13 ctm_pass3.c
--- ctm_pass3.c	1996/04/29 21:02:32	1.13
+++ ctm_pass3.c	1996/07/29 08:23:50
@@ -39,8 +39,9 @@
     FILE *ed=0;
     struct stat st;
     char md5_1[33];
+    int match=0;
     struct timeval times[2];
-
+    struct CTM_Filter *filter = NULL;
     if(Verbose>3)
 	printf("Pass3 -- Applying the CTM-patch\n");
     MD5Init (&ctx);
@@ -153,7 +154,27 @@
 	j = strlen(name)-1;
 	if(name[j] == '/') name[j] = '\0';
 
-	fprintf(stderr,"> %s %s\n",sp->Key,name);
+	/*
+	 * If a filter list is specified, run thru the filter list and
+	 * match `name' against filters.  If the name matches, set the
+	 * required action to that specified in the filter.
+	 * The default action if no filterlist is given is to match
+	 * everything.  
+	 */
+
+	match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
+	for (filter = FilterList; filter; filter = filter->Next) {
+	    if (0 == regexec(&filter->CompiledRegex, name,
+		0, 0, 0)) {
+		match = filter->Action;
+	    }
+	}
+
+	if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
+		continue;
+
+	if (Verbose > 0)
+		fprintf(stderr,"> %s %s\n",sp->Key,name);
 	if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
 	    i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
 	    if(i < 0) {
@@ -228,7 +249,11 @@
 	    continue;
 	}
 	if(!strcmp(sp->Key,"FR")) {
-	    if (0 != unlink(name)) {
+	    if (KeepIt) { 
+		if (Verbose > 1) 
+			printf("<%s> not removed\n", name);
+	    }
+	    else if (0 != unlink(name)) {
 		fprintf(stderr,"<%s> unlink failed\n",name);
 		if (!Force)
 		    WRONG
@@ -240,8 +265,14 @@
 	     * We cannot use rmdir() because we do not get the directories
 	     * in '-depth' order (cvs-cur.0018.gz for examples)
 	     */
-	    sprintf(buf,"rm -rf %s",name);
-	    system(buf);
+	    if (KeepIt) {
+		if (Verbose > 1) {
+			printf("<%s> not removed\n", name);
+		}
+	    } else {
+		    sprintf(buf,"rm -rf %s",name);
+		    system(buf);
+	    }
 	    continue;
 	}
 	WRONG
Index: ctm_syntax.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/ctm/ctm/ctm_syntax.c,v
retrieving revision 1.6
diff -u -r1.6 ctm_syntax.c
--- ctm_syntax.c	1996/02/05 16:06:55	1.6
+++ ctm_syntax.c	1996/07/29 08:23:50
@@ -56,12 +56,12 @@
     { Name|Dir, 0 };
 
 struct CTM_Syntax Syntax[] = {
-    { "FM", ctmFM },
-    { "FS", ctmFS },
-    { "FE", ctmFE },
-    { "FN", ctmFE },
-    { "FR", ctmFR },
-    { "AS", ctmAS },
-    { "DM", ctmDM },
-    { "DR", ctmDR },
-    { 0, 0} };
+    { "FM",  	ctmFM },
+    { "FS",  	ctmFS },
+    { "FE",  	ctmFE },
+    { "FN",  	ctmFE },
+    { "FR",  	ctmFR },
+    { "AS", 	ctmAS },
+    { "DM",  	ctmDM },
+    { "DR",  	ctmDR },
+    { 0,    	0} };
--- /dev/null	Sun Aug  4 15:20:04 1996
+++ ctm_passb.c	Mon Jul 29 12:44:41 1996
@@ -0,0 +1,142 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <koshy@india.hp.com> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Joseph Koshy
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+#define BADREAD 32
+
+/*---------------------------------------------------------------------------*/
+/* PassB -- Backup modified files.
+ */
+
+int
+PassB(FILE *fd)
+{
+    u_char *p,*q;
+    MD5_CTX ctx;
+    int i,j,sep,cnt;
+    u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
+    struct CTM_Syntax *sp;
+    FILE *b = 0;	/* backup command */
+    u_char buf[BUFSIZ];
+    char md5_1[33];
+    int ret = 0;
+    int match = 0;
+    struct CTM_Filter *filter = NULL;
+
+    if(Verbose>3)
+	printf("PassB -- Backing up files which would be changed.\n");
+
+    MD5Init (&ctx);
+    sprintf(buf, TarCmd, BackupFile);
+    b=popen(buf, "w");
+    if(!b) { perror(buf); return Exit_Garbage; }
+
+    GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
+    GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
+    GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
+    GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
+    GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
+    GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
+
+    for(;;) {
+	Delete(md5);
+	Delete(uid);
+	Delete(gid);
+	Delete(mode);
+	Delete(md5before);
+	Delete(trash);
+	Delete(name);
+	cnt = -1;
+
+	GETFIELD(p,' ');
+
+	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
+
+	if(!strcmp(p+3,"_END"))
+	    break;
+
+	for(sp=Syntax;sp->Key;sp++)
+	    if(!strcmp(p+3,sp->Key))
+		goto found;
+	WRONG
+    found:
+	for(i=0;(j = sp->List[i]);i++) {
+	    if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+		sep = ' ';
+	    else
+		sep = '\n';
+
+	    switch (j & CTM_F_MASK) {
+		case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
+		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
+		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
+		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
+		case CTM_F_MD5:
+		    if(j & CTM_Q_MD5_Before)
+			GETFIELDCOPY(md5before,sep);
+		    else
+			GETFIELDCOPY(md5,sep);
+		    break;
+		case CTM_F_Count: GETBYTECNT(cnt,sep); break;
+		case CTM_F_Bytes: GETDATA(trash,cnt); break;
+		default: WRONG
+		}
+	    }
+	/* XXX This should go away.  Disallow trailing '/' */
+	j = strlen(name)-1;
+	if(name[j] == '/') name[j] = '\0';
+
+	if (KeepIt && 
+	    (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR")))
+	    continue;
+		
+	/* match the name against the elements of the filter list.  The
+	   action associated with the last matched filter determines whether
+	   this file should be ignored or backed up. */
+	match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
+	for (filter = FilterList; filter; filter = filter->Next) {
+	    if (0 == regexec(&filter->CompiledRegex, name, 0, 0, 0))
+		match = filter->Action;
+	}
+
+	if (CTM_FILTER_DISABLE == match)
+		continue;
+
+	if (!strcmp(sp->Key,"FS") || !strcmp(sp->Key,"FN") ||
+	    !strcmp(sp->Key,"AS") || !strcmp(sp->Key,"DR") || 
+	    !strcmp(sp->Key,"FR")) {
+	    /* send name to the archiver for a backup */
+	    cnt = strlen(name);
+	    if (cnt != fwrite(name,1,cnt,b) || EOF == fputc('\n',b)) {
+		perror(name);
+		pclose(b);
+		WRONG;
+	    }
+	}
+    }
+
+    ret = pclose(b);
+
+    Delete(md5);
+    Delete(uid);
+    Delete(gid);
+    Delete(mode);
+    Delete(md5before);
+    Delete(trash);
+    Delete(name);
+
+    q = MD5End (&ctx,md5_1);
+    GETFIELD(p,'\n');			/* <MD5> */
+    if(strcmp(q,p)) WRONG
+    if (-1 != getc(fd)) WRONG
+    return ret;
+}
--
Poul-Henning Kamp           | phk@FreeBSD.ORG       FreeBSD Core-team.
http://www.freebsd.org/~phk | phk@login.dknet.dk    Private mailbox.
whois: [PHK]                | phk@ref.tfs.com       TRW Financial Systems, Inc.
Future will arrive by its own means, progress not so.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2400.839190584>