diff options
author | phk <phk@FreeBSD.org> | 1996-08-30 10:21:00 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1996-08-30 10:21:00 +0000 |
commit | d564e1831385a2423f7a027b94d614558a09d924 (patch) | |
tree | 3a20c2d604808479b1443b9686cfdce973836775 /usr.sbin/ctm | |
parent | 31060e30d73e1f88c3b5fa85b5e547fde68fc7ba (diff) | |
download | FreeBSD-src-d564e1831385a2423f7a027b94d614558a09d924.zip FreeBSD-src-d564e1831385a2423f7a027b94d614558a09d924.tar.gz |
Some new options, useful for restoring single files or subtrees from the
deltas.
Submitted by: A JOSEPH KOSHY <koshy@fakir.india.hp.com>
Diffstat (limited to 'usr.sbin/ctm')
-rw-r--r-- | usr.sbin/ctm/ctm/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm.1 | 147 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm.c | 125 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm.h | 25 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm_pass1.c | 84 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm_pass2.c | 55 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm_pass3.c | 43 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm_passb.c | 142 | ||||
-rw-r--r-- | usr.sbin/ctm/ctm/ctm_syntax.c | 20 |
9 files changed, 562 insertions, 83 deletions
diff --git a/usr.sbin/ctm/ctm/Makefile b/usr.sbin/ctm/ctm/Makefile index 567b203..0d1e044 100644 --- a/usr.sbin/ctm/ctm/Makefile +++ b/usr.sbin/ctm/ctm/Makefile @@ -6,13 +6,13 @@ # this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp # ---------------------------------------------------------------------------- # -# $Id: Makefile,v 1.8 1995/03/25 18:14:22 joerg Exp $ +# $Id: Makefile,v 1.9 1995/07/12 18:35:22 bde Exp $ # 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 diff --git a/usr.sbin/ctm/ctm/ctm.1 b/usr.sbin/ctm/ctm/ctm.1 index c28da41..e359857 100644 --- a/usr.sbin/ctm/ctm/ctm.1 +++ b/usr.sbin/ctm/ctm/ctm.1 @@ -10,7 +10,7 @@ .\" .\" CTM and ctm(1) by <phk@login.dknet.dk> .\" -.\" $Id: ctm.1,v 1.6 1996/05/27 22:46:21 wosch Exp $ +.\" $Id: ctm.1,v 1.7 1996/07/24 21:36:48 phk Exp $ .\" .Dd Mar 25, 1995 .Os @@ -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 @@ The 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 @@ If this file exists, .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 @@ are explicitly prohibited as a security measure. .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 @@ Tell us more. .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 @@ contains the sequence number of the last CTM delta applied. Changing 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 @@ cd ~cvs .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 @@ options. .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 diff --git a/usr.sbin/ctm/ctm/ctm.c b/usr.sbin/ctm/ctm/ctm.c index 0aff1a9..c0553ed 100644 --- a/usr.sbin/ctm/ctm/ctm.c +++ b/usr.sbin/ctm/ctm/ctm.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm.c,v 1.12 1996/02/05 16:06:46 phk Exp $ + * $Id: ctm.c,v 1.13 1996/04/29 21:02:28 phk Exp $ * * This is the client program of 'CTM'. It will apply a CTM-patch to a * collection of files. @@ -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 @@ extern int Proc(char *, unsigned applied); 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 @@ main(int argc, char **argv) } 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 @@ Proc(char *filename, unsigned applied) 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 @@ Proc(char *filename, unsigned applied) 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 @@ Proc(char *filename, unsigned applied) } 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 @@ exit_and_close: if(i) return i; - fprintf(stderr,"All done ok\n"); + if (Verbose > 0) + fprintf(stderr,"All done ok\n"); + return Exit_Done; } diff --git a/usr.sbin/ctm/ctm/ctm.h b/usr.sbin/ctm/ctm/ctm.h index a34a238..93498b5 100644 --- a/usr.sbin/ctm/ctm/ctm.h +++ b/usr.sbin/ctm/ctm/ctm.h @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm.h,v 1.8 1996/02/05 16:06:47 phk Exp $ + * $Id: ctm.h,v 1.9 1996/04/29 21:02:29 phk Exp $ * */ @@ -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 *FileName; 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 Verbose; 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 @@ EXTERN struct timeval Times[2]; #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 @@ u_char * Fdata(FILE *fd, int u_chars, MD5_CTX *ctx); 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); diff --git a/usr.sbin/ctm/ctm/ctm_pass1.c b/usr.sbin/ctm/ctm/ctm_pass1.c index d0bf6c3..563d4d9 100644 --- a/usr.sbin/ctm/ctm/ctm_pass1.c +++ b/usr.sbin/ctm/ctm/ctm_pass1.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm_pass1.c,v 1.11 1995/07/12 09:16:08 phk Exp $ + * $Id: ctm_pass1.c,v 1.12 1996/02/05 16:06:50 phk Exp $ * */ @@ -23,9 +23,9 @@ Pass1(FILE *fd, unsigned applied) 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 @@ Pass1(FILE *fd, unsigned applied) GETFIELDCOPY(Prefix,'\n'); /* <Prefix> */ sscanf(Nbr, "%u", ¤t); + 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 @@ Pass1(FILE *fd, unsigned applied) 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 @@ Pass1(FILE *fd, unsigned applied) 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 @@ Pass1(FILE *fd, unsigned applied) 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 @@ Pass1(FILE *fd, unsigned applied) 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 @@ Pass1(FILE *fd, unsigned applied) return 16; } } - return 0; + if ((Verbose > 1) && (0 == total_matches)) + printf("No matches in \"%s\"\n", FileName); + return (total_matches ? Exit_OK : Exit_NoMatch); } diff --git a/usr.sbin/ctm/ctm/ctm_pass2.c b/usr.sbin/ctm/ctm/ctm_pass2.c index 9ddd433..3261d8b 100644 --- a/usr.sbin/ctm/ctm/ctm_pass2.c +++ b/usr.sbin/ctm/ctm/ctm_pass2.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm_pass2.c,v 1.11 1996/02/05 16:06:52 phk Exp $ + * $Id: ctm_pass2.c,v 1.12 1996/04/29 21:02:30 phk Exp $ * */ @@ -27,7 +27,10 @@ Pass2(FILE *fd) 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 @@ Pass2(FILE *fd) 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 @@ Pass2(FILE *fd) 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 @@ Pass2(FILE *fd) 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 @@ Pass2(FILE *fd) 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); @@ -174,6 +201,30 @@ Pass2(FILE *fd) } 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); } break; diff --git a/usr.sbin/ctm/ctm/ctm_pass3.c b/usr.sbin/ctm/ctm/ctm_pass3.c index 07d3e6b..2b69c16 100644 --- a/usr.sbin/ctm/ctm/ctm_pass3.c +++ b/usr.sbin/ctm/ctm/ctm_pass3.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm_pass3.c,v 1.12 1996/02/05 16:06:53 phk Exp $ + * $Id: ctm_pass3.c,v 1.13 1996/04/29 21:02:32 phk Exp $ * */ @@ -39,8 +39,9 @@ Pass3(FILE *fd) 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 @@ Pass3(FILE *fd) 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 @@ Pass3(FILE *fd) 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 @@ Pass3(FILE *fd) * 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 diff --git a/usr.sbin/ctm/ctm/ctm_passb.c b/usr.sbin/ctm/ctm/ctm_passb.c new file mode 100644 index 0000000..0fce077 --- /dev/null +++ b/usr.sbin/ctm/ctm/ctm_passb.c @@ -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; +} diff --git a/usr.sbin/ctm/ctm/ctm_syntax.c b/usr.sbin/ctm/ctm/ctm_syntax.c index 30e2435..014207f 100644 --- a/usr.sbin/ctm/ctm/ctm_syntax.c +++ b/usr.sbin/ctm/ctm/ctm_syntax.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: ctm_syntax.c,v 1.5 1995/05/30 03:47:28 rgrimes Exp $ + * $Id: ctm_syntax.c,v 1.6 1996/02/05 16:06:55 phk Exp $ * */ @@ -56,12 +56,12 @@ static int ctmDR[] = /* Directory Remove */ { 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} }; |