2069 lines
53 KiB
Plaintext
2069 lines
53 KiB
Plaintext
|
|
These patches bring nemeton's ctmkit up to what ctm was like when it
|
|
was still in the OpenBSD src tree. (Mostly documentation fixes, a
|
|
mkstemp or two, and the new ctm options -ektlx.)
|
|
|
|
|
|
diff -uNr ctm/README ../ctm/README
|
|
--- ctm/README Thu Sep 22 12:49:07 1994
|
|
+++ ../ctm/README Wed Jul 14 09:02:03 1999
|
|
@@ -5,7 +5,7 @@
|
|
# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
# ----------------------------------------------------------------------------
|
|
#
|
|
-# $Id: README,v 1.4 1994/09/22 02:49:07 phk 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 @@
|
|
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 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 -uNr ctm/ctm/ctm.1 ../ctm/ctm/ctm.1
|
|
--- ctm/ctm/ctm.1 Wed May 1 09:01:43 1996
|
|
+++ ../ctm/ctm/ctm.1 Wed Jul 14 09:02:05 1999
|
|
@@ -1,5 +1,5 @@
|
|
.\"----------------------------------------------------------------------------
|
|
-.\""THE BEER-WARE LICENSE" (Revision 42):
|
|
+.\""THE BEER-WARE LICENSE" (Revision 42):
|
|
.\"<joerg@freebsd.org> 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. Joerg Wunsch
|
|
@@ -10,7 +10,7 @@
|
|
.\"
|
|
.\" CTM and ctm(1) by <phk@login.dknet.dk>
|
|
.\"
|
|
-.\" $Id: ctm.1,v 1.5 1996/04/29 21:02:26 phk Exp $
|
|
+.\" $Id: ctm.1,v 1.9 1999/07/13 23:02:05 deraadt Exp $
|
|
.\"
|
|
.Dd Mar 25, 1995
|
|
.Os
|
|
@@ -20,19 +20,23 @@
|
|
.Nd source code mirror program
|
|
.Sh SYNOPSIS
|
|
.Nm ctm
|
|
-.Op Fl cFpPquv
|
|
+.Op Fl cFklquv
|
|
.Op Fl b Ar basedir
|
|
+.Op Fl B Ar backup-file
|
|
+.Op Fl e Ar include-regex
|
|
+.Op Fl t Ar tar-command
|
|
.Op Fl T Ar tmpdir
|
|
.Op Fl V Ar level
|
|
-.Ar file Op ...
|
|
+.Op Fl x Ar exclude-regex
|
|
+.Ar
|
|
.Sh DESCRIPTION
|
|
-.Nm Ctm
|
|
+.Nm
|
|
was originally
|
|
.Dq Cvs Through eMail ,
|
|
but now instead it seems more fitting to call it
|
|
.Dq Current Through eMail .
|
|
-
|
|
-.Nm Ctm
|
|
+.Pp
|
|
+.Nm
|
|
is now meant to be the definitive way to make and apply a delta between
|
|
two versions of a directory tree.
|
|
|
|
@@ -40,80 +44,157 @@
|
|
entirely different things.
|
|
|
|
.Ss Usage
|
|
-
|
|
To apply a CTM delta, you pass it to the
|
|
-.Nm ctm
|
|
+.Nm
|
|
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
|
|
+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
|
|
+specify multiple deltas at one time, they will be processed one at a
|
|
time. Deltas that are already applied will be ignored.
|
|
|
|
The
|
|
-.Nm ctm
|
|
+.Nm
|
|
command runs in a number of passes. It will process the entire
|
|
input file in each pass, before commencing with the next pass.
|
|
|
|
-Before working one a file
|
|
+Before working on a file
|
|
.Ar name
|
|
-.Nm ctm
|
|
+.Nm
|
|
first checks for the existence of the file
|
|
.Ar name.ctm .
|
|
If this file exists,
|
|
-.Nm ctm
|
|
+.Nm
|
|
works on it instead.
|
|
-
|
|
-Pass 1 will validate that the input file is OK. The syntax, the data
|
|
+.Pp
|
|
+Pass 1 will verify that the input file is OK. The syntax, the data
|
|
and the global MD5 checksum will be checked. If any of these fail,
|
|
-.Nm ctm
|
|
-will never be able to do anything with the file, so it will simply
|
|
-reject it.
|
|
+.Nm
|
|
+will simply reject the input file.
|
|
|
|
Pass 2 will validate that the directory tree is in the state expected by
|
|
the CTM delta. This is done by looking for files and directories which
|
|
-should/should not exists and by checking the MD5 checksums of files.
|
|
+should/should not exist and by checking the MD5 checksums of files.
|
|
|
|
-Pass 3 will actually apply the delta.
|
|
+If a
|
|
+.Ar backup-file
|
|
+had been specified using the
|
|
+.Fl B
|
|
+option, all files that would be modified by this
|
|
+.Nm
|
|
+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 Ctm
|
|
+.Nm
|
|
will extract the file hierarchy below its working directory. Absolute
|
|
filenames or filenames containing references through
|
|
-.Sq \&.
|
|
-and
|
|
-.Sq \&.\&.
|
|
+.Dq \&.
|
|
+or
|
|
+.Dq \&.\&.
|
|
are explicitly prohibited as a security measure.
|
|
-
|
|
+.Pp
|
|
.Ss Options
|
|
-
|
|
.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 modification time of created and modified files to the CTM delta
|
|
+Set the modification time of created and modified files to the CTM delta
|
|
creation time.
|
|
|
|
.It Fl v
|
|
@@ -121,56 +202,81 @@
|
|
|
|
.It Fl V Ar level
|
|
Tell us more.
|
|
-.Ar Level
|
|
+.Ar level
|
|
is the level of verbosity.
|
|
|
|
-.El
|
|
+.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,
|
|
+if set to a pathname, will cause
|
|
+.Nm
|
|
+to use that pathname
|
|
+as the location of temporary file.
|
|
+See
|
|
+.Xr tempnam 3
|
|
+for more details on this.
|
|
+The same effect may be achieved with the
|
|
+.Fl T
|
|
+flag.
|
|
.Sh FILES
|
|
-
|
|
.Pa .ctm_status
|
|
contains the sequence number of the last CTM delta applied. Changing
|
|
or removing this file will greatly confuse
|
|
.Nm ctm .
|
|
|
|
-.Sh EXAMPLES
|
|
-
|
|
-.Bd -literal
|
|
+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.
|
|
|
|
-cd ~cvs
|
|
-/usr/sbin/ctm ~ctm/cvs-*
|
|
+.Sh EXAMPLES
|
|
+.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-explaining. The
|
|
+Numerous messages, hopefully self-explanatory. The
|
|
.Dq noise level
|
|
can be adjusted with the
|
|
-.Fl q
|
|
-and
|
|
+.Fl q ,
|
|
.Fl v
|
|
+and
|
|
+.Fl V
|
|
options.
|
|
-
|
|
.Sh SEE ALSO
|
|
-
|
|
+.Xr ctm_rmail 1 ,
|
|
.Xr ctm 5
|
|
-
|
|
.Sh HISTORY
|
|
-
|
|
-Initial trials ran during the FreeBSD 1.1.5, and many bugs and
|
|
+Initial trials were run during the work on FreeBSD 1.1.5, and many bugs and
|
|
methods were hashed out.
|
|
-
|
|
The
|
|
-.Nm ctm
|
|
+.Nm
|
|
command appeared in FreeBSD 2.1.
|
|
-
|
|
.Sh AUTHORS
|
|
-
|
|
The CTM system has been designed and implemented by
|
|
Poul-Henning Kamp
|
|
.Aq phk@FreeBSD.org .
|
|
-
|
|
-Joerg Wunsch wrote this man-page.
|
|
-.Aq joerg@FreeBSD.org .
|
|
+Joerg Wunsch
|
|
+.Aq joerg@FreeBSD.org
|
|
+wrote this man page.
|
|
diff -uNr ctm/ctm/ctm.5 ../ctm/ctm/ctm.5
|
|
--- ctm/ctm/ctm.5 Mon Mar 27 06:09:48 1995
|
|
+++ ../ctm/ctm/ctm.5 Wed Jul 14 09:02:05 1999
|
|
@@ -1,5 +1,5 @@
|
|
.\"----------------------------------------------------------------------------
|
|
-.\""THE BEER-WARE LICENSE" (Revision 42):
|
|
+.\""THE BEER-WARE LICENSE" (Revision 42):
|
|
.\"<joerg@freebsd.org> 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. Joerg Wunsch
|
|
@@ -10,7 +10,7 @@
|
|
.\"
|
|
.\" CTM and ctm(1) by <phk@login.dknet.dk>
|
|
.\"
|
|
-.\" $Id: ctm.5,v 1.2 1995/03/26 20:09:48 phk Exp $
|
|
+.\" $Id: ctm.5,v 1.6 1999/07/13 23:02:05 deraadt Exp $
|
|
.\"
|
|
.Dd March 25, 1995
|
|
.Os
|
|
@@ -18,66 +18,63 @@
|
|
.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
|
|
line starts with the letters
|
|
.Dq CTM ,
|
|
-followed by a CTM statement and control data, and ends with a '\en'
|
|
+followed by a CTM statement and control data, and ends with a
|
|
+newline
|
|
+.Pq Sq \en
|
|
character.
|
|
-
|
|
-Data chunks always belong to the preceeding control line, and the
|
|
+.Pp
|
|
+Data chunks always belong to the preceding control line, and the
|
|
last field on that control line is the number of bytes in the data
|
|
chunk.
|
|
-A trailing newline '\en' character follows each data chunk, this
|
|
+A trailing newline
|
|
+character follows each data chunk. This
|
|
newline is not part of the chunk and isn't included in the count.
|
|
-
|
|
-The CTM statements are as follows.
|
|
+.Pp
|
|
+The CTM statements are as follows:
|
|
.Bl -tag -width indent
|
|
-
|
|
.It _BEGIN Ar version name number timestamp prefix
|
|
-
|
|
This is the overall begin of a CTM delta file. The
|
|
.Ar version
|
|
field must match the program version
|
|
.Pq currently 2.0 .
|
|
-.Ar Name
|
|
+.Ar name
|
|
is the name and
|
|
.Ar number
|
|
-the sequence number of the CTM service, it is matched against the file
|
|
+the sequence number of the CTM service; it is matched against the file
|
|
.Pa .ctm_status
|
|
to see if the delta has already been applied.
|
|
-.Ar Timestamp
|
|
+.Ar timestamp
|
|
contains the year, month, day, hour, minute, and second of the
|
|
time of delta creation for reference
|
|
.Po
|
|
followed by the letter
|
|
-.Sq Z
|
|
+.Dq Z ,
|
|
meaning this is a UTC timestamp
|
|
.Pc .
|
|
The
|
|
.Ar prefix
|
|
-This field is currently not implemented.
|
|
-
|
|
+field is currently not implemented.
|
|
.It _END Ar md5
|
|
-
|
|
-This statement ends the CTM delta, the global
|
|
+This statement ends the CTM delta. The global
|
|
.Ar md5
|
|
-checksum is matched against the MD5 checksum of the entire delta, up to
|
|
-and including the space (0x20) character following ``_END''.
|
|
-
|
|
+checksum is matched against the MD5 checksum of the entire delta, up to
|
|
+and including the space (0x20) character following
|
|
+.Dq _END .
|
|
.It \&FM Ar name uid gid mode md5 count
|
|
-
|
|
Make the file
|
|
-.Ar name ,
|
|
-the original file had the uid
|
|
+.Ar name .
|
|
+The original file had the UID
|
|
.Ar uid
|
|
.Pq numerical, decimal ,
|
|
-the gid
|
|
+the GID
|
|
.Ar gid
|
|
.Pq numerical, decimal ,
|
|
mode
|
|
@@ -85,19 +82,16 @@
|
|
.Pq numerical, octal ,
|
|
and the MD5 checksum
|
|
.Ar md5 .
|
|
-
|
|
The following
|
|
.Ar count
|
|
bytes data are the contents of the new file.
|
|
-
|
|
.It \&FS Ar name uid gid mode md5before md5after count
|
|
-
|
|
Substitute the contents of file
|
|
-.Ar name ,
|
|
-the original file had the new uid
|
|
+.Ar name .
|
|
+The original file had the new UID
|
|
.Ar uid
|
|
.Pq numerical, decimal ,
|
|
-the new gid
|
|
+the new GID
|
|
.Ar gid
|
|
.Pq numerical, decimal ,
|
|
new mode
|
|
@@ -107,31 +101,23 @@
|
|
.Ar md5before ,
|
|
and the new MD5 checksum
|
|
.Ar md5after .
|
|
-
|
|
The following
|
|
.Ar count
|
|
bytes data are the contents of the new file.
|
|
-
|
|
File substitution is used if the commands to edit a file would exceed
|
|
the total file length, so substituting it is more efficient.
|
|
-
|
|
.It \&FN Ar name uid gid mode md5before md5after count
|
|
-
|
|
Edit the file
|
|
.Ar name .
|
|
-The arguments are as above, but the data sections contains an
|
|
+The arguments are as above, but the data sections contain a
|
|
.Xr diff 1
|
|
-n script which should be applied to the file in question.
|
|
-
|
|
.It \&FR Ar name md5
|
|
-
|
|
Remove the file
|
|
.Ar name ,
|
|
which must match the MD5 checksum
|
|
.Ar md5 .
|
|
-
|
|
.It \&AS Ar name uid gid mode
|
|
-
|
|
The original file
|
|
.Ar name
|
|
changed its owner to
|
|
@@ -140,34 +126,25 @@
|
|
.Ar gid ,
|
|
and/or its mode to
|
|
.Ar mode .
|
|
-
|
|
.It \&DM Ar name uid gid mode
|
|
-
|
|
The directory
|
|
.Ar name
|
|
-is to be created, it had originally the owner
|
|
+is to be created. It had originally the owner
|
|
.Ar uid ,
|
|
group
|
|
.Ar gid ,
|
|
and mode
|
|
.Ar mode .
|
|
-
|
|
.It \&DR name
|
|
-
|
|
The directory
|
|
.Ar name
|
|
is to be removed.
|
|
-
|
|
.El
|
|
-
|
|
.Sh EXAMPLES
|
|
-
|
|
In the following example, long lines have been folded to make them
|
|
printable
|
|
.Pq marked by backslashes .
|
|
-
|
|
.Bd -literal
|
|
-
|
|
CTM_BEGIN 2.0 cvs-cur 485 19950324214652Z .
|
|
CTMFR src/sys/gnu/i386/isa/scd.c,v 5225f13aa3c7e458f9dd0d4bb637b18d
|
|
CTMFR src/sys/gnu/i386/isa/scdreg.h,v e5af42b8a06f2c8030b93a7d71afb223
|
|
@@ -175,35 +152,29 @@
|
|
CTMFS .ctm_status 545 552 664 d9ccd2a84a9dbb8db56ba85663adebf0 \\
|
|
e2a10c6f66428981782a0a18a789ee2e 12
|
|
cvs-cur 485
|
|
-
|
|
+.Pp
|
|
CTMFN CVSROOT/commitlogs/gnu 545 552 664 \\
|
|
5d7bc3549140d860bd9641b5782c002d 7fb04ed84b48160c9b8eea84b4c0b6e3 394
|
|
a6936 21
|
|
ache 95/03/24 09:59:50
|
|
-
|
|
+.Pp
|
|
Modified: gnu/lib/libdialog kernel.c prgbox.c
|
|
Log:
|
|
[...]
|
|
CTM_END 74ddd298d76215ae45a077a4b6a74e9c
|
|
-
|
|
.Ed
|
|
-
|
|
.Sh SEE ALSO
|
|
-
|
|
-.Xr ctm 1 ;
|
|
-.Xr ed 1 .
|
|
-
|
|
+.Xr ctm 1 ,
|
|
+.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
|
|
-
|
|
The CTM system has been designed and implemented by
|
|
Poul-Henning Kamp
|
|
.Aq phk@FreeBSD.org .
|
|
-
|
|
-Joerg Wunsch wrote this man-page.
|
|
-.Aq joerg@FreeBSD.org .
|
|
+Joerg Wunsch
|
|
+.Aq joerg@FreeBSD.org
|
|
+wrote this man page.
|
|
diff -uNr ctm/ctm/ctm.c ../ctm/ctm/ctm.c
|
|
--- ctm/ctm/ctm.c Wed May 1 09:01:43 1996
|
|
+++ ../ctm/ctm/ctm.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.13 1996/04/29 21:02:28 phk 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 @@
|
|
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 @@
|
|
}
|
|
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 @@
|
|
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;
|
|
}
|
|
|
|
@@ -166,17 +224,27 @@
|
|
|
|
/* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
|
|
if(!p && -1 == fseek(f,0,SEEK_END)) {
|
|
- char *fn = tempnam(TmpDir,"CTMclient");
|
|
- FILE *f2 = fopen(fn,"w+");
|
|
- int i;
|
|
+ char *fn;
|
|
+ FILE *f2;
|
|
+ int fd, i;
|
|
|
|
- if(!f2) {
|
|
- perror(fn);
|
|
+ if (asprintf(&fn, "%s/CTMclient.XXXXXXXX", TmpDir) == -1) {
|
|
+ warnx("Cannot allocate memory\n");
|
|
+ fclose(f);
|
|
+ return Exit_Broke;
|
|
+ }
|
|
+ if ((fd = mkstemp(fn)) == -1 || (f2 = fdopen(fd, "w+")) == NULL) {
|
|
+ warn("%s", fn);
|
|
+ free(fn);
|
|
+ if (fd != -1)
|
|
+ close(fd);
|
|
fclose(f);
|
|
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)) {
|
|
fclose(f2);
|
|
@@ -192,12 +260,17 @@
|
|
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);
|
|
@@ -207,7 +280,7 @@
|
|
} else {
|
|
pclose(f);
|
|
f = popen(p,"r");
|
|
- if(!f) { perror(p); return Exit_Broke; }
|
|
+ if(!f) { warn("%s", p); return Exit_Broke; }
|
|
}
|
|
|
|
if(i) {
|
|
@@ -216,10 +289,25 @@
|
|
}
|
|
|
|
if(CheckIt) {
|
|
- fprintf(stderr,"All checks out ok.\n");
|
|
+ if (Verbose > 0)
|
|
+ fprintf(stderr,"All checks out ok.\n");
|
|
i = Exit_Done;
|
|
goto exit_and_close;
|
|
}
|
|
+
|
|
+ /* backup files if requested */
|
|
+ if(BackupFile) {
|
|
+
|
|
+ i = PassB(f);
|
|
+
|
|
+ if(!p) {
|
|
+ rewind(f);
|
|
+ } else {
|
|
+ pclose(f);
|
|
+ f = popen(p,"r");
|
|
+ if(!f) { warn("%s", p); return Exit_Broke; }
|
|
+ }
|
|
+ }
|
|
|
|
i=Pass3(f);
|
|
|
|
@@ -232,6 +320,8 @@
|
|
if(i)
|
|
return i;
|
|
|
|
- fprintf(stderr,"All done ok\n");
|
|
+ if (Verbose > 0)
|
|
+ fprintf(stderr,"All done ok\n");
|
|
+
|
|
return Exit_Done;
|
|
}
|
|
diff -uNr ctm/ctm/ctm.h ../ctm/ctm/ctm.h
|
|
--- ctm/ctm/ctm.h Wed May 1 09:01:43 1996
|
|
+++ ../ctm/ctm/ctm.h Wed Jul 14 09:02:05 1999
|
|
@@ -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.9 1996/04/29 21:02:29 phk 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 *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 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 @@
|
|
#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 @@
|
|
|
|
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 -uNr ctm/ctm/ctm_ed.c ../ctm/ctm/ctm_ed.c
|
|
--- ctm/ctm/ctm_ed.c Tue May 30 13:47:22 1995
|
|
+++ ../ctm/ctm/ctm_ed.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.6 1995/05/30 03:47:22 rgrimes Exp $
|
|
+ * $Id: ctm_ed.c,v 1.2 1999/07/13 23:02:05 deraadt Exp $
|
|
*
|
|
*/
|
|
|
|
@@ -21,13 +21,13 @@
|
|
|
|
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 @@
|
|
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 -uNr ctm/ctm/ctm_pass1.c ../ctm/ctm/ctm_pass1.c
|
|
--- ctm/ctm/ctm_pass1.c Tue Feb 6 02:06:50 1996
|
|
+++ ../ctm/ctm/ctm_pass1.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.12 1996/02/05 16:06:50 phk Exp $
|
|
+ * $Id: ctm_pass1.c,v 1.2 1999/07/13 23:02:05 deraadt Exp $
|
|
*
|
|
*/
|
|
|
|
@@ -23,9 +23,9 @@
|
|
u_char *p,*q;
|
|
MD5_CTX ctx;
|
|
int i,j,sep,cnt;
|
|
- u_char *md5=0,*trash=0;
|
|
+ u_char *md5=0,*name=0,*trash=0;
|
|
struct CTM_Syntax *sp;
|
|
- int slashwarn=0;
|
|
+ int slashwarn=0, match=0, total_matches=0;
|
|
unsigned current;
|
|
char md5_1[33];
|
|
|
|
@@ -55,8 +55,10 @@
|
|
GETFIELDCOPY(Prefix,'\n'); /* <Prefix> */
|
|
|
|
sscanf(Nbr, "%u", ¤t);
|
|
+ if (FilterList || ListIt)
|
|
+ current = 0; /* ignore if -l or if filters are present */
|
|
if(current && current <= applied) {
|
|
- if(Verbose)
|
|
+ if(Verbose > 0)
|
|
fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
|
|
current);
|
|
return Exit_Version;
|
|
@@ -64,8 +66,14 @@
|
|
|
|
for(;;) {
|
|
Delete(md5);
|
|
+ Delete(name);
|
|
Delete(trash);
|
|
cnt = -1;
|
|
+ /* if a filter list is defined we assume that all pathnames require
|
|
+ an action opposite to that requested by the first filter in the
|
|
+ list.
|
|
+ If no filter is defined, all pathnames are assumed to match. */
|
|
+ match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
|
|
|
|
GETFIELD(p,' '); /* CTM_something */
|
|
|
|
@@ -92,31 +100,61 @@
|
|
sep = ' ';
|
|
else
|
|
sep = '\n';
|
|
- if(Verbose > 5)
|
|
- fprintf(stderr," %x(%d)",sp->List[i],sep);
|
|
+
|
|
+ if(Verbose > 5)
|
|
+ fprintf(stderr," %x(%d)",sp->List[i],sep);
|
|
|
|
switch (j & CTM_F_MASK) {
|
|
case CTM_F_Name: /* XXX check for garbage and .. */
|
|
- GETFIELD(p,sep);
|
|
- j = strlen(p);
|
|
- if(p[j-1] == '/' && !slashwarn) {
|
|
+ GETFIELDCOPY(name,sep);
|
|
+ j = strlen(name);
|
|
+ if(name[j-1] == '/' && !slashwarn) {
|
|
fprintf(stderr,"Warning: contains trailing slash\n");
|
|
slashwarn++;
|
|
}
|
|
- if (p[0] == '/') {
|
|
+ if (name[0] == '/') {
|
|
Fatal("Absolute paths are illegal.");
|
|
return Exit_Mess;
|
|
}
|
|
+ q = name;
|
|
for (;;) {
|
|
- if (p[0] == '.' && p[1] == '.')
|
|
- if (p[2] == '/' || p[2] == '\0') {
|
|
+ if (q[0] == '.' && q[1] == '.')
|
|
+ if (q[2] == '/' || q[2] == '\0') {
|
|
Fatal("Paths containing '..' are illegal.");
|
|
return Exit_Mess;
|
|
}
|
|
- if ((p = strchr(p, '/')) == NULL)
|
|
+ if ((q = strchr(q, '/')) == NULL)
|
|
break;
|
|
- p++;
|
|
+ q++;
|
|
+ }
|
|
+
|
|
+ /* if we have been asked to `keep' files then skip
|
|
+ removes; i.e. we don't match these entries at
|
|
+ all. */
|
|
+ if (KeepIt &&
|
|
+ (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
|
|
+ match = CTM_FILTER_DISABLE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* If filter expression have been defined, match the
|
|
+ path name against the expression list. */
|
|
+
|
|
+ if (FilterList) {
|
|
+ struct CTM_Filter *filter;
|
|
+
|
|
+ for (filter = FilterList; filter;
|
|
+ filter = filter->Next) {
|
|
+ if (0 == regexec(&filter->CompiledRegex, name,
|
|
+ 0, 0, 0))
|
|
+ /* if the name matches, adopt the
|
|
+ action */
|
|
+ match = filter->Action;
|
|
+ }
|
|
}
|
|
+
|
|
+ /* Add up the total number of matches */
|
|
+ total_matches += match;
|
|
break;
|
|
case CTM_F_Uid:
|
|
GETFIELD(p,sep);
|
|
@@ -170,22 +208,22 @@
|
|
p = MD5Data(trash,cnt,md5_1);
|
|
if(md5 && strcmp(md5,p)) {
|
|
Fatal("Internal MD5 failed.");
|
|
- return 1;
|
|
+ return Exit_Garbage;
|
|
default:
|
|
fprintf(stderr,"List = 0x%x\n",j);
|
|
Fatal("List had garbage.");
|
|
- return 1;
|
|
-
|
|
+ return Exit_Garbage;
|
|
}
|
|
-
|
|
- }
|
|
}
|
|
+ }
|
|
if(Verbose > 5)
|
|
putc('\n',stderr);
|
|
- continue;
|
|
+ if(ListIt && match)
|
|
+ printf("> %s %s\n", sp->Key, name);
|
|
}
|
|
|
|
Delete(md5);
|
|
+ Delete(name);
|
|
Delete(trash);
|
|
|
|
q = MD5End (&ctx,md5_1);
|
|
@@ -198,7 +236,7 @@
|
|
Fatal("MD5 sum doesn't match.");
|
|
fprintf(stderr,"\tI have:<%s>\n",q);
|
|
fprintf(stderr,"\tShould have been:<%s>\n",p);
|
|
- return 1;
|
|
+ return Exit_Garbage;
|
|
}
|
|
if (-1 != getc(fd)) {
|
|
if(!Force) {
|
|
@@ -206,5 +244,7 @@
|
|
return 16;
|
|
}
|
|
}
|
|
- return 0;
|
|
+ if ((Verbose > 1) && (0 == total_matches))
|
|
+ printf("No matches in \"%s\"\n", FileName);
|
|
+ return (total_matches ? Exit_OK : Exit_NoMatch);
|
|
}
|
|
diff -uNr ctm/ctm/ctm_pass2.c ../ctm/ctm/ctm_pass2.c
|
|
--- ctm/ctm/ctm_pass2.c Wed May 1 09:01:44 1996
|
|
+++ ../ctm/ctm/ctm_pass2.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.12 1996/04/29 21:02:30 phk Exp $
|
|
+ * $Id: ctm_pass2.c,v 1.2 1999/07/13 23:02:05 deraadt Exp $
|
|
*
|
|
*/
|
|
|
|
@@ -27,7 +27,10 @@
|
|
struct CTM_Syntax *sp;
|
|
struct stat st;
|
|
int ret = 0;
|
|
+ int match = 0;
|
|
char md5_1[33];
|
|
+ struct CTM_Filter *filter;
|
|
+ FILE *ed = NULL;
|
|
|
|
if(Verbose>3)
|
|
printf("Pass2 -- Checking if CTM-patch will apply\n");
|
|
@@ -49,6 +52,12 @@
|
|
Delete(md5);
|
|
cnt = -1;
|
|
|
|
+ /* if a filter list was specified, check file name against
|
|
+ the filters specified
|
|
+ if no filter was given operate on all files. */
|
|
+ match = (FilterList ?
|
|
+ !(FilterList->Action) : CTM_FILTER_ENABLE);
|
|
+
|
|
GETFIELD(p,' ');
|
|
|
|
if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
|
|
@@ -70,6 +79,22 @@
|
|
switch (j & CTM_F_MASK) {
|
|
case CTM_F_Name:
|
|
GETNAMECOPY(name,sep,j,0);
|
|
+ /* If `keep' was specified, we won't remove any files,
|
|
+ so don't check if the file exists */
|
|
+ if (KeepIt &&
|
|
+ (!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
|
|
+ match = CTM_FILTER_DISABLE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ for (filter = FilterList; filter; filter = filter->Next) if (0 == regexec(&filter->CompiledRegex, name,
|
|
+ 0, 0, 0)) {
|
|
+ match = filter->Action;
|
|
+ }
|
|
+
|
|
+ if (CTM_FILTER_DISABLE == match)
|
|
+ break; /* should ignore this file */
|
|
+
|
|
/* XXX Check DR DM rec's for parent-dir */
|
|
if(j & CTM_Q_Name_New) {
|
|
/* XXX Check DR FR rec's for item */
|
|
@@ -124,7 +149,7 @@
|
|
if(j & CTM_Q_MD5_Before) {
|
|
char *tmp;
|
|
GETFIELD(p,sep);
|
|
- if((st.st_mode & S_IFMT) == S_IFREG &&
|
|
+ if(match && (st.st_mode & S_IFMT) == S_IFREG &&
|
|
(tmp = MD5File(name,md5_1)) != NULL &&
|
|
strcmp(tmp,p)) {
|
|
fprintf(stderr," %s: %s md5 mismatch.\n",
|
|
@@ -154,6 +179,8 @@
|
|
case CTM_F_Bytes:
|
|
if(cnt < 0) WRONG
|
|
GETDATA(trash,cnt);
|
|
+ if (!match)
|
|
+ break;
|
|
if(!strcmp(sp->Key,"FN")) {
|
|
p = tempnam(TmpDir,"CTMclient");
|
|
j = ctm_edit(trash,cnt,name,p);
|
|
@@ -171,6 +198,30 @@
|
|
unlink(p);
|
|
Free(p);
|
|
return ret;
|
|
+ }
|
|
+ unlink(p);
|
|
+ Free(p);
|
|
+ } else if (!strcmp(sp->Key,"FE")) {
|
|
+ p = tempnam(TmpDir,"CTMclient");
|
|
+ ed = popen("ed","w");
|
|
+ if (!ed) {
|
|
+ WRONG
|
|
+ }
|
|
+ fprintf(ed,"e %s\n", name);
|
|
+ if (cnt != fwrite(trash,1,cnt,ed)) {
|
|
+ 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);
|
|
diff -uNr ctm/ctm/ctm_pass3.c ../ctm/ctm/ctm_pass3.c
|
|
--- ctm/ctm/ctm_pass3.c Wed May 1 09:01:44 1996
|
|
+++ ../ctm/ctm/ctm_pass3.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.13 1996/04/29 21:02:32 phk Exp $
|
|
+ * $Id: ctm_pass3.c,v 1.3 1999/07/13 23:02:05 deraadt Exp $
|
|
*
|
|
*/
|
|
|
|
@@ -22,7 +22,7 @@
|
|
{
|
|
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 @@
|
|
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);
|
|
@@ -139,10 +140,11 @@
|
|
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)
|
|
+ if(j & CTM_Q_MD5_Before) {
|
|
GETFIELDCOPY(md5before,sep);
|
|
- else
|
|
+ } else {
|
|
GETFIELDCOPY(md5,sep);
|
|
+ }
|
|
break;
|
|
case CTM_F_Count: GETBYTECNT(cnt,sep); break;
|
|
case CTM_F_Bytes: GETDATA(trash,cnt); break;
|
|
@@ -153,15 +155,35 @@
|
|
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);
|
|
@@ -180,13 +202,13 @@
|
|
}
|
|
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))) {
|
|
@@ -206,12 +228,13 @@
|
|
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;
|
|
}
|
|
@@ -228,7 +251,11 @@
|
|
continue;
|
|
}
|
|
if(!strcmp(sp->Key,"FR")) {
|
|
- if (0 != unlink(name)) {
|
|
+ if (KeepIt) {
|
|
+ if (Verbose > 1)
|
|
+ printf("<%s> not removed\n", name);
|
|
+ }
|
|
+ else if (0 != unlink(name)) {
|
|
fprintf(stderr,"<%s> unlink failed\n",name);
|
|
if (!Force)
|
|
WRONG
|
|
@@ -240,8 +267,14 @@
|
|
* We cannot use rmdir() because we do not get the directories
|
|
* in '-depth' order (cvs-cur.0018.gz for examples)
|
|
*/
|
|
- sprintf(buf,"rm -rf %s",name);
|
|
- system(buf);
|
|
+ if (KeepIt) {
|
|
+ if (Verbose > 1) {
|
|
+ printf("<%s> not removed\n", name);
|
|
+ }
|
|
+ } else {
|
|
+ sprintf(buf,"rm -rf %s",name);
|
|
+ system(buf);
|
|
+ }
|
|
continue;
|
|
}
|
|
WRONG
|
|
diff -uNr ctm/ctm/ctm_passb.c ../ctm/ctm/ctm_passb.c
|
|
--- ctm/ctm/ctm_passb.c Thu Jan 1 10:00:00 1970
|
|
+++ ../ctm/ctm/ctm_passb.c Wed Jul 14 09:02:05 1999
|
|
@@ -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 -uNr ctm/ctm/ctm_syntax.c ../ctm/ctm/ctm_syntax.c
|
|
--- ctm/ctm/ctm_syntax.c Tue Feb 6 02:06:55 1996
|
|
+++ ../ctm/ctm/ctm_syntax.c Wed Jul 14 09:02:05 1999
|
|
@@ -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.6 1996/02/05 16:06:55 phk Exp $
|
|
+ * $Id: ctm_syntax.c,v 1.2 1999/07/13 23:02:05 deraadt Exp $
|
|
*
|
|
*/
|
|
|
|
@@ -56,12 +56,12 @@
|
|
{ Name|Dir, 0 };
|
|
|
|
struct CTM_Syntax Syntax[] = {
|
|
- { "FM", ctmFM },
|
|
- { "FS", ctmFS },
|
|
- { "FE", ctmFE },
|
|
- { "FN", ctmFE },
|
|
- { "FR", ctmFR },
|
|
- { "AS", ctmAS },
|
|
- { "DM", ctmDM },
|
|
- { "DR", ctmDR },
|
|
- { 0, 0} };
|
|
+ { "FM", ctmFM },
|
|
+ { "FS", ctmFS },
|
|
+ { "FE", ctmFE },
|
|
+ { "FN", ctmFE },
|
|
+ { "FR", ctmFR },
|
|
+ { "AS", ctmAS },
|
|
+ { "DM", ctmDM },
|
|
+ { "DR", ctmDR },
|
|
+ { 0, 0} };
|
|
diff -uNr ctm/ctm_rmail/ctm_rmail.1 ../ctm/ctm_rmail/ctm_rmail.1
|
|
--- ctm/ctm_rmail/ctm_rmail.1 Wed May 1 09:01:45 1996
|
|
+++ ../ctm/ctm_rmail/ctm_rmail.1 Wed Jul 14 09:02:05 1999
|
|
@@ -9,17 +9,24 @@
|
|
.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
|
|
-.Nm ctm
|
|
+.Xr ctm 1
|
|
deltas via mail
|
|
.Sh SYNOPSIS
|
|
.Nm ctm_smail
|
|
.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
|
|
@@ -28,10 +35,11 @@
|
|
.Op Fl b Ar basedir
|
|
.Op Ar
|
|
.Sh DESCRIPTION
|
|
-In conjuction with the
|
|
+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 @@
|
|
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 @@
|
|
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 @@
|
|
.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
|
|
@@ -112,19 +164,18 @@
|
|
.Fl p
|
|
flag.
|
|
Deltas will not be applied if they do not match the
|
|
-.Li .ctm_status
|
|
+.Pa .ctm_status
|
|
file in
|
|
.Ar basedir
|
|
(or if
|
|
-.Li .ctm_status
|
|
+.Pa .ctm_status
|
|
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 @@
|
|
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 @@
|
|
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 @@
|
|
.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 @@
|
|
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
|
|
@@ -252,9 +307,9 @@
|
|
directories and
|
|
.Pa /ctm/log
|
|
file are writable by user
|
|
-.Em daemon
|
|
+.Dq daemon
|
|
or group
|
|
-.Em wheel ) :
|
|
+.Dq wheel ) :
|
|
.Bd -literal -offset indent
|
|
receiver-dude: "|ctm_rmail -p /ctm/tmp -d /ctm/deltas -l /ctm/log"
|
|
owner-receiver-dude: real_dude@wherever.you.like
|
|
@@ -265,11 +320,50 @@
|
|
.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
|
|
@@ -302,17 +396,21 @@
|
|
.Ev PATH .
|
|
.Sh FILES
|
|
.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.
|
|
.It Pa BASEDIR/.ctm_status
|
|
-File containing name and number of the next delta to be applied to this
|
|
+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 @@
|
|
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
|
|
@@ -359,10 +468,14 @@
|
|
.\" The next request is for sections 2 and 3 error and signal handling only.
|
|
.\" .Sh ERRORS
|
|
.Sh SEE ALSO
|
|
-.Xr ctm 1
|
|
-(coming soon)
|
|
+.Xr ctm 1 ,
|
|
+.Xr ctm 5
|
|
.\" .Sh STANDARDS
|
|
.\" .Sh HISTORY
|
|
.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 -uNr ctm/ctm_rmail/ctm_rmail.c ../ctm/ctm_rmail/ctm_rmail.c
|
|
--- ctm/ctm_rmail/ctm_rmail.c Wed May 1 09:01:45 1996
|
|
+++ ../ctm/ctm_rmail/ctm_rmail.c Wed Jul 14 09:02:06 1999
|
|
@@ -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
|
|
@@ -12,7 +13,7 @@
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
-#include <strings.h>
|
|
+#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
@@ -292,6 +293,7 @@
|
|
if (!decoding)
|
|
{
|
|
char *s;
|
|
+ int fd = -1;
|
|
|
|
if (sscanf(line, "CTM_MAIL BEGIN %s %d %d %c",
|
|
delta, &pce, &npieces, junk) != 3)
|
|
@@ -302,16 +304,16 @@
|
|
|
|
got_one++;
|
|
strcpy(tname, piece_dir);
|
|
- strcat(tname, "/p.XXXXXX");
|
|
- if (mktemp(tname) == NULL)
|
|
+ strcat(tname, "/p.XXXXXXXXXX");
|
|
+ if ((fd = mkstemp(tname)) == -1 ||
|
|
+ (ofp = fdopen(fd, "w")) == NULL)
|
|
{
|
|
- err("*mktemp: '%s'", tname);
|
|
- status++;
|
|
- continue;
|
|
- }
|
|
- if ((ofp = fopen(tname, "w")) == NULL)
|
|
- {
|
|
- err("cannot open '%s' for writing", tname);
|
|
+ if (fd != -1) {
|
|
+ err("cannot open '%s' for writing", tname);
|
|
+ close(fd);
|
|
+ }
|
|
+ else
|
|
+ err("*mkstemp: '%s'", tname);
|
|
status++;
|
|
continue;
|
|
}
|
|
@@ -494,17 +496,19 @@
|
|
FILE *dfp, *pfp;
|
|
int i, n, e;
|
|
char buf[BUFSIZ];
|
|
+ int fd = -1;
|
|
|
|
strcpy(tname, delta_dir);
|
|
- strcat(tname, "/d.XXXXXX");
|
|
- if (mktemp(tname) == NULL)
|
|
- {
|
|
- err("*mktemp: '%s'", tname);
|
|
- return 0;
|
|
- }
|
|
- if ((dfp = fopen(tname, "w")) == NULL)
|
|
- {
|
|
- err("cannot open '%s' for writing", tname);
|
|
+ strcat(tname, "/d.XXXXXXXXXX");
|
|
+ if ((fd = mkstemp(tname)) == -1 ||
|
|
+ (dfp = fdopen(fd, "w")) == NULL)
|
|
+ {
|
|
+ if (fd != -1) {
|
|
+ close(fd);
|
|
+ err("cannot open '%s' for writing", tname);
|
|
+ }
|
|
+ else
|
|
+ err("*mktemp: '%s'", tname);
|
|
return 0;
|
|
}
|
|
|