summaryrefslogtreecommitdiff
path: root/usr.sbin/ctm
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1999-07-13 23:02:08 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1999-07-13 23:02:08 +0000
commitd7f078ed3c1fe896ddc91fc0aef7de14eb11baff (patch)
tree8cfc5028cfda6a899596d77738886790271aaa71 /usr.sbin/ctm
parent8f1871270d687d64197c78161af331eebf21b260 (diff)
Merge with FreeBSD 3.2, while keeping OpenBSD mktemp/mkstemp fixes.
Some minor man page enhancements. Brings better man pages, new features, more error checking, and improved performance; some FreeBSD examples for creating ctm deltas merged by hgweigand@wiesbaden.netsurf.de
Diffstat (limited to 'usr.sbin/ctm')
-rw-r--r--usr.sbin/ctm/Makefile4
-rw-r--r--usr.sbin/ctm/README6
-rw-r--r--usr.sbin/ctm/ctm/Makefile4
-rw-r--r--usr.sbin/ctm/ctm/ctm.1202
-rw-r--r--usr.sbin/ctm/ctm/ctm.58
-rw-r--r--usr.sbin/ctm/ctm/ctm.c149
-rw-r--r--usr.sbin/ctm/ctm/ctm.h34
-rw-r--r--usr.sbin/ctm/ctm/ctm_ed.c12
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass1.c84
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass2.c55
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass3.c58
-rw-r--r--usr.sbin/ctm/ctm/ctm_passb.c142
-rw-r--r--usr.sbin/ctm/ctm/ctm_syntax.c20
-rw-r--r--usr.sbin/ctm/ctm_dequeue/Makefile2
-rw-r--r--usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c210
-rw-r--r--usr.sbin/ctm/ctm_rmail/Makefile4
-rw-r--r--usr.sbin/ctm/ctm_rmail/ctm_rmail.1153
-rw-r--r--usr.sbin/ctm/ctm_rmail/ctm_rmail.c5
-rw-r--r--usr.sbin/ctm/ctm_rmail/error.c1
-rw-r--r--usr.sbin/ctm/ctm_rmail/error.h2
-rw-r--r--usr.sbin/ctm/ctm_rmail/options.h1
-rw-r--r--usr.sbin/ctm/ctm_scan/Makefile16
-rw-r--r--usr.sbin/ctm/ctm_scan/ctm_scan.c187
-rw-r--r--usr.sbin/ctm/ctm_smail/Makefile2
-rw-r--r--usr.sbin/ctm/ctm_smail/ctm_smail.c349
-rw-r--r--usr.sbin/ctm/mkCTM/Makefile2
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur9
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.gnats8
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.ports-cur7
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.smp-cur7
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.src-cur9
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.src-special9
-rw-r--r--usr.sbin/ctm/mkCTM/dequeue6
-rw-r--r--usr.sbin/ctm/mkCTM/mkCTM248
-rw-r--r--usr.sbin/ctm/mkCTM/mkctm.c310
35 files changed, 1321 insertions, 1004 deletions
diff --git a/usr.sbin/ctm/Makefile b/usr.sbin/ctm/Makefile
index bf201528064..1b933985d17 100644
--- a/usr.sbin/ctm/Makefile
+++ b/usr.sbin/ctm/Makefile
@@ -1,5 +1,5 @@
-# $OpenBSD: Makefile,v 1.2 1997/09/21 11:43:34 deraadt Exp $
+# $OpenBSD: Makefile,v 1.3 1999/07/13 23:02:03 deraadt Exp $
-SUBDIR= ctm ctm_scan ctm_rmail ctm_smail ctm_dequeue
+SUBDIR= ctm ctm_rmail ctm_smail ctm_dequeue
.include <bsd.subdir.mk>
diff --git a/usr.sbin/ctm/README b/usr.sbin/ctm/README
index 47f87756d55..70c0ee11e50 100644
--- a/usr.sbin/ctm/README
+++ b/usr.sbin/ctm/README
@@ -5,7 +5,7 @@
# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
# ----------------------------------------------------------------------------
#
-# $Id: README,v 1.1 1996/10/30 17:32:57 graichen Exp $
+# $Id: README,v 1.2 1999/07/13 23:02:03 deraadt Exp $
#
What will I not find in this file ?
@@ -21,7 +21,7 @@ CTM is now meant to be the definitive way to make and apply a delta between
two versions of a directory tree.
There are two parts to this, making the delta and applying it. These are two
entirely different things. CTM concentrates the computation-burden on the
-generation og the deltas, as a delta very often is applied more times than
+generation of the deltas, as a delta very often is applied more times than
it is made. Second CTM tries to make the minimal size delta.
Why not use diff/patch ?
@@ -55,7 +55,7 @@ You pass it to the 'ctm' command. You can pass a CTM-delta on stdin, or
you can give the filename as an argument. If you do the latter, you make
life a lot easier for your self, since the program can accept gzip'ed files
and since it will not have to make a temporary copy of your file. You can
-specify multiple deltas at one time, they will be proccessed one at a time.
+specify multiple deltas at one time, they will be processed one at a time.
The ctm command runs in a number of passes. It will process the entire
input file in each pass, before commencing with the next pass.
diff --git a/usr.sbin/ctm/ctm/Makefile b/usr.sbin/ctm/ctm/Makefile
index 4cde30a3ba7..c2efdda4a81 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.1 1996/10/30 17:32:57 graichen Exp $
+# $Id: Makefile,v 1.2 1999/07/13 23:02:05 deraadt 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
MAN= ctm.1 ctm.5
CFLAGS+= -Wall
diff --git a/usr.sbin/ctm/ctm/ctm.1 b/usr.sbin/ctm/ctm/ctm.1
index 9a59c3b3fc0..edcfeb001d1 100644
--- a/usr.sbin/ctm/ctm/ctm.1
+++ b/usr.sbin/ctm/ctm/ctm.1
@@ -10,37 +10,39 @@
.\"
.\" CTM and ctm(1) by <phk@login.dknet.dk>
.\"
-.\" $Id: ctm.1,v 1.8 1999/07/07 10:50:11 aaron Exp $
+.\" $Id: ctm.1,v 1.9 1999/07/13 23:02:05 deraadt Exp $
.\"
-.Dd March 25, 1995
-.Dt CTM 1
+.Dd Mar 25, 1995
.Os
+.Dt CTM 1
.Sh NAME
.Nm ctm
.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 Ar ...
+.Op Fl x Ar exclude-regex
+.Ar
.Sh DESCRIPTION
.Nm
was originally
.Dq Cvs Through eMail ,
-but now it seems more fitting to call it
+but now instead it seems more fitting to call it
.Dq Current Through eMail .
.Pp
.Nm
is now meant to be the definitive way to make and apply a delta between
two versions of a directory tree.
-.Pp
-There are two parts to this: making the delta and applying it. These are two
-entirely different things. The
-.Nm
-command is only used to apply deltas.
-.Pp
+
+There are two parts to this, making the delta and applying it. These are two
+entirely different things.
+
.Ss Usage
To apply a CTM delta, you pass it to the
.Nm
@@ -48,35 +50,63 @@ command. You can pass a CTM delta on stdin, or you can give the
filename as an argument. If you do the latter, you make life a lot
easier for yourself, since the program can accept gzip'ed files and
since it will not have to make a temporary copy of your file. You can
-specify multiple deltas at one time, they will be proccessed one at a
-time. Deltas that have already been applied will be ignored.
-.Pp
+specify multiple deltas at one time, they will be processed one at a
+time. Deltas that are already applied will be ignored.
+
The
.Nm
-command runs in three passes. It will process the entire
+command runs in a number of passes. It will process the entire
input file in each pass, before commencing with the next pass.
-.Pp
-Before working on the file
-.Ar file ,
+
+Before working on a file
+.Ar name
.Nm
first checks for the existence of the file
-.Ar file.ctm .
+.Ar name.ctm .
If this file exists,
.Nm
works on it instead.
.Pp
-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
-will never be able to do anything with the file, so it will simply
-reject it.
-.Pp
+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 exist and by checking the MD5 checksums of files.
-.Pp
-Pass 3 will actually apply the delta.
-.Pp
+
+If a
+.Ar backup-file
+had been specified using the
+.Fl B
+option, all files that would be modified by this
+.Nm
+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
+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
will extract the file hierarchy below its working directory. Absolute
filenames or filenames containing references through
@@ -86,33 +116,107 @@ or
are explicitly prohibited as a security measure.
.Pp
.Ss Options
-.Bl -tag -width indent
+.Bl -tag -width indent -compact
+
.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 P
-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 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 .
+
.It Fl u
-Set the modification time of created and modified files to the CTM delta's
+Set the modification time of created and modified files to the CTM delta
creation time.
+
.It Fl v
Tell us more.
+
.It Fl V Ar level
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
.Ev TMPDIR,
@@ -128,27 +232,43 @@ The same effect may be achieved with the
flag.
.Sh FILES
.Pa .ctm_status
-contains the sequence number of the last CTM delta applied; changing
+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
-cd ~cvs
-/usr/sbin/ctm ~ctm/cvs-*
+.Bd -literal -offset indent
+.Ic cd ~cvs
+.Ic /usr/sbin/ctm ~ctm/cvs-*
+
+.Ed
+To extract and patch all sources under `lib'
+.Bd -literal -offset indent
+.Ic cd ~/lib-srcs
+.Ic /usr/sbin/ctm -e '^lib' ~ctm/src-cur*
.Ed
.Sh DIAGNOSTICS
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
.Xr ctm_rmail 1 ,
.Xr ctm 5
.Sh HISTORY
-Initial trials ran during 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
.Nm
diff --git a/usr.sbin/ctm/ctm/ctm.5 b/usr.sbin/ctm/ctm/ctm.5
index cda3753f52e..6c249dabc86 100644
--- a/usr.sbin/ctm/ctm/ctm.5
+++ b/usr.sbin/ctm/ctm/ctm.5
@@ -10,17 +10,17 @@
.\"
.\" CTM and ctm(1) by <phk@login.dknet.dk>
.\"
-.\" $Id: ctm.5,v 1.5 1999/07/07 10:50:11 aaron Exp $
+.\" $Id: ctm.5,v 1.6 1999/07/13 23:02:05 deraadt Exp $
.\"
.Dd March 25, 1995
-.Dt CTM 5
.Os
+.Dt CTM 5
.Sh NAME
.Nm ctm
.Nd source code mirror system
.Sh DESCRIPTION
The
-.Nm ctm
+.Nm
transfers data in a specific file format, called a CTM delta.
.Pp
CTM deltas consist of control lines and data chunks. Each control
@@ -168,7 +168,7 @@ CTM_END 74ddd298d76215ae45a077a4b6a74e9c
.Xr ctm_rmail 1 ,
.Xr ed 1
.Sh HISTORY
-Initial trials ran during the FreeBSD 1.1.5, and many bugs and
+Initial trials ran during the work on FreeBSD 1.1.5, and many bugs and
methods were hashed out.
The CTM system has been made publically available in FreeBSD 2.1.
.Sh AUTHORS
diff --git a/usr.sbin/ctm/ctm/ctm.c b/usr.sbin/ctm/ctm/ctm.c
index 03269237288..c6f822e17ec 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.3 1998/11/23 04:35:25 millert Exp $
+ * $Id: ctm.c,v 1.4 1999/07/13 23:02:05 deraadt 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,51 +48,94 @@ 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)))) {
+ warnx("out of memory for expressions: \"%s\"", 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));
+ warnx("regular expression: \"%s\"", 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);
+ warnx("option '%c' requires an argument",optopt);
stat++;
break;
case '?':
- fprintf(stderr,"Option '%c' not supported.\n",optopt);
+ warnx("option '%c' not supported",optopt);
stat++;
break;
default:
- fprintf(stderr,"Option '%c' not yet implemented.\n",optopt);
+ warnx("option '%c' not yet implemented",optopt);
break;
}
}
if(stat) {
- fprintf(stderr,"%d errors during option processing\n",stat);
+ warnx("%d errors during option processing",stat);
return Exit_Pilot;
}
stat = Exit_Done;
@@ -110,26 +157,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)
+ warnx("warning: %s not found", 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)
- fprintf(stderr,"Exit(%d)\n",stat);
+ if(Verbose > 0)
+ warnx("exit(%d)",stat);
+
+ if (FilterList)
+ for (nfilter = FilterList; nfilter; ) {
+ struct CTM_Filter *tmp = nfilter->Next;
+ Free(nfilter);
+ nfilter = tmp;
+ }
return stat;
}
@@ -148,13 +206,13 @@ Proc(char *filename, unsigned applied)
strcpy(p,"gunzip < ");
strcat(p,filename);
f = popen(p,"r");
- if(!f) { perror(p); return Exit_Garbage; }
+ if(!f) { warn("%s", p); return Exit_Garbage; }
} else {
p = 0;
f = fopen(filename,"r");
}
if(!f) {
- perror(filename);
+ warn("%s", filename);
return Exit_Garbage;
}
@@ -168,15 +226,15 @@ Proc(char *filename, unsigned applied)
if(!p && -1 == fseek(f,0,SEEK_END)) {
char *fn;
FILE *f2;
- int fd;
+ int fd, i;
if (asprintf(&fn, "%s/CTMclient.XXXXXXXX", TmpDir) == -1) {
- fprintf(stderr, "Cannot allocate memory\n");
+ warnx("Cannot allocate memory\n");
fclose(f);
return Exit_Broke;
}
if ((fd = mkstemp(fn)) == -1 || (f2 = fdopen(fd, "w+")) == NULL) {
- perror(fn);
+ warn("%s", fn);
free(fn);
if (fd != -1)
close(fd);
@@ -184,7 +242,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);
free(fn);
while(EOF != (i=getc(f)))
if(EOF == putc(i,f2)) {
@@ -201,12 +260,17 @@ 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 {
pclose(f);
f = popen(p,"r");
- if(!f) { perror(p); return Exit_Broke; }
+ if(!f) { warn("%s", p); return Exit_Broke; }
}
i=Pass2(f);
@@ -216,7 +280,7 @@ Proc(char *filename, unsigned applied)
} else {
pclose(f);
f = popen(p,"r");
- if(!f) { perror(p); return Exit_Broke; }
+ if(!f) { warn("%s", p); return Exit_Broke; }
}
if(i) {
@@ -225,10 +289,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) { warn("%s", p); return Exit_Broke; }
+ }
+ }
i=Pass3(f);
@@ -241,6 +320,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 b1ffc9db2c3..f1ebad03a9b 100644
--- a/usr.sbin/ctm/ctm/ctm.h
+++ b/usr.sbin/ctm/ctm/ctm.h
@@ -6,18 +6,20 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
- * $Id: ctm.h,v 1.1 1996/10/30 17:32:58 graichen Exp $
+ * $Id: ctm.h,v 1.2 1999/07/13 23:02:05 deraadt Exp $
*
*/
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <md5.h>
-#include <ctype.h>
#include <string.h>
-#include <errno.h>
#include <time.h>
+#include <unistd.h>
+#include <md5.h>
+#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
@@ -28,6 +30,7 @@
#define SUBSUFF ".ctm"
#define TMPSUFF ".ctmtmp"
+#define TARCMD "tar -rf %s -T -"
/* The fields... */
#define CTM_F_MASK 0xff
@@ -51,12 +54,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 +86,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 +120,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 +136,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 +158,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_ed.c b/usr.sbin/ctm/ctm/ctm_ed.c
index f6ec9e93717..cbe20a91c40 100644
--- a/usr.sbin/ctm/ctm/ctm_ed.c
+++ b/usr.sbin/ctm/ctm/ctm_ed.c
@@ -6,7 +6,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
- * $Id: ctm_ed.c,v 1.1 1996/10/30 17:32:58 graichen Exp $
+ * $Id: ctm_ed.c,v 1.2 1999/07/13 23:02:05 deraadt Exp $
*
*/
@@ -21,13 +21,13 @@ ctm_edit(u_char *script, int length, char *filein, char *fileout)
fi = fopen(filein,"r");
if(!fi) {
- perror(filein);
+ warn("%s", filein);
return 8;
}
fo = fopen(fileout,"w");
if(!fo) {
- perror(fileout);
+ warn("%s", fileout);
fclose(fi);
return 4;
}
@@ -96,17 +96,17 @@ ctm_edit(u_char *script, int length, char *filein, char *fileout)
bye:
if(fi) {
if(fclose(fi) != 0) {
- perror(filein);
+ warn("%s", filein);
ret = 1;
}
}
if(fo) {
if(fflush(fo) != 0) {
- perror(fileout);
+ warn("%s", fileout);
ret = 1;
}
if(fclose(fo) != 0) {
- perror(fileout);
+ warn("%s", fileout);
ret = 1;
}
}
diff --git a/usr.sbin/ctm/ctm/ctm_pass1.c b/usr.sbin/ctm/ctm/ctm_pass1.c
index 880df5698bf..526706ddb63 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.1 1996/10/30 17:32:58 graichen Exp $
+ * $Id: ctm_pass1.c,v 1.2 1999/07/13 23:02:05 deraadt 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", &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 @@ 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 3ca7beaf754..04d56a59bd1 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.1 1996/10/30 17:32:58 graichen Exp $
+ * $Id: ctm_pass2.c,v 1.2 1999/07/13 23:02:05 deraadt 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)) {
+ warn("%s", name);
+ pclose(ed);
+ WRONG
+ }
+ fprintf(ed,"w %s\n",p);
+ if (pclose(ed)) {
+ warn("%s", 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 52def7dc77b..bfcd5a750b5 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.2 1998/11/22 22:50:35 deraadt Exp $
+ * $Id: ctm_pass3.c,v 1.3 1999/07/13 23:02:05 deraadt Exp $
*
*/
@@ -22,7 +22,7 @@ settime(const char *name, const struct timeval *times)
{
if (SetTime)
if (utimes(name,times)) {
- fprintf(stderr, " utimes(): %s: %s\n", name, strerror(errno));
+ warn("utimes(): %s", name);
return -1;
}
return 0;
@@ -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);
@@ -154,15 +155,35 @@ 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) {
- perror(name);
+ warn("%s", name);
WRONG
}
if(cnt != write(i,trash,cnt)) {
- perror(name);
+ warn("%s", name);
WRONG
}
close(i);
@@ -181,13 +202,13 @@ Pass3(FILE *fd)
}
fprintf(ed,"e %s\n",name);
if(cnt != fwrite(trash,1,cnt,ed)) {
- perror(name);
+ warn("%s", name);
pclose(ed);
WRONG
}
fprintf(ed,"w %s\n",name);
if(pclose(ed)) {
- perror("ed");
+ warn("ed");
WRONG
}
if(strcmp(md5,MD5File(name,md5_1))) {
@@ -207,12 +228,13 @@ Pass3(FILE *fd)
sp->Key,name,i);
WRONG
}
- rename(buf,name);
- if(strcmp(md5,MD5File(name,md5_1))) {
+ if(strcmp(md5,MD5File(buf,md5_1))) {
fprintf(stderr," %s %s Edit failed MD5 check.\n",
sp->Key,name);
WRONG
}
+ if (rename(buf,name) == -1)
+ WRONG
if (settime(name,times)) WRONG
continue;
}
@@ -229,7 +251,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
@@ -241,8 +267,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 00000000000..2c7600b337f
--- /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: ctm_passb.c,v 1.1 1999/07/13 23:02:05 deraadt Exp $
+ *
+ */
+
+#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) { warn("%s", 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)) {
+ warn("%s", 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 39de06ef940..845b7400ef3 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.1 1996/10/30 17:32:58 graichen Exp $
+ * $Id: ctm_syntax.c,v 1.2 1999/07/13 23:02:05 deraadt 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} };
diff --git a/usr.sbin/ctm/ctm_dequeue/Makefile b/usr.sbin/ctm/ctm_dequeue/Makefile
index 543e77e3e96..d95a297b8a8 100644
--- a/usr.sbin/ctm/ctm_dequeue/Makefile
+++ b/usr.sbin/ctm/ctm_dequeue/Makefile
@@ -1,3 +1,5 @@
+# $OpenBSD: Makefile,v 1.2 1999/07/13 23:02:05 deraadt Exp $
+
PROG= ctm_dequeue
SRCS= ctm_dequeue.c error.c
NOMAN= yes
diff --git a/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c b/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
index 45e9c8358a3..bb09a56b9a4 100644
--- a/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
+++ b/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
@@ -26,16 +26,16 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ctm_dequeue.c,v 1.3 1998/06/23 22:40:33 millert Exp $
+ * $Id: ctm_dequeue.c,v 1.4 1999/07/13 23:02:05 deraadt Exp $
*/
-/*
- * Change this if you want to alter how many files it sends out by
- * default
+/*
+ * ctm_dequeue: Dequeue queued delta pieces and mail them.
+ *
+ * The pieces have already been packaged up as mail messages by ctm_smail,
+ * and will be simply passed to sendmail in alphabetical order.
*/
-#define DEFAULT_NUM 2
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,16 +43,18 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <fts.h>
-#include <sys/mman.h>
+#include <limits.h>
#include <errno.h>
#include <paths.h>
#include "error.h"
#include "options.h"
+#define DEFAULT_NUM 1 /* Default number of pieces mailed per run. */
+
int fts_sort(const FTSENT **, const FTSENT **);
-FILE *open_sendmail(void);
-int close_sendmail(FILE *fp);
+int run_sendmail(int ifd);
int
main(int argc, char **argv)
@@ -60,174 +62,148 @@ main(int argc, char **argv)
char *log_file = NULL;
char *queue_dir = NULL;
char *list[2];
- char *buffer, *filename;
- int num_to_send = DEFAULT_NUM, piece, fp, len;
+ int num_to_send = DEFAULT_NUM, chunk;
+ int fd;
FTS *fts;
FTSENT *ftsent;
- FILE *sfp;
+ int piece, npieces;
+ char filename[PATH_MAX];
err_prog_name(argv[0]);
OPTIONS("[-l log] [-n num] queuedir")
NUMBER('n', num_to_send)
STRING('l', log_file)
- ENDOPTS;
+ ENDOPTS
if (argc != 2)
usage();
+ if (log_file)
+ err_set_log(log_file);
+
queue_dir = argv[1];
list[0] = queue_dir;
list[1] = NULL;
- fts = fts_open(list, FTS_PHYSICAL, fts_sort);
+ fts = fts_open(list, FTS_PHYSICAL|FTS_COMFOLLOW, fts_sort);
if (fts == NULL)
{
err("fts failed on `%s'", queue_dir);
exit(1);
}
- (void) fts_read(fts);
-
- ftsent = fts_children(fts, 0);
- if (ftsent == NULL)
+ ftsent = fts_read(fts);
+ if (ftsent == NULL || ftsent->fts_info != FTS_D)
{
- err("ftschildren failed");
+ err("not a directory: %s", queue_dir);
exit(1);
}
- /* assumption :-( */
- len = strlen(queue_dir) + 40;
- filename = malloc(len);
- if (filename == NULL)
+ ftsent = fts_children(fts, 0);
+ if (ftsent == NULL && errno)
{
- err("malloc failed");
+ err("*ftschildren failed");
exit(1);
}
- for (piece = 0; piece < num_to_send ; piece++)
+ for (chunk = 1; ftsent != NULL; ftsent = ftsent->fts_link)
{
- /* Skip non-files and files we should ignore (ones starting with `.') */
-
-#define ISFILE ((ftsent->fts_info & FTS_F) == FTS_F)
-#define IGNORE (ftsent->fts_name[0] == '.')
-#define HASNEXT (ftsent->fts_link != NULL)
-
- while(((!ISFILE) || (IGNORE)) && (HASNEXT))
- ftsent = ftsent->fts_link;
-
- if ((!ISFILE) || (IGNORE))
+ /*
+ * Skip non-files and ctm_smail tmp files (ones starting with `.')
+ */
+ if (ftsent->fts_info != FTS_F || ftsent->fts_name[0] == '.')
+ continue;
+
+ sprintf(filename, "%s/%s", queue_dir, ftsent->fts_name);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
{
- err("No more chunks to mail");
- exit(0);
- }
-
-#undef ISFILE
-#undef IGNORE
-#undef HASNEXT
-
- if (snprintf(filename, len, "%s/%s", queue_dir, ftsent->fts_name) >= len)
- err("snprintf(filename) longer than buffer");
-
- fp = open(filename, O_RDONLY, 0);
- if (fp < 0)
- {
- err("open(`%s') failed, errno = %d", filename, errno);
+ err("*open: %s", filename);
exit(1);
}
- buffer = mmap(0, ftsent->fts_statp->st_size, PROT_READ, MAP_PRIVATE, fp, 0);
- if (((long) buffer) <= 0)
- {
- err("mmap failed, errno = %d", errno);
+ if (run_sendmail(fd))
exit(1);
- }
- sfp = open_sendmail();
- if (sfp == NULL)
- exit(1);
+ close(fd);
- if (fwrite(buffer, ftsent->fts_statp->st_size, 1, sfp) < 1)
- {
- err("fwrite failed: errno = %d", errno);
- close_sendmail(sfp);
- exit(1);
- }
-
- if (!close_sendmail(sfp))
- exit(1);
-
- munmap(buffer, ftsent->fts_statp->st_size);
- close(fp);
-
if (unlink(filename) < 0)
{
- err("unlink of `%s' failed", filename);
+ err("*unlink: %s", filename);
exit(1);
}
- err("sent file `%s'", ftsent->fts_name);
-
- if (ftsent->fts_link != NULL)
- ftsent = ftsent->fts_link;
- else
+ /*
+ * Deduce the delta, piece number, and number of pieces from
+ * the name of the file in the queue. Ideally, we should be
+ * able to get the mail alias name too.
+ *
+ * NOTE: This depends intimately on the queue name used in ctm_smail.
+ */
+ npieces = atoi(&ftsent->fts_name[ftsent->fts_namelen-3]);
+ piece = atoi(&ftsent->fts_name[ftsent->fts_namelen-7]);
+ err("%.*s %d/%d sent", ftsent->fts_namelen-8, ftsent->fts_name,
+ piece, npieces);
+
+ if (chunk++ == num_to_send)
break;
}
- err("exiting normally");
+ fts_close(fts);
+
return(0);
}
int
fts_sort(const FTSENT ** a, const FTSENT ** b)
{
- int a_info, b_info;
-
- a_info = (*a)->fts_info;
- if (a_info == FTS_ERR)
- return (0);
- b_info = (*b)->fts_info;
- if (b_info == FTS_ERR)
- return (0);
+ if ((*a)->fts_info != FTS_F)
+ return(0);
+ if ((*a)->fts_info != FTS_F)
+ return(0);
- return (strcmp((*a)->fts_name, (*b)->fts_name));
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
}
/*
- * Start a pipe to sendmail. Sendmail will decode the destination
- * from the message contents.
- */
-FILE *
-open_sendmail()
-{
- FILE *fp;
- char buf[100];
-
- sprintf(buf, "%s -t", _PATH_SENDMAIL);
- if ((fp = popen(buf, "w")) == NULL)
- err("cannot start sendmail");
- return fp;
-}
-
-
-/*
- * Close a pipe to sendmail. Sendmail will then do its bit.
- * Return 1 on success, 0 on failure.
+ * Run sendmail with the given file descriptor as standard input.
+ * Sendmail will decode the destination from the message contents.
+ * Returns 0 on success, 1 on failure.
*/
int
-close_sendmail(FILE *fp)
+run_sendmail(int ifd)
{
+ pid_t child, pid;
int status;
-
- fflush(fp);
- if (ferror(fp))
+
+ switch (child = fork())
{
- err("error writing to sendmail");
- return 0;
+ case -1:
+ err("*fork");
+ return(1);
+
+ case 0: /* Child */
+ dup2(ifd, 0);
+ execl(_PATH_SENDMAIL, _PATH_SENDMAIL, "-odq", "-t", NULL);
+ err("*exec: %s", _PATH_SENDMAIL);
+ _exit(1);
+
+ default: /* Parent */
+ while ((pid = wait(&status)) != child)
+ {
+ if (pid == -1 && errno != EINTR)
+ {
+ err("*wait");
+ return(1);
+ }
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ {
+ err("sendmail failed");
+ return(1);
+ }
}
-
- if ((status = pclose(fp)) != 0)
- err("sendmail failed with status %d", status);
-
- return (status == 0);
+
+ return(0);
}
diff --git a/usr.sbin/ctm/ctm_rmail/Makefile b/usr.sbin/ctm/ctm_rmail/Makefile
index cb672f2c17c..1b33309e1ec 100644
--- a/usr.sbin/ctm/ctm_rmail/Makefile
+++ b/usr.sbin/ctm/ctm_rmail/Makefile
@@ -1,6 +1,8 @@
+# $OpenBSD: Makefile,v 1.2 1999/07/13 23:02:05 deraadt Exp $
+
PROG= ctm_rmail
SRCS= ctm_rmail.c error.c
CFLAGS+= -Wall
-MLINKS+= ctm_rmail.1 ctm_smail.1
+MLINKS+= ctm_rmail.1 ctm_smail.1 ctm_dequeue.1
.include <bsd.prog.mk>
diff --git a/usr.sbin/ctm/ctm_rmail/ctm_rmail.1 b/usr.sbin/ctm/ctm_rmail/ctm_rmail.1
index d37008d2319..a2dcf7b94e0 100644
--- a/usr.sbin/ctm/ctm_rmail/ctm_rmail.1
+++ b/usr.sbin/ctm/ctm_rmail/ctm_rmail.1
@@ -9,7 +9,9 @@
.Dt CTM_MAIL 1
.Os
.Sh NAME
-.Nm ctm_smail, ctm_rmail
+.Nm ctm_smail ,
+.Nm ctm_dequeue ,
+.Nm ctm_rmail
.Nd send and receive
.Xr ctm 1
deltas via mail
@@ -18,8 +20,13 @@ deltas via mail
.Op Fl l Ar log
.Op Fl m Ar maxmsgsize
.Op Fl c Ar maxctmsize
+.Op Fl q Ar queue-dir
.Ar ctm-delta
.Ar mail-alias
+.Nm ctm_dequeue
+.Op Fl l Ar log
+.Op Fl n Ar numchunks
+.Ar queue-dir
.Nm ctm_rmail
.Op Fl Dfuv
.Op Fl l Ar log
@@ -31,7 +38,8 @@ deltas via mail
In conjunction with the
.Xr ctm 1
command,
-.Nm ctm_smail
+.Nm ctm_smail ,
+.Nm ctm_dequeue
and
.Nm ctm_rmail
are used to distribute changes to a source tree via email.
@@ -39,7 +47,8 @@ are used to distribute changes to a source tree via email.
is given a compressed
.Xr ctm
delta, and a mailing list to send it to. It splits the delta into manageable
-pieces, encodes them as mail messages and sends them to the mailing list.
+pieces, encodes them as mail messages and sends them to the mailing list
+(optionally queued to spread the mail load).
Each recipient uses
.Nm ctm_rmail
(either manually or automatically) to decode and reassemble the delta, and
@@ -73,6 +82,13 @@ limit will cause an apology mail message to be sent to the mailing list.
This is to prevent massive changes overwhelming users' mail boxes. Note that
this is the size before encoding. Encoding causes a 4/3 size increase before
mail headers are added. If not specified, there is no limit.
+.It Fl q Ar queue-dir
+Instead of mailing the delta pieces now, store them in the given directory
+to be mailed later using
+.Nm ctm_dequeue .
+This feature allows the mailing of large deltas to be spread out over
+hours or even days to limit the impact on recipients with limited network
+bandwidth or small mail spool areas.
.El
.Pp
.Ar ctm-delta
@@ -83,6 +99,42 @@ The mail messages are sent using
.Xr sendmail 8 .
.Pp
Command line arguments for
+.Nm ctm_dequeue :
+.Bl -tag -width indent
+.It Fl l Ar log
+Instead of appearing on
+.Em stderr ,
+error diagnostics and informational messages (other than command line errors)
+are time stamped and written to the file
+.Em log .
+.It Fl n Ar numchunks
+Limit the number of mail messages that
+.Nm ctm_dequeue
+will send per run. By default,
+.Nm ctm_dequeue
+will send one mail message per run.
+.El
+.Pp
+.Ar queuedir
+is the directory containing the mail messages stored by
+.Nm ctm_smail .
+Up to
+.Ar numchunks
+mail messages will be sent in each run. The recipient mailing list is already
+encoded in the queued files.
+.Pp
+It is safe to run
+.Nm ctm_dequeue
+while
+.Nm ctm_smail
+is adding entries to the queue, or even to run
+.Nm ctm_smail
+multiple times concurrently, but a separate queue directory should be used
+for each tree being distributed. This is because entries are served in
+alphabetical order, and one tree will be unfairly serviced before any others,
+based on the delta names, not delta creation times.
+.Pp
+Command line arguments for
.Nm ctm_rmail :
.Bl -tag -width indent
.It Fl l Ar log
@@ -121,10 +173,9 @@ does not exist).
.It Fl D
Delete deltas after successful application by
.Xr ctm .
-It is probably a good idea to avoid this flag (and keep all the deltas)
-as one of the possible future enhancements to
+It is probably a good idea to avoid this flag (and keep all the deltas) as
.Xr ctm
-is the ability to recover small groups of files from a full set of deltas.
+has the ability to recover small groups of files from a full set of deltas.
.It Fl f
Fork and execute in the background while applying deltas with
.Xr ctm .
@@ -161,7 +212,11 @@ Pass the
flag to the
.Xr ctm
command when applying the complete deltas, causing a more informative
-output. Note that you need to make your own arrangements to capture it.
+output. All
+.Xr ctm
+output appears in the
+.Nm ctm_rmail
+log file.
.El
.Pp
The file arguments (or
@@ -196,7 +251,7 @@ CTM_MAIL END 61065
The subject of the message always begins with
.Dq ctm-mail
followed by the name of the delta, which piece this is, and how many total
-pieces there are. The data is bracketed by
+pieces there are. The data are bracketed by
.Dq CTM_MAIL BEGIN
and
.Dq CTM_MAIL END
@@ -225,7 +280,7 @@ as
.Em src-guys ,
limiting the mail size to roughly 60000 bytes, you could use:
.Bd -literal -offset indent
-ctm_smail -m 60000 /wherever/it/is/src-cur.0032.gz src-guys
+.Ic ctm_smail -m 60000 /wherever/it/is/src-cur.0032.gz src-guys
.Ed
.Pp
To decode every
@@ -233,7 +288,7 @@ To decode every
message in your mailbox, assemble them into complete deltas, then apply
any deltas built or lying around, you could use:
.Bd -literal -offset indent
-ctm_rmail -p ~/pieces -d ~/deltas -b /usr/ctm-src-cur $MAIL
+.Ic ctm_rmail -p ~/pieces -d ~/deltas -b /usr/ctm-src-cur $MAIL
.Ed
.Pp
(Note that no messages are deleted by
@@ -265,11 +320,50 @@ or wherever else you like.
.Pp
To apply all the deltas collected, and delete those applied, you could use:
.Bd -literal -offset indent
-ctm_rmail -D -d /ctm/deltas -b /ctm/src-cur -l /ctm/apply.log
+.Ic ctm_rmail -D -d /ctm/deltas -b /ctm/src-cur -l /ctm/apply.log
+.Ed
+.Pp
+For maximum flexibility, consider this excerpt from a
+.Xr procmail
+script:
+.Bd -literal -offset indent
+PATH=$HOME/bin:$PATH
+
+:0 w
+* ^Subject: ctm-mail cvs-cur
+| ctm_incoming
+.Ed
+.Pp
+together with the
+shell script
+.Pa ~/bin/ctm_incoming :
+.Bd -literal -offset indent
+#! /bin/sh
+PATH="$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
+export PATH
+
+cd $HOME/ctm && ctm_rmail -f -p pieces -d deltas -l log -b /ctm
.Ed
+.Pp
+which will deposit all
+.Xr ctm
+deltas in
+.Pa ~/ctm/deltas ,
+apply them to the tree in
+.Pa /ctm ,
+and drop any failures into your regular mail box.
+Note the
+.Ev PATH
+manipulation in
+.Pa ctm_incoming
+which allows
+.Nm ctm_rmail
+to execute
+.Xr ctm
+on the (non-OpenBSD) machine that this example was taken from.
.Sh SECURITY
If you automatically take your mail and pass it to a file tree patcher, you
-might think you are handing the keys to your system to the hackers! Happily,
+might think you are handing the keys to your system to the crackers! Happily,
the window for mischief is quite small.
.Nm ctm_rmail
is careful to write only to the directories given to it (by not believing any
@@ -289,7 +383,8 @@ source recipients would be able to generate a fake delta, and they're such
nice folk that they wouldn't even think of it! :-)
.Pp
Even this possibility could be removed by using cryptographic signatures.
-A possible future enhancement would be to use PGP
+A possible future enhancement would be to use
+.Nm PGP
to provide a secure wrapper.
.\" This next request is for sections 1, 6, 7 & 8 only
.Sh ENVIRONMENT
@@ -300,19 +395,22 @@ and
must be in your
.Ev PATH .
.Sh FILES
-.Bl -tag -width BASEDIR/.ctm_status -compact
+.Bl -tag -width indent
+.It Pa QUEUEDIR/*
+Pieces of deltas encoded as mail messages waiting to be sent to the
+mailing list.
.It Pa PIECEDIR/*
-pieces of deltas waiting for the rest
+Pieces of deltas waiting for the rest to arrive.
.It Pa DELTADIR/*
-completed deltas
+Completed deltas.
.It Pa BASEDIR/.ctm_status
-file containing name and number of the next delta to be applied to this
-source tree
-.El
+File containing the name and number of the next delta to be applied to this
+source tree.
.\" This next request is for sections 1, 6, 7 & 8 only
.\" (command return values (to shell) and fprintf/stderr type diagnostics)
.Sh DIAGNOSTICS
-.Nm ctm_smail
+.Nm ctm_smail ,
+.Nm ctm_dequeue
and
.Nm ctm_rmail
return exit status 0 for success, and 1 for various failures.
@@ -333,6 +431,17 @@ will report messages like:
ctm_smail: src-cur.0250.gz 1/2 sent to src-guys
.Ed
.Pp
+or, if queueing,
+.Bd -literal -offset indent
+ctm_smail: src-cur.0250.gz 1/2 queued for src-guys
+.Ed
+.Pp
+.Nm ctm_dequeue
+will report messages like:
+.Bd -literal -offset indent
+ctm_dequeue: src-cur.0250.gz 1/2 sent
+.Ed
+.Pp
.Nm ctm_rmail
will report messages like:
.Bd -literal -offset indent
@@ -366,3 +475,7 @@ turn up here too. Error messages should be self explanatory.
.Sh AUTHOR
Stephen McKay <syssgm@devetir.qld.gov.au>
.\" .Sh BUGS
+.\" Gosh! No bugs here!
+.\" This message brought to you by the Coalition for More Humour in Man Pages.
+.\"
+.\" $Id: ctm_rmail.1,v 1.5 1999/07/13 23:02:05 deraadt Exp $
diff --git a/usr.sbin/ctm/ctm_rmail/ctm_rmail.c b/usr.sbin/ctm/ctm_rmail/ctm_rmail.c
index 06897e35510..190a11de0ab 100644
--- a/usr.sbin/ctm/ctm_rmail/ctm_rmail.c
+++ b/usr.sbin/ctm/ctm_rmail/ctm_rmail.c
@@ -1,3 +1,4 @@
+/* $OpenBSD: ctm_rmail.c,v 1.7 1999/07/13 23:02:06 deraadt Exp $ */
/*
* Accept one (or more) ASCII encoded chunks that together make a compressed
* CTM delta. Decode them and reconstruct the deltas. Any completed
@@ -164,7 +165,7 @@ apply_complete()
return;
}
- i = fscanf(fp, "%19s %d %c", class, &dn, junk);
+ i = fscanf(fp, "%s %d %c", class, &dn, junk);
fclose(fp);
if (i != 2)
{
@@ -294,7 +295,7 @@ read_piece(char *input_file)
char *s;
int fd = -1;
- if (sscanf(line, "CTM_MAIL BEGIN %29s %d %d %c",
+ if (sscanf(line, "CTM_MAIL BEGIN %s %d %d %c",
delta, &pce, &npieces, junk) != 3)
continue;
diff --git a/usr.sbin/ctm/ctm_rmail/error.c b/usr.sbin/ctm/ctm_rmail/error.c
index 724b117184a..df2f96b7fcd 100644
--- a/usr.sbin/ctm/ctm_rmail/error.c
+++ b/usr.sbin/ctm/ctm_rmail/error.c
@@ -1,3 +1,4 @@
+/* $OpenBSD: error.c,v 1.2 1999/07/13 23:02:06 deraadt Exp $ */
/*
* Routines for logging error messages or other informative messages.
*
diff --git a/usr.sbin/ctm/ctm_rmail/error.h b/usr.sbin/ctm/ctm_rmail/error.h
index b8bc4521e10..95e7df45071 100644
--- a/usr.sbin/ctm/ctm_rmail/error.h
+++ b/usr.sbin/ctm/ctm_rmail/error.h
@@ -1,3 +1,5 @@
+/* $OpenBSD: error.h,v 1.2 1999/07/13 23:02:06 deraadt Exp $ */
+
extern void err_set_log(char *log_file);
extern void err_prog_name(char *name);
extern void err(char *fmt, ...);
diff --git a/usr.sbin/ctm/ctm_rmail/options.h b/usr.sbin/ctm/ctm_rmail/options.h
index 18b844cebf5..62ba8bc8da9 100644
--- a/usr.sbin/ctm/ctm_rmail/options.h
+++ b/usr.sbin/ctm/ctm_rmail/options.h
@@ -1,3 +1,4 @@
+/* $OpenBSD: options.h,v 1.2 1999/07/13 23:02:06 deraadt Exp $ */
/*
* Macros for processing command arguments.
*
diff --git a/usr.sbin/ctm/ctm_scan/Makefile b/usr.sbin/ctm/ctm_scan/Makefile
deleted file mode 100644
index a52c5d62393..00000000000
--- a/usr.sbin/ctm/ctm_scan/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# ----------------------------------------------------------------------------
-# "THE BEER-WARE LICENSE" (Revision 42):
-# <phk@login.dkuug.dk> 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. Poul-Henning Kamp
-# ----------------------------------------------------------------------------
-#
-# $Id: Makefile,v 1.1 1996/10/30 17:32:59 graichen Exp $
-#
-PROG= ctm_scan
-NOMAN= 1
-CFLAGS+= -Wall
-
-.include "../../Makefile.inc"
-.include <bsd.prog.mk>
diff --git a/usr.sbin/ctm/ctm_scan/ctm_scan.c b/usr.sbin/ctm/ctm_scan/ctm_scan.c
deleted file mode 100644
index 323880b1d75..00000000000
--- a/usr.sbin/ctm/ctm_scan/ctm_scan.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@login.dkuug.dk> 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. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- *
- * $Id: ctm_scan.c,v 1.1 1996/10/30 17:32:59 graichen Exp $
- *
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <dirent.h>
-#include <md5.h>
-
-int barf[256];
-int CheckMode = 0;
-
-int
-pstrcmp(const void *pp, const void *qq)
-{
- return strcmp(*(char **)pp,*(char **)qq);
-}
-
-int
-Do(char *path)
-{
- DIR *d;
- struct dirent *de;
- struct stat st;
- int ret=0;
- u_char buf[BUFSIZ];
- u_char data[BUFSIZ],*q;
- int bufp;
- MD5_CTX ctx;
- int fd,i,j,k,l,npde,nde=0;
- char **pde, md5[33];
-
- npde = 1;
- pde = malloc(sizeof *pde * (npde+1));
- d = opendir(path);
- if(!d) { perror(path); return 2; }
- if(!strcmp(path,".")) {
- *buf = 0;
- } else {
- strcpy(buf,path);
- if(buf[strlen(buf)-1] != '/')
- strcat(buf,"/");
- }
- bufp = strlen(buf);
- while((de=readdir(d))) {
- if(!strcmp(de->d_name,".")) continue;
- if(!strcmp(de->d_name,"..")) continue;
- if(nde >= npde) {
- npde *= 2;
- pde = realloc(pde,sizeof *pde * (npde+1));
- }
- strcpy(buf+bufp,de->d_name);
- if(stat(buf,&st)) {
- ret |= 1;
- continue;
- }
- pde[nde] = malloc(strlen(buf+bufp)+1);
- strcpy(pde[nde++],buf+bufp);
- }
- closedir(d);
- if(!nde) return 0;
- qsort(pde,nde,sizeof *pde, pstrcmp);
- for(k=0;k<nde;k++) {
- strcpy(buf+bufp,pde[k]);
- free(pde[k]);
- if(stat(buf,&st)) {
- ret |= 1;
- continue;
- }
- switch(st.st_mode & S_IFMT) {
- case S_IFDIR:
- if(!CheckMode) {
- i = printf("d %s %o %u %u - - -\n",
- buf,st.st_mode & (~S_IFMT),st.st_uid,st.st_gid);
- if(!i)
- exit(-1);
- }
- ret |= Do(buf);
- break;
- case S_IFREG:
- fd = open(buf,O_RDONLY);
- if(fd < 0) {
- ret |= 1;
- continue;
- }
- MD5Init(&ctx);
- l = 1;
- j = 0;
- while(0 < (i = read(fd,data,sizeof data))) {
- l = (data[i-1] == '\n');
- if(!CheckMode)
- MD5Update(&ctx,data,i);
- for(q=data;i && !j;i--)
- if(barf[*q++])
- j=1;
- }
- close(fd);
- if(CheckMode) {
- if(j || !l) {
- i = printf("%s",buf);
- if(!i) exit(-1);
- if(j) printf(" Illegal characters.");
- if(!l) printf(" No final newline.");
- i = printf(".\n");
- if(!i) exit(-1);
- }
- } else {
- if(!l)
- j=2;
- i = printf("f %s %o %u %u %u %lu %s\n",
- buf,st.st_mode & (~S_IFMT),st.st_uid,st.st_gid,
- j,(u_long)st.st_size,MD5End(&ctx,md5));
- if(!i) exit(-1);
- }
- break;
- default:
- fprintf(stderr,"%s: type 0%o\n",buf, st.st_mode & S_IFMT);
- ret |= 4;
- break;
- }
- }
- free(pde);
- return ret;
-}
-
-int
-main(int argc, char **argv)
-{
- int i;
-
- /*
- * Initialize barf[], characters diff/patch will not appreciate.
- */
-
- barf[0x00] = 1;
- barf[0x7f] = 1;
- barf[0x80] = 1;
- barf[0xff] = 1;
-
- /*
- * -c is CheckMode
- */
- if (argc > 1 && !strcmp(argv[1],"-c")) {
- CheckMode=1;
- argc--;
- argv++;
- }
-
- /*
- * First argument, if any, is where to do the work.
- */
- if (argc > 1) {
- if(chdir(argv[1])) {
- perror(argv[1]);
- return 2;
- }
- argc--;
- argv++;
- }
-
- /*
- * Scan the directories recursively.
- */
- if (argc > 1) {
- while (argc > 1) {
- i = Do(argv[1]);
- argc--;
- argv++;
- if (i)
- return i;
- }
- return i;
- } else
- return Do(".");
-}
diff --git a/usr.sbin/ctm/ctm_smail/Makefile b/usr.sbin/ctm/ctm_smail/Makefile
index e9eb84680ba..422526ede49 100644
--- a/usr.sbin/ctm/ctm_smail/Makefile
+++ b/usr.sbin/ctm/ctm_smail/Makefile
@@ -1,3 +1,5 @@
+# $OpenBSD: Makefile,v 1.2 1999/07/13 23:02:06 deraadt Exp $
+
PROG= ctm_smail
SRCS= ctm_smail.c error.c
NOMAN= 1
diff --git a/usr.sbin/ctm/ctm_smail/ctm_smail.c b/usr.sbin/ctm/ctm_smail/ctm_smail.c
index c995572ae61..c213f46606f 100644
--- a/usr.sbin/ctm/ctm_smail/ctm_smail.c
+++ b/usr.sbin/ctm/ctm_smail/ctm_smail.c
@@ -1,8 +1,9 @@
/*
* Send a compressed CTM delta to a recipient mailing list by encoding it
- * in safe ASCII characters, in mailer-friendly chunks, and passing it
- * to sendmail. The encoding is almost the same as MIME BASE64, and is
- * protected by a simple checksum.
+ * in safe ASCII characters, in mailer-friendly chunks, and passing them
+ * to sendmail. Optionally, the chunks can be queued to be sent later by
+ * ctm_dequeue in controlled bursts. The encoding is almost the same as
+ * MIME BASE64, and is protected by a simple checksum.
*
* Author: Stephen McKay
*
@@ -10,7 +11,7 @@
* In return you should think about all the nice people who give away software.
* Maybe you should write some free software too.
*
- * $Id: ctm_smail.c,v 1.1 1996/10/30 17:32:59 graichen Exp $
+ * $Id: ctm_smail.c,v 1.2 1999/07/13 23:02:06 deraadt Exp $
*/
#include <stdio.h>
@@ -22,38 +23,42 @@
#include <sys/stat.h>
#include <errno.h>
#include <paths.h>
+#include <limits.h>
#include "error.h"
#include "options.h"
#define DEF_MAX_MSG 64000 /* Default maximum mail msg minus headers. */
-#define LINE_LENGTH 76 /* Chars per encode line. Divisible by 4. */
+#define LINE_LENGTH 76 /* Chars per encoded line. Divisible by 4. */
-void chop_and_send(char *delta, off_t ctm_size, long max_msg_size,
+int chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size,
+ long max_msg_size, char *mail_alias, char *queue_dir);
+int chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces,
char *mail_alias);
-void chop_and_queue(char *delta, off_t ctm_size, long max_msg_size,
- char *queue_dir, char *mail_alias);
-unsigned encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size);
+int chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces,
+ char *mail_alias, char *queue_dir);
+void clean_up_queue(char *queue_dir);
+int encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size, unsigned *sum);
void write_header(FILE *sfp, char *mail_alias, char *delta, int pce,
int npieces);
void write_trailer(FILE *sfp, unsigned sum);
-void apologise(char *delta, off_t ctm_size, long max_ctm_size,
+int apologise(char *delta, off_t ctm_size, long max_ctm_size,
char *mail_alias);
FILE *open_sendmail(void);
int close_sendmail(FILE *fp);
-int lock_queuedir(char *queue_dir);
-void free_lock(int lockf, char *queue_dir);
-void add_to_queue(char *queue_dir, char *mail_alias, char *delta, int npieces, char **tempnames);
int
main(int argc, char **argv)
{
+ int status = 0;
char *delta_file;
char *mail_alias;
long max_msg_size = DEF_MAX_MSG;
long max_ctm_size = 0;
char *log_file = NULL;
char *queue_dir = NULL;
+ char *delta;
+ FILE *dfp;
struct stat sb;
err_prog_name(argv[0]);
@@ -74,42 +79,44 @@ main(int argc, char **argv)
delta_file = argv[1];
mail_alias = argv[2];
- if (stat(delta_file, &sb) < 0)
+ if ((delta = strrchr(delta_file, '/')) == NULL)
+ delta = delta_file;
+ else
+ delta++;
+
+ if ((dfp = fopen(delta_file, "r")) == NULL || fstat(fileno(dfp), &sb) < 0)
{
- err("%s: %s", delta_file, strerror(errno));
+ err("*%s", delta_file);
exit(1);
}
if (max_ctm_size != 0 && sb.st_size > max_ctm_size)
- apologise(delta_file, sb.st_size, max_ctm_size, mail_alias);
- else if (queue_dir == NULL)
- chop_and_send(delta_file, sb.st_size, max_msg_size, mail_alias);
+ status = apologise(delta, sb.st_size, max_ctm_size, mail_alias);
else
- chop_and_queue(delta_file, sb.st_size, max_msg_size, queue_dir, mail_alias);
+ status = chop_and_send_or_queue(dfp, delta, sb.st_size, max_msg_size,
+ mail_alias, queue_dir);
- return 0;
+ fclose(dfp);
+
+ return status;
}
/*
- * Carve our CTM delta into pieces, encode them, and send them.
+ * Carve our CTM delta into pieces, encode them, and send or queue them.
+ * Returns 0 on success, and 1 on failure.
*/
-void
-chop_and_send(char *delta, off_t ctm_size, long max_msg_size, char *mail_alias)
+int
+chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size,
+ long max_msg_size, char *mail_alias, char *queue_dir)
{
int npieces;
long msg_size;
long exp_size;
- int pce;
- FILE *sfp;
- FILE *dfp;
- unsigned sum;
+ int status;
-#ifdef howmany
#undef howmany
-#endif
-
-#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+#define howmany(x,y) (((x)+((y)-1)) / (y))
/*
* Work out how many pieces we need, bearing in mind that each piece
@@ -124,137 +131,160 @@ chop_and_send(char *delta, off_t ctm_size, long max_msg_size, char *mail_alias)
#undef howmany
- if ((dfp = fopen(delta, "r")) == NULL)
+ if (queue_dir == NULL)
+ status = chop_and_send(dfp, delta, msg_size, npieces, mail_alias);
+ else
{
- err("cannot open '%s' for reading.", delta);
- exit(1);
+ status = chop_and_queue(dfp, delta, msg_size, npieces, mail_alias,
+ queue_dir);
+ if (status)
+ clean_up_queue(queue_dir);
}
+ return status;
+ }
+
+
+/*
+ * Carve our CTM delta into pieces, encode them, and send them.
+ * Returns 0 on success, and 1 on failure.
+ */
+int
+chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces,
+ char *mail_alias)
+ {
+ int pce;
+ FILE *sfp;
+ unsigned sum;
+
+ /*
+ * Send each chunk directly to sendmail as it is generated.
+ * No temporary files necessary. If things turn ugly, we just
+ * have to live with the fact the we have sent only part of
+ * the delta.
+ */
for (pce = 1; pce <= npieces; pce++)
{
- sfp = open_sendmail();
- if (sfp == NULL)
- exit(1);
+ int read_error;
+
+ if ((sfp = open_sendmail()) == NULL)
+ return 1;
+
write_header(sfp, mail_alias, delta, pce, npieces);
- sum = encode_body(sfp, dfp, msg_size);
- write_trailer(sfp, sum);
- if (!close_sendmail(sfp))
- exit(1);
+ read_error = encode_body(sfp, dfp, msg_size, &sum);
+ if (!read_error)
+ write_trailer(sfp, sum);
+
+ if (!close_sendmail(sfp) || read_error)
+ return 1;
+
err("%s %d/%d sent to %s", delta, pce, npieces, mail_alias);
}
- fclose(dfp);
+ return 0;
}
-/*
- * Carve our CTM delta into pieces, encode them, and drop them in the
- * queue dir.
- *
- * Basic algorythm:
- *
- * - for (each piece)
- * - gen. temp. file name (one which the de-queuer will ignore)
- * - record in array
- * - open temp. file
- * - encode delta (including headers) into the temp file
- * - close temp. file
- * - end
- * - lock queue directory
- * - foreach (temp. file)
- * - rename to the proper filename
- * - end
- * - unlock queue directory
- *
- * This is probably overkill, but it means that incomplete deltas
- * don't get mailed, and also reduces the window for lock races
- * between ctm_smail and the de-queueing process.
+
+/*
+ * Construct the tmp queue file name of a delta piece.
*/
+#define mk_tmp_name(fn,qd,p) \
+ sprintf((fn), "%s/.%08ld.%03d", (qd), (long)getpid(), (p))
-void
-chop_and_queue(char *delta, off_t ctm_size, long max_msg_size, char *queue_dir, char *mail_alias)
-{
- int npieces, pce, len;
- long msg_size, exp_size;
- FILE *sfp, *dfp;
- unsigned sum;
- char **tempnames, *tempnam, *sn;
+/*
+ * Construct the final queue file name of a delta piece.
+ */
+#define mk_queue_name(fn,qd,d,p,n) \
+ sprintf((fn), "%s/%s+%03d-%03d", (qd), (d), (p), (n))
-#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+/*
+ * Carve our CTM delta into pieces, encode them, and queue them.
+ * Returns 0 on success, and 1 on failure.
+ */
+int
+chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces,
+ char *mail_alias, char *queue_dir)
+ {
+ int pce;
+ FILE *qfp;
+ unsigned sum;
+ char tname[PATH_MAX];
+ char qname[PATH_MAX];
/*
- * Work out how many pieces we need, bearing in mind that each piece
- * grows by 4/3 when encoded. We count the newlines too, but ignore
- * all mail headers and piece headers. They are a "small" (almost
- * constant) per message overhead that we make the user worry about. :-)
+ * Store each piece in the queue directory, but under temporary names,
+ * so that they can be deleted without unpleasant consequences if
+ * anything goes wrong. We could easily fill up a disk, for example.
*/
- exp_size = ctm_size * 4 / 3;
- exp_size += howmany(exp_size, LINE_LENGTH);
- npieces = howmany(exp_size, max_msg_size);
- msg_size = howmany(ctm_size, npieces);
+ for (pce = 1; pce <= npieces; pce++)
+ {
+ int write_error;
-#undef howmany
+ mk_tmp_name(tname, queue_dir, pce);
+ if ((qfp = fopen(tname, "w")) == NULL)
+ {
+ err("cannot open '%s' for writing", tname);
+ return 1;
+ }
- /*
- * allocate space for the array of filenames. Try to be portable
- * by not assuming anything to do with sizeof(char *)
- */
- tempnames = malloc(npieces * sizeof(char *));
- if (tempnames == NULL)
- {
- err("malloc for tempnames failed");
- exit(1);
- }
-
- len = strlen(queue_dir) + 16;
- tempnam = malloc(len);
- if (tempnam == NULL)
- {
- err("malloc for tempnames failed");
- exit(1);
- }
-
- if ((dfp = fopen(delta, "r")) == NULL)
- {
- err("cannot open '%s' for reading.", delta);
- exit(1);
- }
+ write_header(qfp, mail_alias, delta, pce, npieces);
+ if (encode_body(qfp, dfp, msg_size, &sum))
+ return 1;
+ write_trailer(qfp, sum);
- if ((sn = strrchr(delta, '/')) == NULL)
- sn = delta;
- else
- sn++;
+ fflush(qfp);
+ write_error = ferror(qfp);
+ fclose(qfp);
+ if (write_error)
+ {
+ err("error writing '%s'", tname);
+ return 1;
+ }
- for (pce = 1; pce <= npieces; pce++)
- {
- if (snprintf(tempnam, len, "%s/.%08d-%03d", queue_dir, getpid(), pce) >= len)
- err("Whoops! tempnam isn't long enough");
+ /*
+ * Give the warm success message now, instead of all in a rush
+ * during the rename phase.
+ */
+ err("%s %d/%d queued for %s", delta, pce, npieces, mail_alias);
+ }
- tempnames[pce - 1] = strdup(tempnam);
- if (tempnames[pce - 1] == NULL)
+ /*
+ * Rename the pieces into place. If an error occurs now, we are
+ * stuffed, but there is no neat way to back out. rename() should
+ * only fail now under extreme circumstances.
+ */
+ for (pce = 1; pce <= npieces; pce++)
{
- err("strdup failed for temp. filename");
- exit(1);
+ mk_tmp_name(tname, queue_dir, pce);
+ mk_queue_name(qname, queue_dir, delta, pce, npieces);
+ if (rename(tname, qname) < 0)
+ {
+ err("*rename: '%s' to '%s'", tname, qname);
+ unlink(tname);
+ }
}
- sfp = fopen(tempnam, "w");
- if (sfp == NULL)
- exit(1);
-
- write_header(sfp, mail_alias, delta, pce, npieces);
- sum = encode_body(sfp, dfp, msg_size);
- write_trailer(sfp, sum);
-
- if (fclose(sfp) != 0)
- exit(1);
-
- err("%s %d/%d created succesfully", sn, pce, npieces);
+ return 0;
}
- add_to_queue(queue_dir, mail_alias, delta, npieces, tempnames);
- fclose(dfp);
+/*
+ * There may be temporary files cluttering up the queue directory.
+ */
+void
+clean_up_queue(char *queue_dir)
+ {
+ int pce;
+ char tname[PATH_MAX];
-}
+ err("discarding queued delta pieces");
+ for (pce = 1; ; pce++)
+ {
+ mk_tmp_name(tname, queue_dir, pce);
+ if (unlink(tname) < 0)
+ break;
+ }
+ }
/*
@@ -281,8 +311,8 @@ static char to_b64[0x40] =
* of 4 characters encodes 3 input characters. Each output character encodes
* 6 bits. Thus 64 different characters are needed in this representation.
*/
-unsigned
-encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size)
+int
+encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size, unsigned *sum)
{
unsigned short cksum = 0xffff;
unsigned char *ip;
@@ -337,16 +367,12 @@ encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size)
if (ferror(delta_fp))
{
err("error reading input file.");
- exit(1);
+ return 1;
}
- if (ferror(sm_fp))
- {
- err("error writing encoded file");
- exit(1);
- }
+ *sum = cksum;
- return cksum;
+ return 0;
}
@@ -356,18 +382,11 @@ encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size)
void
write_header(FILE *sfp, char *mail_alias, char *delta, int pce, int npieces)
{
- char *sn;
-
- if ((sn = strrchr(delta, '/')) == NULL)
- sn = delta;
- else
- sn++;
-
fprintf(sfp, "From: owner-%s\n", mail_alias);
fprintf(sfp, "To: %s\n", mail_alias);
- fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", sn, pce, npieces);
+ fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", delta, pce, npieces);
- fprintf(sfp, "CTM_MAIL BEGIN %s %d %d\n", sn, pce, npieces);
+ fprintf(sfp, "CTM_MAIL BEGIN %s %d %d\n", delta, pce, npieces);
}
@@ -383,32 +402,30 @@ write_trailer(FILE *sfp, unsigned sum)
/*
* We're terribly sorry, but the delta is too big to send.
+ * Returns 0 on success, 1 on failure.
*/
-void
+int
apologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias)
{
FILE *sfp;
- char *sn;
sfp = open_sendmail();
if (sfp == NULL)
- exit(1);
+ return 1;
- if ((sn = strrchr(delta, '/')) == NULL)
- sn = delta;
- else
- sn++;
-
- fprintf(sfp, "From: %s-owner\n", mail_alias);
+ fprintf(sfp, "From: owner-%s\n", mail_alias);
fprintf(sfp, "To: %s\n", mail_alias);
- fprintf(sfp, "Subject: ctm-notice %s\n\n", sn);
+ fprintf(sfp, "Subject: ctm-notice %s\n\n", delta);
- fprintf(sfp, "%s is %ld bytes. The limit is %ld bytes.\n\n", sn,
+ fprintf(sfp, "%s is %ld bytes. The limit is %ld bytes.\n\n", delta,
(long)ctm_size, max_ctm_size);
- fprintf(sfp, "You can retrieve this delta via ftpmail, or your good mate at the university.\n");
+ fprintf(sfp, "You can retrieve this delta via ftpmail, "
+ "or your good mate at the university.\n");
if (!close_sendmail(sfp))
- exit(1);
+ return 1;
+
+ return 0;
}
@@ -422,7 +439,7 @@ open_sendmail()
FILE *fp;
char buf[100];
- sprintf(buf, "%s -t", _PATH_SENDMAIL);
+ sprintf(buf, "%s -odq -t", _PATH_SENDMAIL);
if ((fp = popen(buf, "w")) == NULL)
err("cannot start sendmail");
return fp;
@@ -451,6 +468,8 @@ close_sendmail(FILE *fp)
return (status == 0);
}
+/* Delete below, unneeded now -hgw */
+
/*
* Lock the queuedir so we're the only guy messing about in there.
*/
diff --git a/usr.sbin/ctm/mkCTM/Makefile b/usr.sbin/ctm/mkCTM/Makefile
index 2fd32716022..389f73506d2 100644
--- a/usr.sbin/ctm/mkCTM/Makefile
+++ b/usr.sbin/ctm/mkCTM/Makefile
@@ -1,7 +1,7 @@
+# $OpenBSD: Makefile,v 1.3 1999/07/13 23:02:06 deraadt Exp $
PROG= mkctm
SRCS= mkctm.c
-LDADD= -lmd
CFLAGS+= -Wall
test: mkctm
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur b/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur
new file mode 100644
index 00000000000..fbb5bf26ce7
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur
@@ -0,0 +1,9 @@
+#!/usr/local/bin/tclsh
+
+set CTMname cvs-cur
+set CTMref /home/ncvs
+set CTMignore {^src/secure|^src/eBones|^src/kerberosIV|^CVSROOT/val-tags$|CVSROOT/\\.#}
+set CTMbogus {\\.core$|/#cvs|/\\.#}
+set CTMmail ctm-cvs-cur-fast@freebsd.org
+set CTMqueuemail ctm-cvs-cur@freebsd.org
+set CTMqueue /home/ctm/queue/ctm-cvs-cur
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.gnats b/usr.sbin/ctm/mkCTM/ctm_conf.gnats
new file mode 100644
index 00000000000..c2223f02cd1
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.gnats
@@ -0,0 +1,8 @@
+#!/usr/local/bin/tclsh
+
+#set CTMfirst 1
+set CTMname gnats
+set CTMref /home/gnats
+set CTMdest $CTMSW/../CTM-pub/$CTMname
+set CTMignore {\\.lock$}
+set CTMmail ctm-gnats@freebsd.org
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.ports-cur b/usr.sbin/ctm/mkCTM/ctm_conf.ports-cur
new file mode 100644
index 00000000000..b9d3d13a102
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.ports-cur
@@ -0,0 +1,7 @@
+#!/usr/local/bin/tclsh
+
+set CTMname ports-cur
+set CTMref /usr/ports
+set CTMignore {/CVS$|/CVS/|^distfiles}
+set CTMbogus {\\.core$|/#cvs|/\\.#}
+set CTMmail ctm-ports-cur@freebsd.org
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.smp-cur b/usr.sbin/ctm/mkCTM/ctm_conf.smp-cur
new file mode 100644
index 00000000000..5c3e1d1bf21
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.smp-cur
@@ -0,0 +1,7 @@
+#!/usr/local/bin/tclsh
+
+set CTMname smp-cur
+set CTMref /home/smp
+set CTMignore {^CVSROOT/history.*$|^CVSROOT/val-tags$|^CVSROOT/\\.#}
+set CTMbogus {\\.core$|/#cvs|/\\.#}
+set CTMmail smp-cvs-cur@freebsd.org
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.src-cur b/usr.sbin/ctm/mkCTM/ctm_conf.src-cur
new file mode 100644
index 00000000000..8589d040efb
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.src-cur
@@ -0,0 +1,9 @@
+#!/usr/local/bin/tclsh
+
+set CTMname src-cur
+set CTMref /c/src
+set CTMignore {/CVS$|/CVS/|^/secure|^/eBones}
+set CTMbogus {\\.core$|/#cvs|/\\.#}
+set CTMmail ctm-src-cur-fast@freebsd.org
+set CTMqueue /home/ctm/queue/ctm-src-cur
+set CTMqueuemail ctm-src-cur@freebsd.org
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.src-special b/usr.sbin/ctm/mkCTM/ctm_conf.src-special
new file mode 100644
index 00000000000..2a8ca70aeb6
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.src-special
@@ -0,0 +1,9 @@
+#!/usr/local/bin/tclsh
+
+set CTMname src-cur
+set CTMref $CTMSW/../$CTMname
+set CTMcopy /c/phk/20R/usr/src
+set CTMdont {\.core$|/CVS$|/CVS/|^/secure|^/eBones|/#cvs|/\.#}
+set CTMtest 1
+set CTMspecial 1
+set CTMsuff R20
diff --git a/usr.sbin/ctm/mkCTM/dequeue b/usr.sbin/ctm/mkCTM/dequeue
new file mode 100644
index 00000000000..c2e32897fed
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/dequeue
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: dequeue,v 1.1 1999/07/13 23:02:07 deraadt Exp $
+
+L=/home/ctm/log.dequeue
+/usr/sbin/ctm_dequeue -n 1 -l $L /home/ctm/queue/ctm-cvs-cur
+/usr/sbin/ctm_dequeue -n 1 -l $L /home/ctm/queue/ctm-src-cur
diff --git a/usr.sbin/ctm/mkCTM/mkCTM b/usr.sbin/ctm/mkCTM/mkCTM
index 3f884c13899..7d508881947 100644
--- a/usr.sbin/ctm/mkCTM/mkCTM
+++ b/usr.sbin/ctm/mkCTM/mkCTM
@@ -1,104 +1,6 @@
#!/usr/local/bin/tclsh7.4
-#############################################################################
-### Add something
-#############################################################################
-# Type Name Mode User Group Barf Size Hash
-
-proc CTMadd {t n m u g b s h} {
- global fo_files fo_mkdir changes CTMref
-
- puts stderr "A $b $t $n"
- incr changes
-
- if {$t == "d"} {
- puts $fo_mkdir "CTMDM $n $u $g $m"
- } elseif {$t == "f"} {
- puts $fo_files "CTMFM $n $u $g $m $h $s"
- flush $fo_files
- exec cat $CTMref/$n >@ $fo_files
- puts $fo_files ""
- } else {
- puts "confused in CTMadd"
- exit 0
- }
-}
-
-#############################################################################
-### Delete something
-#############################################################################
-# Type Name Mode User Group Barf Size Hash
-
-proc CTMdel {t n m u g b s h} {
- global fo_del fo_rmdir changes damage max_damage CTMlock
-
- puts stderr "D $b $t $n"
- incr damage
- incr changes
-
- if {$damage > $max_damage} {
- exec rm -f $CTMlock
- return
- }
- if {$t == "d"} {
- puts $fo_rmdir "CTMDR $n"
- } elseif {$t == "f"} {
- puts $fo_del "CTMFR $n $h"
- } else {
- puts "confused in CTMdel"
- exit 0
- }
-}
-
-#############################################################################
-### Change something
-#############################################################################
-# Type Name Mode User Group Barf Size Hash
-
-proc CTMchg {t1 n1 m1 u1 g1 b1 s1 h1 t2 n2 m2 u2 g2 b2 s2 h2} {
- global fo_files CTMref CTMcopy changes damage CTMscratch
-
- # Ignore attribute changes for directories
- if {$t1 == "d" && $t2 == "d"} return
-
- # turn file into dir or vice versa...
- if {$t1 != $t2} {
- CTMdel $t1 $n1 $m1 $u1 $g1 $b1 $s1 $h1
- CTMadd $t2 $n2 $m2 $u2 $g2 $b2 $s2 $h2
- return
- }
-
- # only files allowed past this poing...
- if {$t1 != "f" && $t2 != "f"} {
- puts "confused in CTMchg"
- exit 0
- }
-
- # Ignore attribute changes for files
- if {"x$h1" == "x$h2" && $s1 == $s2} return
-
- if {$s2 == 0} { incr damage }
- incr changes
-
- # If diff will deal with it...
- if {$b1 == "0" && $b2 == "0"} {
- set i [catch "exec diff -n $CTMcopy/$n1 $CTMref/$n2 > $CTMscratch" j]
- set s [file size $CTMscratch]
- if {$s < $s2} {
- puts stderr "E $b1$b2 $t1$t2 $n1"
- puts $fo_files "CTMFN $n1 $u2 $g2 $m2 $h1 $h2 $s"
- flush $fo_files
- exec cat $CTMscratch >@ $fo_files
- puts $fo_files ""
- return
- }
- }
- puts stderr "R $b1$b2 $t1$t2 $n1"
- puts $fo_files "CTMFS $n2 $u2 $g2 $m2 $h1 $h2 $s2"
- flush $fo_files
- exec cat $CTMref/$n2 >@ $fo_files
- puts $fo_files ""
-}
+# $OpenBSD: mkCTM,v 1.2 1999/07/13 23:02:07 deraadt Exp $
#############################################################################
### Do we already have this delta ?
@@ -121,8 +23,13 @@ cd $CTMSW
# Defaults...
set CTMapply 1
-set CTMdont {^///}
+set CTMignore {^///}
+set CTMbogus {\.core$}
set CTMmail {}
+set CTMqueue {}
+set CTMqueuemail {}
+set CTMmaxctm 10000000
+set CTMmaxmsg 100000
set CTMsuff {}
set CTMdate [exec date -u +%Y%m%d%H%M%SZ]
set CTMtmp {}
@@ -133,13 +40,13 @@ set CTMtest 0
set CTMspecial 0
set CTMscan .
set CTMfirst 0
-set max_damage 1200
+set max_damage 100
set damage 0
set changes 0
-exec sh -c "date -u '+%y%m%d%H%M%S $argv'" >> /home/ctm/log
source $argv
+exec sh -c "date -u '+%Y%m%d%H%M%S $argv'" >> ${CTMSW}/log
if {$CTMtmp == ""} {
set CTMtmp $CTMSW/../tmp/${CTMname}_${CTMsuff}
@@ -159,7 +66,7 @@ exec echo starting > ${CTMlock}
if {[catch "exec ln $CTMlock LCK.$CTMname" a]} {
puts "Not going, lock exists..."
exec rm -f $CTMlock
- exit 0
+ exit 1
}
exec rm -f $CTMlock
set CTMlock LCK.$CTMname
@@ -177,7 +84,7 @@ while 1 {
if {$CTMnbr > 0 && ![find_delta $CTMnbr]} {
puts "$CTMname delta $CTMnbr doesn't exist..."
exec rm -f $CTMlock
- exit 0
+ exit 1
}
incr CTMnbr
@@ -185,7 +92,7 @@ while 1 {
if {[find_delta $CTMnbr]} {
puts "$CTMname delta $CTMnbr does already exist..."
exec rm -f $CTMlock
- exit 0
+ exit 1
}
set fo [open $CTMref/.ctm_status w]
@@ -197,114 +104,33 @@ while 1 {
set CTMnbr [lindex [exec cat $CTMref/.ctm_status] 1]
}
- if {"$CTMcopy" == "" } {
- set f1 [open /dev/null]
- } else {
- set f1 [open "| ./ctm_scan $CTMcopy $CTMscan"]
- }
-
puts "Doing CTMname $CTMname CTMnbr $CTMnbr$CTMsuff CTMdate $CTMdate"
flush stdout
exec sh -c "rm -f ${CTMtmp}.* ${CTMtmp}:*" >&@ stdout
- set f2 [open "| ./ctm_scan $CTMref $CTMscan"]
-
- set fo_del [open $CTMtmp.del w]
- set fo_rmdir [open $CTMtmp.rmdir w]
- set fo_mkdir [open $CTMtmp.mkdir w]
- set fo_files [open $CTMtmp.files w]
-
- set l1 ""
- set l2 ""
-
- while 1 {
-
- if {$l1 == ""} {gets $f1 l1}
-
- if {$l2 == ""} {gets $f2 l2}
-
- if {$l1 == "" && $l2 == ""} break
-
- set n1 [lindex $l1 1]
- set n2 [lindex $l2 1]
-
- if {[regexp $CTMdont /$n1]} { set l1 "" ; continue }
- if {[regexp $CTMdont /$n2]} { set l2 "" ; continue }
-
- # they're all the same...
- if {$l1 == $l2} { set l1 "" ; set l2 "" ; continue }
-
- if {$l1 == "" } { eval CTMadd $l2 ; set l2 "" ; continue }
-
- if {$l2 == "" } { eval CTMdel $l1 ; set l1 "" ; continue }
-
- # if the name is the same we're safe...
- if {$n1 == $n2} {
- eval CTMchg $l1 $l2
- set l1 ""
- set l2 ""
- continue
- }
-
- # To avoid this anomaly:
- # A - d src/gnu/lib/libreadline/readline/Attic
- # A 0 f src/gnu/lib/libreadline/readline/Attic/readline.h,v
- # A 0 f src/gnu/lib/libreadline/readline.c,v
- # D 0 f src/gnu/lib/libreadline/readline/readline.h,v
- # D 0 f src/gnu/lib/libreadline/readline.c,v
- # we have to make things somewhat complicated...
+ set nm [format "%s.%04d%s" $CTMname $CTMnbr $CTMsuff]
- # if they have the same number of components...
- set ll1 [llength [split $n1 /]]
- set ll2 [llength [split $n2 /]]
- if {$ll1 == $ll2} {
- if {$n1 < $n2 } {
- eval CTMdel $l1 ; set l1 "" ; continue
- } else {
- eval CTMadd $l2 ; set l2 "" ; continue
- }
- }
- if {$ll1 < $ll2} {
- eval CTMadd $l2 ; set l2 "" ; continue
- } else {
- eval CTMdel $l1 ; set l1 "" ; continue
- }
+ set x1 $CTMcopy
+ if {$x1 == ""} {
+ exec mkdir ${CTMtmp}.dir
+ set x1 ${CTMtmp}.dir
}
+ set r1 [catch "exec ${CTMSW}/mkctm -I ${CTMignore} -B ${CTMbogus} -l ${CTMtmp}.log -D $max_damage $CTMname $CTMnbr $CTMdate . $x1 $CTMref | md5 -p | gzip -9 > ${CTMtmp}:${nm}.gz 2>@ stderr" r2]
- close $fo_del
- close $fo_rmdir
- close $fo_mkdir
- close $fo_files
-
- if {$damage > $max_damage} {
- puts "Too much damage: $damage deletes"
- exec sh -c "rm -f ${CTMtmp}.*"
+ if {$r1} {
+ if {[lindex $errorCode 2] == 4} {
+ puts "No changes, stopping."
exec rm -f $CTMlock
- exit 0
- }
-
- if {!$changes} {
- puts "no changes"
- exec sh -c "rm -f ${CTMtmp}.*"
+ exit 0
+ }
+ puts "problems, stopping now."
+ puts "errorCode $errorCode"
+ puts "$r2"
exec rm -f $CTMlock
- exit 0
- }
-
- exec echo CTM_BEGIN 2.0 $CTMname $CTMnbr $CTMdate $CTMprefix > $CTMtmp.begin
-
- puts "Assembling delta"
- flush stdout
- set nm [format "%s.%04d%s" $CTMname $CTMnbr $CTMsuff]
-
- set fdout [open "| /sbin/md5 -p | gzip -9 > ${CTMtmp}:${nm}.gz" w]
-
- foreach i {begin del rmdir mkdir files} {
- exec cat $CTMtmp.$i >@$fdout
+ exit 1
}
- puts $fdout "CTM_END " nonewline
- close $fdout ; unset fdout
-
- exec sh -c "rm -f ${CTMtmp}.*" >&@ stdout
+
+ puts "mkctm done"
if {$CTMtest} {
puts "testing, stopping now."
@@ -315,7 +141,7 @@ while 1 {
puts "Applying delta"
flush stdout
exec echo now applying > $CTMlock
- exec sh -e -c "cd $CTMcopy ; $CTMSW/ctm -v -v -v ${CTMtmp}:${nm}.gz" >&@ stdout
+ exec sh -e -c "cd $CTMcopy ; $CTMSW/ctm -v -v -v ${CTMtmp}:${nm}.gz" >& ${CTMtmp}.apply
exec echo did apply > $CTMlock
}
puts "Moving delta"
@@ -324,10 +150,20 @@ while 1 {
exec mv $CTMdest/.CTMtmp_${nm}.gz $CTMdest/${nm}.gz >&@ stdout
exec echo moved > $CTMlock
+ exec sh -c "rm -rf ${CTMtmp}.*" >&@ stdout
+
if {$CTMmail != ""} {
puts "Mailing delta"
flush stdout
- exec $CTMSW/ctm_smail -m 100000 -c 3000000 $CTMdest/${nm}.gz $CTMmail >&@ stdout
+ exec $CTMSW/ctm_smail -m $CTMmaxmsg -c $CTMmaxctm $CTMdest/${nm}.gz $CTMmail >&@ stdout
+ if {$CTMqueue != "" && $CTMqueuemail != ""} {
+ puts "Queueing delta"
+ flush stdout
+ exec $CTMSW/ctm_smail -m $CTMmaxmsg -c $CTMmaxctm -q $CTMqueue $CTMdest/${nm}.gz $CTMqueuemail >&@ stdout
+ puts "Sending initial two deltas"
+ flush stdout
+ exec $CTMSW/ctm_dequeue -n 2 $CTMqueue >&@ stdout
+ }
}
exec echo mailed > $CTMlock
@@ -342,6 +178,8 @@ while 1 {
set CTMsuff A
set CTMcopy ""
set CTMmail ""
+ set CTMqueue ""
+ set CTMqueuemail ""
set CTMapply 0
set CTMspecial 1
exec rm -f $CTMlock
diff --git a/usr.sbin/ctm/mkCTM/mkctm.c b/usr.sbin/ctm/mkCTM/mkctm.c
index e08c82b59e8..ef9e82df7e8 100644
--- a/usr.sbin/ctm/mkCTM/mkctm.c
+++ b/usr.sbin/ctm/mkCTM/mkctm.c
@@ -1,20 +1,13 @@
+/* $OpenBSD: mkctm.c,v 1.3 1999/07/13 23:02:07 deraadt Exp $ */
/* Still missing:
*
- * Damage counter
- * Change counter
- * Time stamp
- * prefix
- * cmd-line args
- * %100 deltas
- * delta and Add are different. delta -> Equ.
- *
* mkctm
* -B regex Bogus
* -I regex Ignore
* -D int Damage
* -q decrease verbosity
* -v increase verbosity
- * (-l str control logging.)
+ * -l file logfile
* name cvs-cur
* prefix src/secure
* dir1 "Soll"
@@ -38,7 +31,7 @@
#include <signal.h>
#define DEFAULT_IGNORE "/CVS$|/\\.#|00_TRANS\\.TBL$"
-#define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$"
+#define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$|\\.o$"
regex_t reg_ignore, reg_bogus;
int flag_ignore, flag_bogus;
@@ -46,6 +39,8 @@ int verbose;
int damage, damage_limit;
int change;
+FILE *logf;
+
u_long s1_ignored, s2_ignored;
u_long s1_bogus, s2_bogus;
u_long s1_wrong, s2_wrong;
@@ -59,10 +54,9 @@ u_long s_sub_files, s_sub_bytes;
void
Usage(void)
{
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, "\tmkctm [-options] name number timestamp prefix");
- fprintf(stderr, " dir1 dir2");
- fprintf(stderr, "Options:\n");
+ fprintf(stderr,
+ "usage: mkctm [-options] name number timestamp prefix dir1 dir2\n");
+ fprintf(stderr, "options:\n");
fprintf(stderr, "\t\t-B bogus_regexp\n");
fprintf(stderr, "\t\t-D damage_limit\n");
fprintf(stderr, "\t\t-I ignore_regexp\n");
@@ -73,34 +67,35 @@ Usage(void)
void
print_stat(FILE *fd, char *pre)
{
- fprintf(fd,"%sAvoided:\n",pre);
- fprintf(fd,"%s ignore: %5lu old %5lu new\n",
+ fprintf(fd, "%sNames:\n", pre);
+ fprintf(fd, "%s ignore: %5lu ref %5lu target\n",
pre, s1_ignored, s2_ignored);
- fprintf(fd,"%s bogus: %5lu old %5lu new\n",
+ fprintf(fd, "%s bogus: %5lu ref %5lu target\n",
pre, s1_bogus, s2_bogus);
- fprintf(fd,"%s wrong: %5lu old %5lu new\n",
+ fprintf(fd, "%s wrong: %5lu ref %5lu target\n",
pre, s1_wrong, s2_wrong);
- fprintf(fd,"%sDelta:\n",pre);
- fprintf(fd,"%s new: %5lu dirs %5lu files %9lu plus\n",
+ fprintf(fd, "%sDelta:\n", pre);
+ fprintf(fd, "%s new: %5lu dirs %5lu files %9lu plus\n",
pre, s_new_dirs, s_new_files, s_new_bytes);
- fprintf(fd,"%s del: %5lu dirs %5lu files %9lu minus\n",
+ fprintf(fd, "%s del: %5lu dirs %5lu files %9lu minus\n",
pre, s_del_dirs, s_del_files, s_del_bytes);
- fprintf(fd,"%s chg: %5lu files %9lu plus %9lu minus\n",
+ fprintf(fd, "%s chg: %5lu files %9lu plus %9lu minus\n",
pre, s_files_chg, s_bytes_add, s_bytes_del);
- fprintf(fd,"%s same: %5lu dirs %5lu files %9lu bytes\n",
+ fprintf(fd, "%s same: %5lu dirs %5lu files %9lu bytes\n",
pre, s_same_dirs, s_same_files, s_same_bytes);
- fprintf(fd,"%sMethod:\n",pre);
- fprintf(fd,"%s edit: %5lu files %9lu bytes %9lu saved\n",
+ fprintf(fd, "%sMethod:\n", pre);
+ fprintf(fd, "%s edit: %5lu files %9lu bytes %9lu saved\n",
pre, s_edit_files, s_edit_bytes, s_edit_saves);
- fprintf(fd,"%s sub: %5lu files %9lu bytes\n",
+ fprintf(fd, "%s sub: %5lu files %9lu bytes\n",
pre, s_sub_files, s_sub_bytes);
+
}
void
stat_info(int foo)
{
- signal(SIGINFO,stat_info);
- print_stat(stderr,"INFO: ");
+ signal(SIGINFO, stat_info);
+ print_stat(stderr, "INFO: ");
}
void DoDir(const char *dir1, const char *dir2, const char *name);
@@ -109,16 +104,16 @@ static struct stat st;
static __inline struct stat *
StatFile(char *name)
{
- if (lstat(name,&st) < 0)
- err(1,"Couldn't stat %s\n",name);
+ if (lstat(name, &st) < 0)
+ err(1, "couldn't stat %s", name);
return &st;
}
int
dirselect(struct dirent *de)
{
- if (!strcmp(de->d_name,".")) return 0;
- if (!strcmp(de->d_name,"..")) return 0;
+ if (!strcmp(de->d_name, ".")) return 0;
+ if (!strcmp(de->d_name, "..")) return 0;
return 1;
}
@@ -129,15 +124,16 @@ name_stat(const char *pfx, const char *dir, const char *name, struct dirent *de)
strlen(de->d_name) + 3);
struct stat *st;
- strcpy(buf,dir);
- strcat(buf,"/"); strcat(buf,name);
- strcat(buf,"/"); strcat(buf,de->d_name);
+ strcpy(buf, dir);
+ strcat(buf, "/"); strcat(buf, name);
+ strcat(buf, "/"); strcat(buf, de->d_name);
st = StatFile(buf);
- printf("%s %s%s %lu %lu %o",
+ printf("%s %s%s %u %u %o",
pfx, name, de->d_name,
st->st_uid, st->st_gid, st->st_mode & ~S_IFMT);
+ fprintf(logf, "%s %s%s\n", pfx, name, de->d_name);
if (verbose > 1) {
- fprintf(stderr,"%s %s%s\n", pfx, name, de->d_name);
+ fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name);
}
}
@@ -147,31 +143,31 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
if (de->d_type == DT_DIR) {
char *p = alloca(strlen(name)+strlen(de->d_name)+2);
- strcpy(p,name); strcat(p,de->d_name); strcat(p, "/");
- DoDir(dir1,dir2,p);
+ strcpy(p, name); strcat(p, de->d_name); strcat(p, "/");
+ DoDir(dir1, dir2, p);
s_same_dirs++;
} else {
char *buf1 = alloca(strlen(dir1) + strlen(name) +
strlen(de->d_name) + 3);
char *buf2 = alloca(strlen(dir2) + strlen(name) +
strlen(de->d_name) + 3);
- char *m1,md5_1[33],*m2, md5_2[33];
- u_char *p1,*p2;
- int fd1,fd2;
- struct stat s1,s2;
-
- strcpy(buf1,dir1);
- strcat(buf1,"/"); strcat(buf1,name);
- strcat(buf1,"/"); strcat(buf1,de->d_name);
- fd1 = open(buf1,O_RDONLY);
- if(fd1 < 0) { perror(buf1); exit(3); }
- fstat(fd1,&s1);
- strcpy(buf2,dir2);
- strcat(buf2,"/"); strcat(buf2,name);
- strcat(buf2,"/"); strcat(buf2,de->d_name);
- fd2 = open(buf2,O_RDONLY);
- if(fd2 < 0) { perror(buf2); exit(3); }
- fstat(fd2,&s2);
+ char *m1, md5_1[33], *m2, md5_2[33];
+ u_char *p1, *p2;
+ int fd1, fd2;
+ struct stat s1, s2;
+
+ strcpy(buf1, dir1);
+ strcat(buf1, "/"); strcat(buf1, name);
+ strcat(buf1, "/"); strcat(buf1, de->d_name);
+ fd1 = open(buf1, O_RDONLY);
+ if(fd1 < 0) { err(3, "%s", buf1); }
+ fstat(fd1, &s1);
+ strcpy(buf2, dir2);
+ strcat(buf2, "/"); strcat(buf2, name);
+ strcat(buf2, "/"); strcat(buf2, de->d_name);
+ fd2 = open(buf2, O_RDONLY);
+ if(fd2 < 0) { err(3, "%s", buf2); }
+ fstat(fd2, &s2);
#if 0
/* XXX if we could just trust the size to change... */
if (s1.st_size == s2.st_size) {
@@ -182,23 +178,22 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
goto finish;
}
#endif
- p1=mmap(0,s1.st_size,PROT_READ,MAP_PRIVATE,fd1,0);
- if ((int)p1 == -1) { perror(buf1); exit(3); }
+ p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf1); }
close(fd1);
- p2=mmap(0,s2.st_size,PROT_READ,MAP_PRIVATE,fd2,0);
- if ((int)p2 == -1) { perror(buf2); exit(3); }
+ p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (p2 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
close(fd2);
/* If identical, we're done. */
- if((s1.st_size == s2.st_size) && !memcmp(p1,p2,s1.st_size)) {
+ if((s1.st_size == s2.st_size) && !memcmp(p1, p2, s1.st_size)) {
s_same_files++;
s_same_bytes += s1.st_size;
goto finish;
}
s_files_chg++;
- damage++;
change++;
if (s1.st_size > s2.st_size)
s_bytes_del += (s1.st_size - s2.st_size);
@@ -209,11 +204,11 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
m2 = MD5Data(p2, s2.st_size, md5_2);
/* Just a curiosity... */
- if(!strcmp(m1,m2)) {
+ if(!strcmp(m1, m2)) {
if (s1.st_size != s2.st_size)
fprintf(stderr,
"Notice: MD5 same for files of diffent size:\n\t%s\n\t%s\n",
- buf1,buf2);
+ buf1, buf2);
goto finish;
}
@@ -224,7 +219,7 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
int j;
FILE *F;
- if (p1[s1.st_size-1] != '\n') {
+ if (s1.st_size && p1[s1.st_size-1] != '\n') {
if (verbose > 0)
fprintf(stderr,
"last char != \\n in %s\n",
@@ -232,7 +227,7 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
goto subst;
}
- if (p2[s2.st_size-1] != '\n') {
+ if (s2.st_size && p2[s2.st_size-1] != '\n') {
if (verbose > 0)
fprintf(stderr,
"last char != \\n in %s\n",
@@ -262,7 +257,7 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
strcat(cmd, buf1);
strcat(cmd, " ");
strcat(cmd, buf2);
- F = popen(cmd,"r");
+ F = popen(cmd, "r");
for (j = 1, l = 0; l < s2.st_size; ) {
j = fread(ob+l, 1, s2.st_size - l, F);
if (j < 1)
@@ -278,26 +273,26 @@ Equ(const char *dir1, const char *dir2, const char *name, struct dirent *de)
pclose(F);
if (l && l < s2.st_size) {
- name_stat("CTMFN",dir2,name,de);
- printf(" %s %s %d\n",m1,m2,(unsigned)l);
- fwrite(ob,1,l,stdout);
+ name_stat("CTMFN", dir2, name, de);
+ printf(" %s %s %d\n", m1, m2, (unsigned)l);
+ fwrite(ob, 1, l, stdout);
putchar('\n');
s_edit_files++;
s_edit_bytes += l;
s_edit_saves += (s2.st_size - l);
} else {
subst:
- name_stat("CTMFS",dir2,name,de);
- printf(" %s %s %u\n",m1,m2,(unsigned)s2.st_size);
- fwrite(p2,1,s2.st_size,stdout);
+ name_stat("CTMFS", dir2, name, de);
+ printf(" %s %s %u\n", m1, m2, (unsigned)s2.st_size);
+ fwrite(p2, 1, s2.st_size, stdout);
putchar('\n');
s_sub_files++;
s_sub_bytes += s2.st_size;
}
}
finish:
- munmap(p1,s1.st_size);
- munmap(p2,s2.st_size);
+ munmap(p1, s1.st_size);
+ munmap(p2, s2.st_size);
}
}
@@ -307,11 +302,11 @@ Add(const char *dir1, const char *dir2, const char *name, struct dirent *de)
change++;
if (de->d_type == DT_DIR) {
char *p = alloca(strlen(name)+strlen(de->d_name)+2);
- strcpy(p,name); strcat(p,de->d_name); strcat(p, "/");
- name_stat("CTMDM",dir2,name,de);
+ strcpy(p, name); strcat(p, de->d_name); strcat(p, "/");
+ name_stat("CTMDM", dir2, name, de);
putchar('\n');
s_new_dirs++;
- DoDir(dir1,dir2,p);
+ DoDir(dir1, dir2, p);
} else if (de->d_type == DT_REG) {
char *buf2 = alloca(strlen(dir2) + strlen(name) +
strlen(de->d_name) + 3);
@@ -320,21 +315,21 @@ Add(const char *dir1, const char *dir2, const char *name, struct dirent *de)
struct stat st;
int fd1;
- strcpy(buf2,dir2);
- strcat(buf2,"/"); strcat(buf2,name);
- strcat(buf2,"/"); strcat(buf2,de->d_name);
- fd1 = open(buf2,O_RDONLY);
- if (fd1 < 0) {perror(buf2); exit (3); }
- fstat(fd1,&st);
- p1=mmap(0,st.st_size,PROT_READ,MAP_PRIVATE,fd1,0);
- if ((int)p1 == -1) { perror(buf2); exit(3); }
+ strcpy(buf2, dir2);
+ strcat(buf2, "/"); strcat(buf2, name);
+ strcat(buf2, "/"); strcat(buf2, de->d_name);
+ fd1 = open(buf2, O_RDONLY);
+ if (fd1 < 0) { err(3, "%s", buf2); }
+ fstat(fd1, &st);
+ p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
close(fd1);
m2 = MD5Data(p1, st.st_size, md5_2);
- name_stat("CTMFM",dir2,name,de);
- printf(" %s %u\n",m2,(unsigned)st.st_size);
- fwrite(p1,1,st.st_size,stdout);
+ name_stat("CTMFM", dir2, name, de);
+ printf(" %s %u\n", m2, (unsigned)st.st_size);
+ fwrite(p1, 1, st.st_size, stdout);
putchar('\n');
- munmap(p1,st.st_size);
+ munmap(p1, st.st_size);
s_new_files++;
s_new_bytes += st.st_size;
}
@@ -347,19 +342,27 @@ Del (const char *dir1, const char *dir2, const char *name, struct dirent *de)
change++;
if (de->d_type == DT_DIR) {
char *p = alloca(strlen(name)+strlen(de->d_name)+2);
- strcpy(p,name); strcat(p,de->d_name); strcat(p, "/");
- DoDir(dir1,dir2,p);
- printf("CTMDR %s%s\n",name,de->d_name);
+ strcpy(p, name); strcat(p, de->d_name); strcat(p, "/");
+ DoDir(dir1, dir2, p);
+ printf("CTMDR %s%s\n", name, de->d_name);
+ fprintf(logf, "CTMDR %s%s\n", name, de->d_name);
+ if (verbose > 1) {
+ fprintf(stderr, "CTMDR %s%s\n", name, de->d_name);
+ }
s_del_dirs++;
} else if (de->d_type == DT_REG) {
char *buf1 = alloca(strlen(dir1) + strlen(name) +
strlen(de->d_name) + 3);
char *m1, md5_1[33];
- strcpy(buf1,dir1);
- strcat(buf1,"/"); strcat(buf1,name);
- strcat(buf1,"/"); strcat(buf1,de->d_name);
+ strcpy(buf1, dir1);
+ strcat(buf1, "/"); strcat(buf1, name);
+ strcat(buf1, "/"); strcat(buf1, de->d_name);
m1 = MD5File(buf1, md5_1);
- printf("CTMFR %s%s %s\n",name,de->d_name,m1);
+ printf("CTMFR %s%s %s\n", name, de->d_name, m1);
+ fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1);
+ if (verbose > 1) {
+ fprintf(stderr, "CTMFR %s%s\n", name, de->d_name);
+ }
s_del_files++;
s_del_bytes += StatFile(buf1)->st_size;
}
@@ -369,35 +372,38 @@ void
GetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u_long *ignored, u_long *bogus, u_long *wrong)
{
char buf[BUFSIZ];
+ char buf1[BUFSIZ];
for (;;) {
for (;;) {
(*i)++;
if (*i >= *n)
return;
- *buf = 0;
- if (*dir != '/')
- strcat(buf,"/");
- strcat(buf,dir);
- if (buf[strlen(buf)-1] != '/')
- strcat(buf,"/");
- strcat(buf,name);
- if (buf[strlen(buf)-1] != '/')
- strcat(buf,"/");
- strcat(buf,nl[*i]->d_name);
+ strcpy(buf1, name);
+ if (buf1[strlen(buf1)-1] != '/')
+ strcat(buf1, "/");
+ strcat(buf1, nl[*i]->d_name);
if (flag_ignore &&
- !regexec(&reg_ignore,buf,0,0,0)) {
+ !regexec(&reg_ignore, buf1, 0, 0, 0)) {
(*ignored)++;
+ fprintf(logf, "Ignore %s\n", buf1);
if (verbose > 2) {
- fprintf(stderr,"Ignore %s\n",buf);
+ fprintf(stderr, "Ignore %s\n", buf1);
}
} else if (flag_bogus &&
- !regexec(&reg_bogus,buf,0,0,0)) {
+ !regexec(&reg_bogus, buf1, 0, 0, 0)) {
(*bogus)++;
- if (verbose > 0) {
- fprintf(stderr,"Bogus %s\n",buf);
- }
+ fprintf(logf, "Bogus %s\n", buf1);
+ fprintf(stderr, "Bogus %s\n", buf1);
+ damage++;
} else {
+ *buf = 0;
+ if (*dir != '/')
+ strcat(buf, "/");
+ strcat(buf, dir);
+ if (buf[strlen(buf)-1] != '/')
+ strcat(buf, "/");
+ strcat(buf, buf1);
break;
}
free(nl[*i]); nl[*i] = 0;
@@ -409,7 +415,7 @@ GetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u
break;
(*wrong)++;
if (verbose > 0)
- fprintf(stderr,"Wrong %s\n",buf);
+ fprintf(stderr, "Wrong %s\n", buf);
free(nl[*i]); nl[*i] = 0;
}
}
@@ -417,13 +423,13 @@ GetNext(int *i, int *n, struct dirent **nl, const char *dir, const char *name, u
void
DoDir(const char *dir1, const char *dir2, const char *name)
{
- int i1,i2,n1,n2,i;
- struct dirent **nl1,**nl2;
+ int i1, i2, n1, n2, i;
+ struct dirent **nl1, **nl2;
char *buf1 = alloca(strlen(dir1) + strlen(name) + 4);
char *buf2 = alloca(strlen(dir2) + strlen(name) + 4);
- strcpy(buf1,dir1); strcat(buf1,"/"); strcat(buf1,name);
- strcpy(buf2,dir2); strcat(buf2,"/"); strcat(buf2,name);
+ strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, name);
+ strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, name);
n1 = scandir(buf1, &nl1, dirselect, alphasort);
n2 = scandir(buf2, &nl2, dirselect, alphasort);
i1 = i2 = -1;
@@ -449,31 +455,31 @@ DoDir(const char *dir1, const char *dir2, const char *name)
break;
} else if (i1 >= n1 && i2 < n2) {
/* end of list 1, add anything left on list 2 */
- Add(dir1,dir2,name,nl2[i2]);
+ Add(dir1, dir2, name, nl2[i2]);
free(nl2[i2]); nl2[i2] = 0;
} else if (i1 < n1 && i2 >= n2) {
/* end of list 2, delete anything left on list 1 */
- Del(dir1,dir2,name,nl1[i1]);
+ Del(dir1, dir2, name, nl1[i1]);
free(nl1[i1]); nl1[i1] = 0;
} else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) {
/* Identical names */
if (nl1[i1]->d_type == nl2[i2]->d_type) {
/* same type */
- Equ(dir1,dir2,name,nl1[i1]);
+ Equ(dir1, dir2, name, nl1[i1]);
} else {
/* different types */
- Del(dir1,dir2,name,nl1[i1]);
- Add(dir1,dir2,name,nl2[i2]);
+ Del(dir1, dir2, name, nl1[i1]);
+ Add(dir1, dir2, name, nl2[i2]);
}
free(nl1[i1]); nl1[i1] = 0;
free(nl2[i2]); nl2[i2] = 0;
} else if (i < 0) {
/* Something extra in list 1, delete it */
- Del(dir1,dir2,name,nl1[i1]);
+ Del(dir1, dir2, name, nl1[i1]);
free(nl1[i1]); nl1[i1] = 0;
} else {
/* Something extra in list 2, add it */
- Add(dir1,dir2,name,nl2[i2]);
+ Add(dir1, dir2, name, nl2[i2]);
free(nl2[i2]); nl2[i2] = 0;
}
}
@@ -492,22 +498,24 @@ main(int argc, char **argv)
setbuf(stderr, NULL);
- if (regcomp(&reg_bogus,DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE))
+#if 0
+ if (regcomp(&reg_bogus, DEFAULT_BOGUS, REG_EXTENDED | REG_NEWLINE))
/* XXX use regerror to explain it */
- err(1,"Default regular expression argument to -B is botched");
+ errx(1, "default regular expression argument to -B is botched");
flag_bogus = 1;
- if (regcomp(&reg_ignore,DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE))
+ if (regcomp(&reg_ignore, DEFAULT_IGNORE, REG_EXTENDED | REG_NEWLINE))
/* XXX use regerror to explain it */
- err(1,"Default regular expression argument to -I is botched");
+ errx(1, "default regular expression argument to -I is botched");
flag_ignore = 1;
+#endif
- while ((i = getopt(argc,argv,"D:I:B:qv")) != -1)
+ while ((i = getopt(argc, argv, "D:I:B:l:qv")) != -1)
switch (i) {
case 'D':
- damage_limit = strtol(optarg,0,0);
+ damage_limit = strtol(optarg, 0, 0);
if (damage_limit < 0)
- err(1,"Damage limit must be positive");
+ errx(1, "damage limit must be positive");
break;
case 'I':
if (flag_ignore)
@@ -515,10 +523,10 @@ main(int argc, char **argv)
flag_ignore = 0;
if (!*optarg)
break;
- if (regcomp(&reg_ignore,optarg,
+ if (regcomp(&reg_ignore, optarg,
REG_EXTENDED | REG_NEWLINE))
/* XXX use regerror to explain it */
- err(1,"Regular expression argument to -I is botched");
+ errx(1, "regular expression argument to -I is botched");
flag_ignore = 1;
break;
case 'B':
@@ -527,12 +535,17 @@ main(int argc, char **argv)
flag_bogus = 0;
if (!*optarg)
break;
- if (regcomp(&reg_bogus,optarg,
+ if (regcomp(&reg_bogus, optarg,
REG_EXTENDED | REG_NEWLINE))
/* XXX use regerror to explain it */
- err(1,"Regular expression argument to -B is botched");
+ errx(1, "regular expression argument to -B is botched");
flag_bogus = 1;
break;
+ case 'l':
+ logf = fopen(optarg, "w");
+ if (!logf)
+ err(1, "%s", optarg);
+ break;
case 'q':
verbose--;
break;
@@ -547,26 +560,35 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- setbuf(stdout,0);
+ if (!logf)
+ logf = fopen("/dev/null", "w");
+
+ setbuf(stdout, 0);
if (argc != 6) {
Usage();
return (1);
}
- signal(SIGINFO,stat_info);
+ signal(SIGINFO, stat_info);
+ fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n",
+ argv[0], argv[1], argv[2], argv[3]);
+ fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n",
+ argv[0], argv[1], argv[2], argv[3]);
printf("CTM_BEGIN 2.0 %s %s %s %s\n",
argv[0], argv[1], argv[2], argv[3]);
- DoDir(argv[4],argv[5],"");
+ DoDir(argv[4], argv[5], "");
if (damage_limit && damage > damage_limit) {
- print_stat(stderr,"");
- err(1,"Damage would exceede %d files", damage_limit);
- } else if (!change) {
- err(1,"No changes");
+ print_stat(stderr, "DAMAGE: ");
+ errx(1, "damage of %d would exceed %d files",
+ damage, damage_limit);
+ } else if (change < 2) {
+ errx(4, "no changes");
} else {
printf("CTM_END ");
- print_stat(stderr,"");
+ fprintf(logf, "CTM_END\n");
+ print_stat(stderr, "END: ");
}
exit(0);
}