Some new options, useful for restoring single files or subtrees from the
deltas. Submitted by: A JOSEPH KOSHY <koshy@fakir.india.hp.com>
This commit is contained in:
parent
e7d24931fe
commit
d09e8179fa
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=17946
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 @@ Proc(char *filename, unsigned applied)
|
||||
if(i)
|
||||
return i;
|
||||
|
||||
fprintf(stderr,"All done ok\n");
|
||||
if (Verbose > 0)
|
||||
fprintf(stderr,"All done ok\n");
|
||||
|
||||
return Exit_Done;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
142
usr.sbin/ctm/ctm/ctm_passb.c
Normal file
142
usr.sbin/ctm/ctm/ctm_passb.c
Normal file
@ -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;
|
||||
}
|
@ -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} };
|
||||
|
Loading…
Reference in New Issue
Block a user