1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-30 16:51:41 +00:00

This commit was generated by cvs2svn to compensate for changes in r12750,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Peter Wemm 1995-12-10 22:31:43 +00:00
commit c294469919
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=12751
45 changed files with 16307 additions and 0 deletions

248
gnu/usr.bin/cvs/BUGS Normal file
View File

@ -0,0 +1,248 @@
* `cvs checkout -d nested/dir/path <module>' just doesn't work. The
simpler version -- `cvs checkout -d single-dir <module>' works,
however.
* CVS leaves .#mumble files around when a conflict occurs. (Note:
this is intentional and is documented in doc/cvs.texinfo. Of course
whether it is a good idea is a separate question).
* pcl-cvs doesn't like it when you try to check in a file which isn't
up-to-date. The messages produced by the server perhaps don't match
what pcl-cvs is looking for.
* From: Roland McGrath <roland@gnu.ai.mit.edu>
To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
Subject: weird bug
Date: Sat, 25 Mar 1995 16:41:41 -0500
X-Windows: Even your dog won't like it.
I just noticed some droppings on my disk from what must be a pretty weird
bug in remote CVS.
In my home directory on a repository machine I use, I find:
drwxr-xr-x 4 roland staff 512 Mar 7 14:08 cvs-serv28962
drwxr-xr-x 4 roland staff 512 Mar 7 14:11 cvs-serv28978
drwxr-xr-x 4 roland staff 512 Mar 7 15:13 cvs-serv29141
OK, so these are leftover cruft from some cvs run that got aborted.
Well, it should clean up after itself, but so what.
The last one is pretty dull; the real weirdness is the contents of the
first two directories.
duality 77 # ls -RF cvs-serv28978/
CVS/ cvs-serv28978/
cvs-serv28978/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978:
arpa/
cvs-serv28978/cvs-serv28978/arpa:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978:
assert/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978:
bare/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978:
conf/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978:
crypt/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978:
csu/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu:
CVS/ cvs-serv28978/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/CVS:
Entries Repository
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978:
ctype/
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype:
CVS/ cvs-serv28978/
[...]
ls: cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978/socket: File name too long
cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978:
* From: billr@mpd.tandem.com (Bill Robertson)
Subject: Problem with rtag and the -D option
Date: Fri, 17 Mar 1995 10:53:29 -0600 (CST)
I have been trying to use the -D option to specify a date for tagging, but
rtag does not recognize the -D option. It is documented to do so and I've
tested the use of -D with cvs update and cvs diff and it works fine there.
* We need some version numbers really badly. Are there some
(and Charles Hannum is just not including them in his reports), or do
we simply have no reliable way to distinguish between the various
versions of rCVS people on the list are running?
Now that I think of it, version numbers present a problem when
people can update their sources anytime and rebuild. I think the
solution is to increment a minor version number *every* time a bug is
fixed, so we can identify uniquely what someone is running when they
submit a report. This implies recording the version increments in the
ChangeLog; that way we can just look to see where a particular version
lies in relation to the flow of changing code.
Should we be doing same with Guppy? I guess not -- it's only
important when you have people who are updating directly from your
development tree, which is the case with the remote-cvs folks.
Thoughts?
* (Charles Hannum <mycroft@ai.mit.edu>) has these bugs:
I just tossed remote CVS at a fairly large source tree that I already
had, and noticed a few problems:
1) server.c assumes that /usr/tmp is a valid default for the place to
store files uploaded from the client. There are a number of systems
that now use /var/tmp. These should probably be detected by autoconf.
2) The server deals rather ungracefully with the tmp directory
becoming full.
3) There's some oddness with relative paths in Repository files that
causes the directory prefix to be added twice; e.g. if I have CVSROOT
set to `machine:/this/dir', and I try to update in a directory whose
Repository file says `src/bin', the server looks in
`/this/dir/machine:/this/dir/src/bin'.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: jimb@duality.gnu.ai.mit.edu, roland@duality.gnu.ai.mit.edu
Subject: Serious flaw in remote CVS
Date: Wed, 22 Feb 1995 20:54:36 -0500
I just found a major flaw in the current implementation. Because the
sockets are not changed to non-blocking mode, write(2)s can hang. In
some cases, this happens on both sides at the same time, with the
socket buffers full in both directions. This causes a deadlock,
because both processes are stuck in I/O wait and thus never drain
their input queues.
Until this is fixed, I can't use it. I'll look at the problem myself
at some point, but I don't know when.
From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Cc: jimb@totoro.bio.indiana.edu
Subject: Re: forwarded message from Charles M. Hannum
Date: Wed, 22 Feb 1995 22:07:07 -0500
FYI, this happened because the tmp directory on the server became
full. Somehow the server started interpreting the files the client
was sending as commands, and started spewing tons of errors.
Apparently the errors are sent with blocking I/O, or something, and
thus allowed the deadlock to happen.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Subject: Regarding that relative path problem
Date: Thu, 23 Feb 1995 02:41:51 -0500
This is actually more serious. If you have `bar.com:/foo' as your CVS
root directory, then:
1) When you check things out, the Repository files will contain
`/foo/...' (i.e. without the machine name), which makes little sense.
2) If you instead have a relative path, when the Repository file is
read, `bar.com:/foo' is prepended. This is sent to the server, but
confuses it, because it's not expecting the machine name to be
prepended.
A slightly klugy fix would be to have the client prepend the machine
name when writing a new Repository file, and strip it off before
sending one to the server. This would be backward-compatible with the
current arrangement.
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: remote-cvs@cyclic.com
Subject: Still one more bug
Date: Sat, 25 Feb 1995 17:01:15 -0500
mycroft@duality [1]; cd /usr/src/lib/libc
mycroft@duality [1]; cvs diff -c2 '-D1 day ago' -Dnow
cvs server: Diffing .
cvs server: Diffing DB
cvs [server aborted]: could not chdir to DB: No such file or directory
mycroft@duality [1];
`DB' is an old directory, which no longer has files in it, and is
removed automatically when I use the `-P' option to checkout.
This error doesn't occur when run locally.
P.S. Is anyone working on fixing these bugs?
* From: Roland McGrath <roland@gnu.ai.mit.edu>
To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com>
Subject: bizarre failure mode
Date: Tue, 7 Mar 95 14:17:28 -0500
This is pretty weird:
CVS_SERVER='TMPDIR=. /usr/local/bin/cvs' ../cvs-build/src/cvs update -q
cvs [server aborted]: could not get working directory: Result too large
[Exit 1]
asylum 29 % grep 'Result too large' /usr/include/sys/errno.h
#define ERANGE 34 /* Result too large */
Now, getcwd fails with ERANGE when the buffer is too small. But I don't
know why that would be the case; I don't think there are exceptionally long
directory names involved. It would be robust to notice ERANGE and use a
bigger buffer. But I suspect something weirder is going on.
The repository in question in duality.gnu.ai.mit.edu:/gd4/gnu/cvsroot/libc.
Send me a PGP-signed message if you want the password to use the machine
where the problem showed up.

356
gnu/usr.bin/cvs/INSTALL Normal file
View File

@ -0,0 +1,356 @@
#ident "$CVSid$"
First, read the README file. If you're still happy...
CVS has been tested on the following platforms. The most recent
version of CVS reported to have been tested is indicated, but more
recent versions of CVS probably will work too. Please send updates to
this list to info-cvs@prep.ai.mit.edu.
Alpha:
DEC Alpha running OSF/1 version 1.3 using cc (about 1.4A2)
DEC Alpha running OSF/1 version 2.0 (1.4.90)
DEC Alpha running OSF/1 version 2.1 (about 1.4A2)
DEC Alpha running OSF/1 version 3.0 (1.5.95) (footnote 7)
HPPA:
HP 9000/710 running HP-UX 8.07A using gcc (about 1.4A2)
HP 9000/715 running HP-UX 9.01 (1.6)
HPPA 1.1 running HP-UX A.09.03 (1.5.95) (footnote 8)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
i386 family:
Gateway P5-66 (pentium) running Solaris 2.4 using gcc (about 1.4A2)
PC Clone running UnixWare v1.1.1 using gcc (about 1.4A2)
PC Clone running ISC 4.0.1 (1.5.94)
PC Clone running Fintronic Linux 1.2.5 (1.5)
PC Clone running BSDI 2.0 (1.4.93) (footnote 5)
PC Clone running Windows NT 3.51 (1.6.2 client-only)
FreeBSD 2.0.5, i486, gcc (1.5.95)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
SCO Unix 3.2.4.2 (1.4.93) (footnote 4)
SCO OpenServer 5.0.0, "CC='cc -b elf' configure"
m68k:
Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.6)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
m88k:
Data General AViiON running dgux 5.4R2.10 (1.5)
Harris Nighthawk 5800 running CX/UX 7.1 (1.5) (footnote 6)
MIPS:
DECstation running Ultrix 4.2a (1.4.90)
DECstation running Ultrix 4.3 (1.5)
SGI running Irix 4.0.5H using gcc and cc (about 1.4A2) (footnote 2)
SGI running Irix 5.3 (1.4.93)
SGI running Irix-6 (about 1.4.90) (footnote 3)
Siemens-Nixdorf RM600 running SINIX-Y (1.6)
PowerPC or RS/6000:
IBM RS/6000 running AIX 3.2.5 (cc=xlc, CVS 1.5)
IBM RS/6000 running AIX 4.1 using gcc and cc (about 1.4A2) (footnote 1)
SPARC:
Sun SPARC running SunOS 4.1.4 w/ bundled K&R /usr/5bin/cc (1.6)
Sun SPARC running SunOS 4.1.3, 4.1.2, and 4.1.1 (1.5)
Sun SPARC running SunOS 4.1.3, w/ bundled K&R cc (1.5.94)
Sun SPARCstation 10 running Solaris 2.3 using gcc and cc (about 1.4A2)
Sun SPARCstation running Solaris 2.4 using gcc and cc (about 1.5.91)
Sun SPARC running Solaris 2.5 (2.5 beta?) (1.6.2)
NextSTEP 3.3 (1.4.92, a few tweaks needed)
(footnote 1)
AIX 4.1 systems fail to run "configure" due to bugs in their
"/bin/sh" implementation. You might want to try feeding the
configure script to "bash" ported to AIX 4.1. (about 1.4A2).
(footnote 2)
Some Irix 4.0 systems may core dump in malloc while running
CVS. We believe this is a bug in the Irix malloc. You can
workaround this bug by linking with "-lmalloc" if necessary.
(about 1.4A2).
(footnote 3)
There are some warnings about pointer casts which can safely be
ignored. (about 1.4.90).
(footnote 4) Comment out the include of sys/time.h in src/server.c. (1.4.93)
You also may have to make sure TIME_WITH_SYS_TIME is undef'ed.
(footnote 5) Change /usr/tmp to /var/tmp in src/server.c (2 places) (1.4.93).
(footnote 6) Build in ucb universe with COFF compiler tools. Put
/usr/local/bin first in PATH while doing a configure, make
and install of GNU diffutils-2.7, rcs-5.7, then cvs-1.5.
(footnote 7) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
success with this configure command:
CC=cc CFLAGS='-O2 -Olimit 2000 -std1' ./configure --verbose alpha-dec-osf
(footnote 8) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports
success with this configure command:
CC=cc CFLAGS='+O2 -Aa -D_HPUX_SOURCE' ./configure --verbose hppa1.1-hp-hpux
-------------------------------------------------------------------------------
Installation under Unix:
1) Run "configure":
$ ./configure
You can specify an alternate destination to override the default with
the --prefix option:
$ ./configure --prefix=/usr/local/gnu
or some path that is more appropriate for your site. The default prefix
value is "/usr/local", with binaries in sub-directory "bin", manual
pages in sub-directory "man", and libraries in sub-directory "lib".
This release of CVS also requires RCS commands to be installed in
the user's PATH (or a path you have configured in src/options.h).
If you don't have RCS, you will need to get it from GNU as well. It
is best to get the version 5.7 (or later) version of RCS, available
from prep.ai.mit.edu in the file pub/gnu/rcs-5.7.tar.gz. It is best
(although not essential) to avoid RCS versions 5.6.[5-7] beta
because the rcsmerge therein defaults to -A instead of -E which
affects the way CVS handles conflicts (this is fixed in RCS 5.6.8
and RCS 5.7).
Along with RCS, you will want to run GNU diffutils. This will allow
revision control of files with binary data (a real nice feature).
You will need at least version 1.15 of GNU diff for this to work.
The current version of GNU diffutils is 2.7, and it is also
available from prep.ai.mit.edu in the file pub/gnu/diffutils-2.7.tar.gz.
WARNING: Be sure that you (have) configure(d) RCS to work correctly
with GNU diff to avoid other configuration problems.
Configure will attempt to discern the location of your most capable
version of diff, and tries to find the GNU Diffutils version first.
You can explicitly tell configure to use the diffutils that's
installed in the same place you intend to install CVS:
$ ./configure --with-diffutils
Or, if you've installed it somewhere else, you can give configure
the full pathname:
$ ./configure --with-diffutils=/usr/gnu/bin/diff
Configure will also try to find a version of grep that supports the
'-s' option, and tries to find the GNU Grep version first. You can
similarly tell it where to find GNU Grep:
$ ./configure --with-gnugrep
$ ./configure --with-gnugrep=/usr/gnu/bin/grep
If you are using the remote client, you will need a version of patch
which understands unidiffs (such as any recent version of GNU
patch). Configure does not yet check to see if you've got this, so
be careful!
NOTE: The configure program will cache the results of the previous
configure execution. If you need to re-run configure from scratch, you
may need to run "make distclean" first to remove the cached
configuration information.
Try './configure --help' for further information on its usage.
NOTE ON CVS's USE OF NDBM:
By default, CVS uses some built-in ndbm emulation code to allow
CVS to work in a heterogeneous environment. However, if you have
a very large modules database, this may not work well. You will
need to edit src/options.h to turn off the MY_NDBM #define and
re-run configure. If you do this, the following comments apply.
If not, you may safely skip these comments.
If you configure CVS to use the real ndbm(3) libraries and
you do not have them installed in a "normal" place, you will
probably want to get the GNU version of ndbm (gdbm) and install
that before running the CVS configure script. Be aware that the
GDBM 1.5 release does NOT install the <ndbm.h> header file included
with the release automatically. You may have to install it by hand.
If you configure CVS to use the ndbm(3) libraries, you cannot
compile CVS with GNU cc (gcc) on Sun-4 SPARC systems. However, gcc
2.0 may have fixed this limitation if -fpcc-struct-return is
defined. When using gcc on other systems to compile CVS, you *may*
need to specify the -fpcc-struct-return option to gcc (you will
*know* you have to if "cvs checkout" core dumps in some ndbm
function). You can do this as follows:
$ CC='gcc -fpcc-struct-return' ./configure
for sh, bash, and ksh users and:
% setenv CC 'gcc -fpcc-struct-return'
% ./configure
for csh and tcsh users.
END OF NOTE FOR NDBM GUNK.
2) Edit src/options.h. Appropriate things to look at may be the
invocation locations of programs like DIFF, GREP, RM, and SORT.
Also glance at the default values for the environment variables
that CVS uses, in particular, the RCSBIN variable, which holds the
path to where the RCS programs live on your system. The
likelihood is that you don't have to change anything here, except
perhaps adding the -a option to DIFF if you are using GNU diff.
3) Try to build it:
$ make
This will (hopefully) make the needed CVS binaries within the "src"
directory. If something fails for your system, using the "cvsbug"
script submit your "config.status" file together with your host
type, operating system and compiler information, make output, and
anything else you think will be helpful.
You may also wish to validate the correctness of the new binary by
running the regression tests:
$ make check
Note that if your /bin/sh doesn't support shell functions, you'll
have to try something like this, where "/bin/sh5" is replaced by the
pathname of a shell which handles normal shell functions:
$ make SHELL=/bin/sh5 check
WARNING: This test can take quite a while to run, esp. if your
disks are slow or over-loaded.
If you receive any un-expected output from the regression tests,
using the "cvsbug" script please submit your "config.status" file,
together with your host type, operating system and compiler
information, the contents of /tmp/cvs-sanity/check.log, and any
"make check" output.
4) Install the binaries/documentation:
$ make install
Depending on your installation's configuration, you may need to be
root to do this.
5) Take a look at the CVS documentation.
$ man cvs
and
$ info cvs
See what it can do for you, and if it fits your environment (or can
possibly be made to fit your environment). If things look good,
continue on...
6) Setup the master source repository. Choose a directory with ample disk
space available for source files. This is where the RCS ",v" files
will be stored. Note that this should be some shared directory for your
site. It should probably be auto-mounted, if you're running NFS.
Say you choose "/src/master" as the root of your source repository.
Run the "cvsinit" script to help you set it up. It will ask you to
enter the path to your CVSROOT area. You would enter /src/master in
this example.
$ ./cvsinit
The cvsinit script will setup a reasonable CVSROOT area to start with.
It is also valuable to folks who already have a CVSROOT area setup from
using earlier releases of CVS. It assumes that you have installed CVS
already (step 4) and that the RCS programs (co and ci) are in your
PATH. There are many ways to customize CVS for your site. Read the
cvs(5) manual page when you get the chance.
7) Have all users of the CVS system set the CVSROOT environment
variable appropriately to reflect the placement of your source
repository. If the above example is used, the following commands
can be placed in user's ~/.profile, ~/.bash_profile file; or in the
site-wide /etc/profile:
CVSROOT=/src/master; export CVSROOT
for sh/bash/ksh users, or place the following commands in the user's
~/.cshrc, ~/.login, or /etc/chsrc file:
setenv CVSROOT /src/master
for csh/tcsh users. If these environment variables are not already set
in your current shell, set them now (or source the login script you
just edited). You will need to have the CVSROOT environment variable
set to continue on to the next step.
8) It might be a good idea to jump right in and put the CVS distribution
directly under CVS control. From within the top-level directory of the
CVS distribution (the one that contains this README file) do the
following commands:
$ make distclean
$ cvs import -m 'CVS 1.6 distribution' cvs CVS CVS-1_6
9) Having done step 8, one should be able to checkout a fresh copy of the
CVS distribution and hack away at the sources with the following command:
$ cd
$ cvs checkout cvs
This will make the directory "cvs" in your current directory and
populate it with the appropriate CVS files and directories.
10) Remember to edit the modules file manually when sources are checked in
with "cvs import" or "cvs add". A copy of the modules file for editing
can usually be retrieved with the "cvs checkout modules" command, and
definitely with the "cvs checkout CVSROOT" command. See cvs(5).
11) Read the NEWS file to see what's new.
12) Hack away.
-------------------------------------------------------------------------------
Detailed information about your interaction with "configure":
The "configure" script and its interaction with its options and the
environment is described here. For more detailed documentation about
"configure", please refer to the GNU Autoconf documentation.
Supported options are:
--srcdir=DIR Useful for compiling on many different
machines sharing one source tree.
--prefix=DIR The root of where to install the
various pieces of CVS (/usr/local).
--exec_prefix=DIR If you want executables in a
host-dependent place and shared
things in a host-independent place.
--with-diffutils[=PATH] Assume use of GNU diffutils is possible.
--with-gnugrep[=PATH] Assume use of GNU grep is possible.
The following environment variables override configure's default
behaviour:
CC If not set, tries to use gcc first,
then cc. Also tries to use "-g -O"
as options, backing down to -g
alone if that doesn't work.
INSTALL If not set, tries to use "install", then
"./install-sh" as a final choice.
RANLIB If not set, tries to determine if "ranlib"
is available, choosing "echo" if it doesn't
appear to be.
YACC If not set, tries to determine if "bison"
is available, choosing "yacc" if it doesn't
appear to be.
-------------------------------------------------------------------------------
Installation under Windows NT:
You may find interesting information in windows-NT/README.
1) Using Microsoft Visual C++ version 2.1, open the project `cvsnt.mak',
in the top directory of the CVS distribution.
2) Choose "Build cvs.exe" from the "Project" menu.
3) MSVC will place the executable file cvs.exe in WinDebug, or whatever
your target directory is.
-------------------------------------------------------------------------------

View File

@ -0,0 +1,60 @@
Low-priority bugs go here. We don't have many yet -- everything is
high-priority at the moment. :-)
* From: Jeff Johnson <jbj@brewster.JBJ.ORG>
To: cyclic-cvs@cyclic.com
Subject: Named_Root assumes . on server
Date: Wed, 17 May 1995 11:04:53 -0400 (EDT)
Problem:
On server, Name_Root() attempts (aggressively) to set CVSADM_Root.
If ~/CVS/Root exists (wrto rsh login), then CVSADM_Root will be
initialized from that file. The sanity check between the root
repository and the invocation will fail if the two values are not
coincidentally the same.
Workaround:
There's a zillion ways to fix this bugture/featurelet. My current
workaround is to remove ~/CVS/Root on the server. I shall attempt
a better fix as soon as I can determine what appears politically
correct. IMHO, the CVS/Root stuff (and getenv("CVSROOT") also) is
a bit fragile and tedious in an rcmd() driven CCVS environment.
* (Jeff Johnson <jbj@jbj.org>)
I tried a "cvs status -v" and received the following:
? CVS
? programs/CVS
? tests/CVS
cvs server: Examining .
===================================================================
File: Install.dec Status: Up-to-date
...
I claim that CVS dirs should be ignored.
* I sometimes get this message:
Could not look up address for your host. Permission denied.
cvs [update aborted]: premature end of file from server
The client's response should be cleaned up.
* In the gb-grep module, update-ChangeLog (and therefore, I assume,
rcs2log) truncates file names --- I get entries for things called
ring/lenstring.h instead of lenstring/lenstring.h.
* On remote checkout, files don't have the right time/date stamps in
the CVS/Entries files. Doesn't look like the C/S protocol has any
way to send this information along (according to cvsclient.texi).
Perhaps we can spiff it up a bit by using the conflict field for the
stamp on the checkout/update command. Please note that this really
doesn't do very much for us even if we get it done.
* Does the function that lists the available modules in the repository
belong under the "checkout" function? Perhaps it is more logically
grouped with the "history" function or we should create a new "info"
function?

863
gnu/usr.bin/cvs/NEWS Normal file
View File

@ -0,0 +1,863 @@
Changes since 1.6:
* RCS keyword "Name" supported for "cvs update -r <tag>" and "cvs
checkout -r <tag>".
* If there is a group whose name matches a compiled in value which
defaults to "cvsadmin", only members of that group can use "cvs
admin".
* CVS now sets the modes of files in the repository based on the
CVSUMASK environment variable or a compiled in value defaulting to
002. This way other developers will be able to access the files in
the repository regardless of the umask of the developer creating them.
* The command name .cvsrc now matches the official name of the
command, not the one (possibly an alias) by which it was invoked. If
you had previously relied on "cvs di" and "cvs diff" using different
options, instead use a shell function or alias (for example "alias
cvsdi='cvs diff -u'").
Changes from 1.5 to 1.6:
* Del updated the man page to include all of the new features
of CVS 1.6.
* "cvs tag" now supports a "-r | -D" option for tagging an already
tagged revision / specific revision of a file.
* There is a "taginfo" file in CVSROOT that supports filtering and
recording of tag operations.
* Long options support added, including --help and --version options.
* "cvs release" no longer cares whether or not the directory being
released has an entry in the `modules' file.
* The modules file now takes a -e option which is used instead of -o
for "cvs export". If your modules file has a -o option which you want
to be used for "cvs export", change it to specify -e as well as -o.
* "cvs export" now takes a -k option to set RCS keyword expansion.
This way you can export binary files. If you want the old behavior,
you need to specify -kv.
* "cvs update", "cvs rdiff", "cvs checkout", "cvs import", "cvs
release", "cvs rtag", and "cvs tag" used to take -q and -Q options
after the command name (e.g. "cvs update -q"). This was confusing
because other commands, such as "cvs ci", did not. So the options
after the command name have been removed and you must now specify, for
example, "cvs -q update", which has been supported since CVS 1.3.
* New "wrappers" feature. This allows you to set a hook which
transforms files on their way in and out of cvs (apparently on the
NeXT there is some particular usefulness in tarring things up in the
repository). It also allows you to declare files as merge-by-copy
which means that instead of trying to merge the file, CVS will merely
copy the new version. There is a CVSROOT/cvswrappers file and an
optionsl ~/.cvswrappers file to support this feature.
* You can set CVSROOT to user@host:dir, not just host:dir, if your
username on the server host is different than on the client host.
* VISUAL is accepted as well as EDITOR.
* $CVSROOT is expanded in *info files.
Changes from 1.4A2 to 1.5:
* Remote implementation. This is very helpful when collaborating on a
project with someone across a wide-area network. This release can
also be used locally, like other CVS versions, if you have no need for
remote access.
Here are some of the features of the remote implementation:
- It uses reliable transport protocols (TCP/IP) for remote repository
access, not NFS. NFS is unusable over long distances (and sometimes
over short distances)
- It transfers only those files that have changed in the repository or
the working directory. To save transmission time, it will transfer
patches when appropriate, and can compress data for transmission.
- The server never holds CVS locks while waiting for a reply from the client;
this makes the system robust when used over flaky networks.
The remote features are documented in doc/cvsclient.texi in the CVS
distribution, but the main doc file, cvs.texinfo, has not yet been
updated to include the remote features.
* Death support. See src/README-rm-add for more information on this.
* Many speedups, especially from jtc@cygnus.com.
* CVS 1.2 compatibility code has been removed as a speedup. If you
have working directories checked out by CVS 1.2, CVS 1.3 or 1.4A2 will
try to convert them, but CVS 1.5 and later will not (if the working
directory is up to date and contains no extraneous files, you can just
remove it, and then check out a new working directory). Likewise if
your repository contains a CVSROOT.adm directory instead of a CVSROOT
directory, you need to rename it.
Fri Oct 21 20:58:54 1994 Brian Berliner <berliner@sun.com>
* Changes between CVS 1.3 and CVS 1.4 Alpha-2
* A new program, "cvsbug", is provided to let you send bug reports
directly to the CVS maintainers. Please use it instead of sending
mail to the info-cvs mailing list. If your build fails, you may
have to invoke "cvsbug" directly from the "src" directory as
"src/cvsbug.sh".
* A new User's Guide and Tutorial, written by Per Cederqvist
<ceder@signum.se> of Signum Support. See the "doc" directory. A
PostScript version is included as "doc/cvs.ps".
* The Frequesntly Asked Questions file, FAQ, has been added to the
release. Unfortunately, its contents are likely out-of-date.
* The "cvsinit" shell script is now installed in the $prefix/bin
directory like the other programs. You can now create new
CVS repositories with great ease.
* Index: lines are now printed on output from 'diff' and 'rdiff',
in order to facilitate application of patches to multiple subdirs.
* Support for a ~/.cvsrc file, which allows you to specify options
that are always supposed to be given to a specific command. This
feature shows the non-orthogonality of the option set, since while
there may be an option to turn something on, the option to turn
that same thing off may not exist.
* You can now list subdirectories that you wish to ignore in a
modules listing, such as:
gcc -a gnu/gcc, !gnu/gcc/testsuites
which will check out everything underneath gnu/gcc, except
everything underneath gnu/gcc/testsuites.
* It is now much harder to accidentally overwrite an existing tag
name, since attempting to move a tag name will result in a error,
unless the -F (force) flag is given to the tag subcommands.
* Better error checking on matching of the repository used to
check code out from against the repository the current cvs
commnands would use. (Thanks to Mark Baushke <mdb@cisco.com>)
* Better support for sites with multiple CVSROOT repositories has
been contributed. The file "CVS/Root" in your working directory
is created to hold the full path to the CVS repository and a
simple check is made against your current CVSROOT setting.
* You can now specify an RCS keyword substitution value when you
import files into the repository.
* Uses a much newer version of Autoconf, and conforms to the GNU
coding standards much more closely. No, it still doesn't have
long option names.
* Code cleanup. Many passes through gcc -Wall helped to identify
a number of questionable constructs. Most arbitrary length limits
were removed.
* Profiling to determine bottlenecks helped to identify the best
places to spend time speeding up the code, which was then done. A
number of performance enhancements in filename matching have sped
up checkouts.
* Many more contributions have been added to the "contrib"
directory. See the README file in that directory for more
information.
* "cvs commit" will try harder to not change the file's
modification time after the commit. If the file does not change
as a result of the commit operation, CVS will preserve the
original modification time, thus speeding up future make-type
builds.
* "cvs commit" now includes any removed files in the (optional)
pre-commit checking program that may be invoked. Previously, only
added and modified files were included.
* It is now possible to commit a file directly onto the trunk at a
specific revision level by doing "cvs commit -r3.0 file.c", where
"3.0" specifies the revision you wish to create. The file must be
up-to-date with the current head of the trunk for this to succeed.
* "cvs commit" will now function with a pre-commit program that
has arguments specified in the "commitinfo" file.
* The "mkmodules" program will now look within the
$CVSROOT/CVSROOT/checkoutlist" file for any additional files that
should be automatically checked out within CVSROOT; mkmodules also
tries harder to preserve any execute bits the files may have
originally had.
* "cvs diff" is much more accurate about its exit status now. It
now returns the maximum exit status of any invoked diff.
* The "-I !" option is now supported for the import and update
commands correctly. It will properly clear the ignore list now.
* Some problems with "cvs import" handling of .cvsignore have been
fixed; as well, some rampant recursion problems with import have
also been fixed.
* "cvs rdiff" (aka "cvs patch") now tries to set the modify time
of any temporary files it uses to match those specified for the
particular revision. This allows a more accurate patch image to
be created.
* "cvs status" has improved revision descriptions. "Working
revision" is used for the revision of the working file that you
edit directly; "Repository revision" is the revision of the file
with the $CVSROOT source repository. Also, the output is clearer
with regard to sticky and branch revisions.
* CVS no longer dumps core when given a mixture of directories and
files in sub-directories (as in "cvs ci file1 dir1/file2").
Instead, arguments are now clumped into their respective directory
and operated on in chunks, together.
* If the CVSEDITOR environment variable is set, that editor is
used for log messages instead of the EDITOR environment variable.
This makes it easy to substitute intelligent programs to make more
elaborate log messages. Contributed by Mark D Baushke
(mdb@cisco.com).
* Command argument changes:
cvs: The "-f" option has been added to ignore
the ~/.cvsrc file.
commit: Renamed the "-f logfile" option to the
"-F logfile" option. Added the "-f"
option to force a commit of the specified
files (this disables recursion).
history: Added "-t timezone" option to force any
date-specific output into the specified
timezone.
import: Added "-d" option to use the file's
modification time as the time of the
import. Added "-k sub" option to set the
default RCS keyword substitution mode for
newly-created files.
remove: Added "-f" option to force the file's
automatic removal if it still exists in
the working directory (use with caution).
rtag: Added "-F" option to move the tag if it
already exists -- new default is to NOT
move tags automatically.
tag: Added "-F" option to move the tag if it
already exists -- new default is to NOT
move tags automatically.
Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.3 Beta-3 and official CVS 1.3!
* A new shell script is provided, "./cvsinit", which can be run at
install time to help setup your $CVSROOT area. This can greatly
ease your entry into CVS usage.
* The INSTALL file has been updated to include the machines on
which CVS has compiled successfully. I think CVS 1.3 is finally
portable. Thanks to all the Beta testers!
* Support for the "editinfo" file was contributed. This file
(located in $CVSROOT/CVSROOT) can be used to specify a special
"editor" to run on a per-directory basis within the repository,
instead of the usual user's editor. As such, it can verify that
the log message entered by the user is of the appropriate form
(contains a bugid and test validation, for example).
* The manual pages cvs(1) and cvs(5) have been updated.
* The "mkmodules" command now informs you when your modules file
has duplicate entries.
* The "add" command now preserves any per-directory sticky tag when
you add a new directory to your checked-out sources.
* The "admin" command is now a fully recursive interface to the
"rcs" program which operates on your checked-out sources. It no
longer requires you to specify the full path to the RCS file.
* The per-file sticky tags can now be effectively removed with
"cvs update -A file", even if you had checked out the whole
directory with a per-directory sticky tag. This allows a great
deal of flexibility in managing the revisions that your checked-out
sources are based upon (both per-directory and per-file sticky
tags).
* The "cvs -n commit" command now works, to show which files are
out-of-date and will cause the real commit to fail, or which files
will fail any pre-commit checks. Also, the "cvs -n import ..."
command will now show you what it would've done without actually
doing it.
* Doing "cvs commit modules" to checkin the modules file will no
properly run the "mkmodules" program (assuming you have setup your
$CVSROOT/CVSROOT/modules file to do so).
* The -t option in the modules file (which specifies a program to
run when you do a "cvs rtag" operation on a module) now gets the
symbolic tag as the second argument when invoked.
* When the source repository is locked by another user, that user's
login name will be displayed as the holder of the lock.
* Doing "cvs checkout module/file.c" now works even if
module/file.c is in the Attic (has been removed from main-line
development).
* Doing "cvs commit */Makefile" now works as one would expect.
Rather than trying to commit everything recursively, it will now
commit just the files specified.
* The "cvs remove" command is now fully recursive. To schedule a
file for removal, all you have to do is "rm file" and "cvs rm".
With no arguments, "cvs rm" will schedule all files that have been
physically removed for removal from the source repository at the
next "cvs commit".
* The "cvs tag" command now prints "T file" for each file that was
tagged by this invocation and "D file" for each file that had the
tag removed (as with "cvs tag -d").
* The -a option has been added to "cvs rtag" to force it to clean
up any old, matching tags for files that have been removed (in the
Attic) that may not have been touched by this tag operation. This
can help keep a consistent view with your tag, even if you re-use
it frequently.
Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3
* Many portability fixes, thanks to all the Beta testers! With any
luck, this Beta release will compile correctly on most anything.
Hey, what are we without our dreams.
* CVS finally has support for doing isolated development on a
branch off the current (or previous!) revisions. This is also
extremely nice for generating patches for previously released
software while development is progressing on the next release.
Here's an example of creating a branch to fix a patch with the 2.0
version of the "foo" module, even though we are already well into
the 3.0 release. Do:
% cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo
% cvs checkout -rFOO_2_0_Patch foo
% cd foo
[[ hack away ]]
% cvs commit
A physical branch will be created in the RCS file only when you
actually commit the change. As such, forking development at some
random point in time is extremely light-weight -- requiring just a
symbolic tag in each file until a commit is done. To fork
development at the currently checked out sources, do:
% cvs tag -b Personal_Hack
% cvs update -rPersonal_Hack
[[ hack away ]]
% cvs commit
Now, if you decide you want the changes made in the Personal_Hack
branch to be merged in with other changes made in the main-line
development, you could do:
% cvs commit # to make Personal_Hack complete
% cvs update -A # to update sources to main-line
% cvs update -jPersonal_Hack # to merge Personal_Hack
to update your checked-out sources, or:
% cvs checkout -jPersonal_Hack module
to checkout a fresh copy.
To support this notion of forked development, CVS reserves
all even-numbered branches for its own use. In addition, CVS
reserves the ".0" and ".1" branches. So, if you intend to do your
own branches by hand with RCS, you should use odd-numbered branches
starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", ....
* The "cvs commit" command now supports a fully functional -r
option, allowing you to commit your changes to a specific numeric
revision or symbolic tag with full consistency checks. Numeric
tags are useful for bringing your sources all up to some revision
level:
% cvs commit -r2.0
For symbolic tags, you can only commit to a tag that references a
branch in the RCS file. One created by "cvs rtag -b" or from
"cvs tag -b" is appropriate (see below).
* Roland Pesch <pesch@cygnus.com> and K. Richard Pixley
<rich@cygnus.com> were kind enough to contribute two new manual
pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features
are now documented, with the exception of the new branch support
added to commit/rtag/tag/checkout/update.
* The -j options of checkout/update have been added. The "cvs join"
command has been removed.
With one -j option, CVS will merge the changes made between the
resulting revision and the revision that it is based on (e.g., if
the tag refers to a branch, CVS will merge all changes made in
that branch into your working file).
With two -j options, CVS will merge in the changes between the two
respective revisions. This can be used to "remove" a certain delta
from your working file. E.g., If the file foo.c is based on
revision 1.6 and I want to remove the changes made between 1.3 and
1.5, I might do:
% cvs update -j1.5 -j1.3 foo.c # note the order...
In addition, each -j option can contain on optional date
specification which, when used with branches, can limit the chosen
revision to one within a specific date. An optional date is
specified by adding a colon (:) to the tag, as in:
-jSymbolic_Tag:Date_Specifier
An example might be what "cvs import" tells you to do when you have
just imported sources that have conflicts with local changes:
% cvs checkout -jTAG:yesterday -jTAG module
which tells CVS to merge in the changes made to the branch
specified by TAG in the last 24 hours. If this is not what is
intended, substitute "yesterday" for whatever format of date that
is appropriate, like:
% cvs checkout -jTAG:'1 week ago' -jTAG module
* "cvs diff" now supports the special tags "BASE" and "HEAD". So,
the command:
% cvs diff -u -rBASE -rHEAD
will effectively show the changes made by others (in unidiff
format) that will be merged into your working sources with your
next "cvs update" command. "-rBASE" resolves to the revision that
your working file is based on. "-rHEAD" resolves to the current
head of the branch or trunk that you are working on.
* The -P option of "cvs checkout" now means to Prune empty
directories, as with "update". The default is to not remove empty
directories. However, if you do "checkout" with any -r options, -P
will be implied. I.e., checking out with a tag will cause empty
directories to be pruned automatically.
* The new file INSTALL describes how to install CVS, including
detailed descriptions of interfaces to "configure".
* The example loginfo file in examples/loginfo has been updated to
use the perl script included in contrib/log.pl. The nice thing
about this log program is that it records the revision numbers of
your change in the log message.
Example files for commitinfo and rcsinfo are now included in the
examples directory.
* All "#if defined(__STDC__) && __STDC__ == 1" lines have been
changed to be "#if __STDC__" to fix some problems with the former.
* The lib/regex.[ch] files have been updated to the 1.3 release of
the GNU regex package.
* The ndbm emulation routines included with CVS 1.3 Beta-2 in the
src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files
to avoid any conflict with the system <ndbm.h> header file. If
you had a previous CVS 1.3 Beta release, you will want to "cvs
remove ndbm.[ch]" form your copy of CVS as well.
* "cvs add" and "cvs remove" are a bit more verbose, telling you
what to do to add/remove your file permanently.
* We no longer mess with /dev/tty in "commit" and "add".
* More things are quiet with the -Q option set.
* New src/config.h option: If CVS_BADROOT is set, CVS will not
allow people really logged in as "root" to commit changes.
* "cvs diff" exits with a status of 0 if there were no diffs, 1 if
there were diffs, and 2 if there were errors.
* "cvs -n diff" is now supported so that you can still run diffs
even while in the middle of committing files.
* Handling of the CVS/Entries file is now much more robust.
* The default file ignore list now includes "*.so".
* "cvs import" did not expand '@' in the log message correctly. It
does now. Also, import now uses the ignore file facility
correctly.
Import will now tell you whether there were conflicts that need to
be resolved, and how to resolve them.
* "cvs log" has been changed so that you can "log" things that are
not a part of the current release (in the Attic).
* If you don't change the editor message on commit, CVS now prompts
you with the choice:
!)reuse this message unchanged for remaining dirs
which allows you to tell CVS that you have no intention of changing
the log message for the remainder of the commit.
* It is no longer necessary to have CVSROOT set if you are using
the -H option to get Usage information on the commands.
* Command argument changes:
checkout: -P handling changed as described above.
New -j option (up to 2 can be specified)
for doing rcsmerge kind of things on
checkout.
commit: -r option now supports committing to a
numeric or symbolic tags, with some
restrictions. Full consistency checks will
be done.
Added "-f logfile" option, which tells
commit to glean the log message from the
specified file, rather than invoking the
editor.
rtag: Added -b option to create a branch tag,
useful for creating a patch for a previous
release, or for forking development.
tag: Added -b option to create a branch tag,
useful for creating a patch for a previous
release, or for forking development.
update: New -j option (up to 2 can be specified)
for doing rcsmerge kind of things on
update.
Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM)
* Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2
* Thanks to K. Richard Pixley at Cygnus we now have function
prototypes in all the files
* Some small changes to configure for portability. There have
been other portability problems submitted that have not been fixed
(Brian will be working on those). Additionally all __STDC__
tests have been modified to check __STDC__ against the constant 1
(this is what the Second edition of K&R says must be true).
* Lots of additional error checking for forked processes (run_exec)
(thanks again to K. Richard Pixley)
* Lots of miscellaneous bug fixes - including but certainly not
limited to:
various commit core dumps
various update core dumps
bogus results from status with numeric sticky tags
commitprog used freed memory
Entries file corruption caused by No_Difference
commit to revision broken (now works if branch exists)
ignore file processing broken for * and !
ignore processing didn't handle memory reasonably
miscellaneous bugs in the recursion processor
file descriptor leak in ParseInfo
CVSROOT.adm->CVSROOT rename bug
lots of lint fixes
* Reformatted all the code in src (with GNU indent) and then
went back and fixed prototypes, etc since indent gets confused. The
rationale is that it is better to do it sooner than later and now
everything is consistent and will hopefully stay that way.
The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0
-nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then
miscellaneous formatting fixes were applied. Note also that the
"-nfc1" or "-nfca" may be appropriate in files where comments have
been carefully formatted (e.g, modules.c).
Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com)
* Changes between CVS 1.2 and CVS 1.3 Beta are described here.
* Lots of portability work. CVS now uses the GNU "configure"
script to dynamically determine the features provided by your
system. It probably is not foolproof, but it is better than
nothing. Please let me know of any portability problems. Some
file names were changed to fit within 14-characters.
* CVS has a new RCS parser that is much more flexible and
extensible. It should read all known RCS ",v" format files.
* Most of the commands now are fully recursive, rather than just
operating on the current directory alone. This includes "commit",
which makes it real easy to do an "atomic" commit of all the
changes made to a CVS hierarchy of sources. Most of the commands
also correctly handle file names that are in directories other than
".", including absolute path names. Commands now accept the "-R"
option to force recursion on (though it is always the default now)
and the "-l" option to force recursion off, doing just "." and not
any sub-directories.
* CVS supports many of the features provided with the RCS 5.x
distribution - including the new "-k" keyword expansion options. I
recommend using RCS 5.x (5.6 is the current official RCS version)
and GNU diff 1.15 (or later) distributions with CVS.
* Checking out files with symbolic tags/dates is now "sticky", in
that CVS remembers the tag/date used for each file (and directory)
and will use that tag/date automatically on the next "update" call.
This stickyness also holds for files checked out with the the new
RCS 5.x "-k" options.
* The "cvs diff" command now recognizes all of the rcsdiff 5.x
options. Unidiff format is available by installing the GNU
diff 1.15 distribution.
* The old "CVS.adm" directories created on checkout are now called
"CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm
directories are automagically converted to CVS directories. The
old "CVSROOT.adm" directory within the source repository is
automagically changed into a "CVSROOT" directory as well.
* Symbolic links in the source repository are fully supported ONLY
if you use RCS 5.6 or later and (of course) your system supports
symlinks.
* A history database has been contributed which maintains the
history of certain CVS operations, as well as providing a wide array
of querying options.
* The "cvs" program has a "-n" option which can be used with the
"update" command to show what would be updated without actually
doing the update, like: "cvs -n update". All usage statements
have been cleaned up and made more verbose.
* The module database parsing has been rewritten. The new format
is compatible with the old format, but with much more
functionality. It allows modules to be created that grab pieces or
whole directories from various different parts of your source
repository. Module-relative specifications are also correctly
recognized now, like "cvs checkout module/file.c".
* A configurable template can be specified such that on a "commit",
certain directories can supply a template that the user must fill
before completing the commit operation.
* A configurable pre-commit checking program can be specified which
will run to verify that a "commit" can happen. This feature can be
used to restrict certain users from changing certain pieces of the
source repository, or denying commits to the entire source
repository.
* The new "cvs export" command is much like "checkout", but
establishes defaults suitable for exporting code to others (expands
out keywords, forces the use of a symbolic tag, and does not create
"CVS" directories within the checked out sources.
* The new "cvs import" command replaces the deprecated "checkin"
shell script and is used to import sources into CVS control. It is
also much faster for the first-time import. Some algorithmic
improvements have also been made to reduce the number of
conflicting files on next-time imports.
* The new "cvs admin" command is basically an interface to the
"rcs" program. (Not yet implemented very well).
* Signal handling (on systems with BSD or POSIX signals) is much
improved. Interrupting CVS now works with a single interrupt!
* CVS now invokes RCS commands by direct fork/exec rather than
calling system(3). This improves performance by removing a call to
the shell to parse the arguments.
* Support for the .cvsignore file has been contributed. CVS will
now show "unknown" files as "? filename" as the result of an "update"
command. The .cvsignore file can be used to add files to the
current list of ignored files so that they won't show up as unknown.
* Command argument changes:
cvs: Added -l to turn off history logging.
Added -n to show what would be done without actually
doing anything.
Added -q/-Q for quiet and really quiet settings.
Added -t to show debugging trace.
add: Added -k to allow RCS 5.x -k options to be specified.
admin: New command; an interface to rcs(1).
checkout: Added -A to reset sticky tags/date/options.
Added -N to not shorten module paths.
Added -R option to force recursion.
Changed -p (prune empty directories) to -P option.
Changed -f option; forcing tags match is now default.
Added -p option to checkout module to standard output.
Added -s option to cat the modules db with status.
Added -d option to checkout in the specified directory.
Added -k option to use RCS 5.x -k support.
commit: Removed -a option; use -l instead.
Removed -f option.
Added -l option to disable recursion.
Added -R option to force recursion.
If no files specified, commit is recursive.
diff: Now recognizes all RCS 5.x rcsdiff options.
Added -l option to disable recursion.
Added -R option to force recursion.
history: New command; displays info about CVS usage.
import: Replaces "checkin" shell script; imports sources
under CVS control. Ignores files on the ignore
list (see -I option or .cvsignore description above).
export: New command; like "checkout", but w/special options
turned on by default to facilitate exporting sources.
join: Added -B option to join from base of the branch;
join now defaults to only joining with the top two
revisions on the branch.
Added -k option for RCS 5.x -k support.
log: Supports all RCS 5.x options.
Added -l option to disable recursion.
Added -R option to force recursion.
patch: Changed -f option; forcing tags match is now default.
Added -c option to force context-style diffs.
Added -u option to support unidiff-style diffs.
Added -V option to support RCS specific-version
keyword expansion formats.
Added -R option to force recursion.
remove: No option changes. It's a bit more verbose.
rtag: Equivalent to the old "cvs tag" command.
No option changes. It's a lot faster for re-tag.
status: New output formats with more information.
Added -l option to disable recursion.
Added -R option to force recursion.
Added -v option to show symbolic tags for files.
tag: Functionality changed to tag checked out files
rather than modules; use "rtag" command to get the
old "cvs tag" behaviour.
update: Added -A to reset sticky tags/date/options.
Changed -p (prune empty directories) to -P option.
Changed -f option; forcing tags match is now default.
Added -p option to checkout module to standard output.
Added -I option to add files to the ignore list.
Added -R option to force recursion.
Major Contributors:
* Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS
1.2. He made just about everything dynamic (by using malloc),
added a generic hashed list manager, re-wrote the modules database
parsing in a compatible - but extended way, generalized directory
hierarchy recursion for virtually all the commands (including
commit!), generalized the loginfo file to be used for pre-commit
checks and commit templates, wrote a new and flexible RCS parser,
fixed an uncountable number of bugs, and helped in the design of
future CVS features. If there's anything gross left in CVS, it's
probably my fault!
* David G. Grubbs <dgg@odi.com> contributed the CVS "history" and
"release" commands. As well as the ever-so-useful "-n" option of
CVS which tells CVS to show what it would do, without actually
doing it. He also contributed support for the .cvsignore file.
* Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and
contributed the code in lib/sighandle.c. I added support for
POSIX, BSD, and non-POSIX/non-BSD systems.
* Free Software Foundation contributed the "configure" script and
other compatibility support in the "lib" directory, which will help
make CVS much more portable.
* Many others have contributed bug reports and enhancement requests.
Some have even submitted actual code which I have not had time yet
to integrate into CVS. Maybe for the next release.
* Thanks to you all!
Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com)
* Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also
known as "Changes from CVS 1.1 to CVS 1.2".
* Major new support with this release is the ability to use the
recently-posted RCS 5.5 distribution with CVS 1.2. See below for
other assorted bug-fixes that have been thrown in.
* ChangeLog (new): Added Emacs-style change-log file to CVS 1.2
release. Chronological description of changes between release.
* README: Small fixes to installation instructions. My email
address is now "berliner@sun.com".
* src/Makefile: Removed "rcstime.h". Removed "depend" rule.
* src/partime.c: Updated to RCS 5.5 version with hooks for CVS.
* src/maketime.c: Updated to RCS 5.5 version with hooks for CVS.
* src/rcstime.h: Removed from the CVS 1.2 distribution.
Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
* src/checkin.csh: Support for RCS 5.5 parsing.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is
specified. When checking out files on-top-of other files that CVS
doesn't know about, run a diff in the hopes that they are really
the same file before aborting.
* src/commit.c (branch_number): Fix for RCS 5.5 parsing.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/commit.c (do_editor): Bug fix - fprintf missing argument
which sometimes caused core dumps.
* src/modules.c (process_module): Properly NULL-terminate
update_dir[] in all cases.
* src/no_difference.c (No_Difference): The wrong RCS revision was
being registered in certain (strange) cases.
* src/patch.c (get_rcsdate): New algorithm. No need to call
maketime() any longer.
Thanks to Paul Eggert <eggert@twinsun.com> for this change.
* src/patchlevel.h: Increased patch level to "2".
* src/subr.c (isdir, islink): Changed to compare stat mode bits
correctly.
* src/tag.c (tag_file): Added support for following symbolic links
that are in the master source repository when tagging. Made tag
somewhat quieter in certain cases.
* src/update.c (update_process_lists): Unlink the user's file if it
was put on the Wlist, meaning that the user's file is not modified
and its RCS file has been removed by someone else.
* src/update.c (update): Support for "cvs update dir" to correctly
just update the argument directory "dir".
* src/cvs.h: Fixes for RCS 5.5 parsing.
* src/version_number.c (Version_Number): Fixes for parsing RCS 5.5
and older RCS-format files.
Thanks to Paul Eggert <eggert@twinsun.com> for these changes.
* src/version_number.c (Version_Number): Bug fixes for "-f" option.
Bug fixes for parsing with certain branch numbers. RCS
revision/symbol parsing is much more solid now.
Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com)
* Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also
known as "Changes from CVS 1.0 to CVS 1.1".
* src/patch.c (get_rcsdate): Portability fix. Replaced call to
timelocal() with call to maketime().
Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com)
* Sent CVS 1.0 release to comp.sources.unix moderator and FSF.
* Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the
1986 version of CVS and making it available to the world. Dick's
version is available on uunet.uu.net in the
comp.sources.unix/volume6/cvs directory.
$CVSid: @(#)ChangeLog 1.35 94/10/22 $

59
gnu/usr.bin/cvs/PROJECTS Normal file
View File

@ -0,0 +1,59 @@
This is a list of projects for CVS. In general, unlike the things in
the TODO file, these need more analysis to determine if and how
worthwhile each task is.
I haven't gone through TODO, but it's likely that it has entries that
are actually more appropriate for this list.
0. Improved Efficency
* CVS uses a single doubly linked list/hash table data structure for
all of its lists. Since the back links are only used for deleting
list nodes it might be beneficial to use singly linked lists or a
tree structure. Most likely, a single list implementation will not
be appropriate for all uses.
One easy change would be to remove the "type" field out of the list
and node structures. I have found it to be of very little use when
debugging, and each instance eats up a word of memory. This can add
up and be a problem on memory-starved machines.
Profiles have shown that on fast machines like the Alpha, fsortcmp()
is one of the hot spots.
* Dynamically allocated character strings are created, copied, and
destroyed throughout CVS. The overhead of malloc()/strcpy()/free()
needs to be measured. If significant, it could be minimized by using a
reference counted string "class".
* File modification time is stored as a character string. It might be
worthwile to use a time_t internally if the time to convert a time_t
(from struct stat) to a string is greater that the time to convert a
ctime style string (from the entries file) to a time_t. time_t is
an machine-dependant type (although it's pretty standard on UN*X
systems), so we would have to have different conversion routines.
Profiles show that both operations are called about the same number
of times.
* stat() is one of the largest performance bottlenecks on systems
without the 4.4BSD filesystem. By spliting information out of
the filesystem (perhaps the "rename database") we should be
able to improve performance.
* Parsing RCS files is very expensive. This might be unnecessary if
RCS files are only used as containers for revisions, and tag,
revision, and date information was available in easy to read
(and modify) indexes. This becomes very apparent with files
with several hundred revisions.
* A RCS "library", so CVS could operate on RCS files directly.
CVS parses RCS files in order to determine if work needs to be done,
and then RCS parses the files again when it is performing the work.
This would be much faster if CVS could do whatever is necessary
by itself.
1. Improved testsuite/sanity check script
* Need to use a code coverage tool to determine how much the sanity
script tests, and fill in the holes.

View File

@ -0,0 +1,97 @@
#!/usr/bin/perl
# The version of the remote shell program on some Linuxes, at least,
# misuses GNU getopt in such a way that it plucks arguments to rsh
# that look like command-line switches from anywhere in rsh's
# arguments. This is the Wrong Thing to do, and causes older versions
# of CCVS to break.
# In addition, if we live behind a firewall and have to construct a
# "pipeline" of rshes through different machines in order to get to
# the outside world, each rshd along the way undoes the hard work CCVS
# does to put the command to be executed at the far end into a single
# argument. Sigh.
# This script is a very minimal wrapper to rsh which makes sure that
# the commands to be executed remotely are packed into a single
# argument before we call exec(). It works on the idea of a "proxy
# chain", which is a set of machines you go through to get to the CCVS
# server machine.
# Each host you go through before you reach the CCVS server machine
# should have a copy of this script somewhere (preferably accessible
# directly from your PATH envariable). In addition, each host you go
# through before you reach the firewall should have the CVS_PROXY_HOST
# envariable set to the next machine in the chain, and CVS_PROXY_USER
# set if necessary.
# This really isn't as complex as it sounds. Honest.
# Bryan O'Sullivan <bos@serpentine.com> April 1995
$usage = "usage: ccvs-rsh hostname [-l username] command [...]\n";
if ($#ARGV < 1) {
print STDERR $usage;
exit 1;
}
# Try to pick a sane version of the remote shell command to run. This
# only understands BSD and Linux machines; if your remote shell is
# called "remsh" under some System V (e.g. HP-SUX), you should edit
# the line manually to suit yourself.
$rsh = (-x "/usr/ucb/rsh") ? "/usr/ucb/rsh" : "/usr/bin/rsh";
# If you are not rshing directly to the CCVS server machine, make the
# following variable point at ccvs-rsh on the next machine in the
# proxy chain. If it's accessible through the PATH envariable, you
# can just set this to "ccvs-rsh".
$ccvs_rsh = "ccvs-rsh";
# There shouldn't be any user-serviceable parts beyond this point.
$host = $ARGV[0];
if ($ARGV[1] eq "-l") {
if ($#ARGV < 3) {
print STDERR $usage;
exit 1;
}
$user = $ARGV[2];
$cbase = 3;
} else {
$cbase = 1;
}
# You might think you shoul be able to do something like
# $command = join(' ', $ARGV[$cbase..$#ARGV]);
# to achieve the effect of the following block of code, but it doesn't
# work under Perl 4 on Linux, at least. Sigh.
$command = $ARGV[$cbase];
for ($cbase++; $cbase <= $#ARGV; $cbase++) {
$command .= " " . $ARGV[$cbase];
}
if (defined $ENV{"CVS_PROXY_HOST"}) {
$command = (defined $user)
? "$ccvs_rsh $host -l $user $command"
: "$ccvs_rsh $host $command";
if (defined $ENV{"CVS_PROXY_USER"}) {
exec ($rsh, $ENV{"CVS_PROXY_HOST"}, "-l", $ENV{"CVS_PROXY_USER"},
$command);
} else {
exec ($rsh, $ENV{"CVS_PROXY_HOST"}, $command);
}
} elsif (defined $user) {
exec ($rsh, $host, "-l", $user, $command);
} else {
if (defined $ENV{"CVS_PROXY_USER"}) {
exec ($rsh, $host, "-l", $ENV{"CVS_PROXY_USER"}, $command);
} else {
exec ($rsh, $host, $command);
}
}

View File

@ -0,0 +1,152 @@
#! xPERL_PATHx
# Merge conflicted ChangeLogs
# tromey Mon Aug 15 1994
# Usage is:
#
# cl-merge [-i] file ...
#
# With -i, it works in place (backups put in a ~ file). Otherwise the
# merged ChangeLog is printed to stdout.
# Please report any bugs to me. I wrote this yesterday, so there are no
# guarantees about its performance. I recommend checking its output
# carefully. If you do send a bug report, please include the failing
# ChangeLog, so I can include it in my test suite.
#
# Tom
# ---
# tromey@busco.lanl.gov Member, League for Programming Freedom
# Sadism and farce are always inexplicably linked.
# -- Alexander Theroux
# Month->number mapping. Used for sorting.
%months = ('Jan', 0,
'Feb', 1,
'Mar', 2,
'Apr', 3,
'May', 4,
'Jun', 5,
'Jul', 6,
'Aug', 7,
'Sep', 8,
'Oct', 9,
'Nov', 10,
'Dec', 11);
# If '-i' is given, do it in-place.
if ($ARGV[0] eq '-i') {
shift (@ARGV);
$^I = '~';
}
$lastkey = '';
$lastval = '';
$conf = 0;
%conflist = ();
$tjd = 0;
# Simple state machine. The states:
#
# 0 Not in conflict. Just copy input to output.
# 1 Beginning an entry. Next non-blank line is key.
# 2 In entry. Entry beginner transitions to state 1.
while (<>) {
if (/^<<<</ || /^====/) {
# Start of a conflict.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
$conf = 1;
} elsif (/^>>>>/) {
# End of conflict. Output.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
foreach (reverse sort clcmp keys %conflist) {
print STDERR "doing $_" if $tjd;
print $_;
print $conflist{$_};
}
$lastkey = '';
$lastval = '';
$conf = 0;
%conflist = ();
} elsif ($conf == 1) {
# Beginning an entry. Skip empty lines. Error if not a real
# beginner.
if (/^$/) {
# Empty line; just skip at this point.
} elsif (/^[MTWFS]/) {
# Looks like the name of a day; assume opener and move to
# "in entry" state.
$lastkey = $_;
$conf = 2;
print STDERR "found $_" if $tjd;
} else {
die ("conflict crosses entry boundaries: $_");
}
} elsif ($conf == 2) {
# In entry. Copy into variable until we see beginner line.
if (/^[MTWFS]/) {
# Entry beginner line.
# Copy last key into array.
if ($lastkey ne '') {
$conflist{$lastkey} = $lastval;
$lastkey = '';
$lastval = '';
}
$lastkey = $_;
print STDERR "found $_" if $tjd;
$lastval = '';
} else {
$lastval .= $_;
}
} else {
# Just copy.
print;
}
}
# Compare ChangeLog time strings like <=>.
#
# 0 1 2 3
# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu)
# 0123456789012345678901234567890
#
sub clcmp {
# First check year.
$r = substr ($a, 20, 4) <=> substr ($b, 20, 4);
# Now check month.
$r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r;
# Now check day.
$r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r;
# Now check time (3 parts).
$r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r;
$r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r;
$r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r;
$r;
}

View File

@ -0,0 +1,84 @@
#! /bin/sh
# $Id: cvscheck.sh,v 1.1 1995/07/10 02:26:29 kfogel Exp $
#
# cvscheck - identify files added, changed, or removed
# in CVS working directory
#
# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net>
#
# This program should be run in a working directory that has been
# checked out using CVS. It identifies files that have been added,
# changed, or removed in the working directory, but not "cvs
# committed". It also determines whether the files have been "cvs
# added" or "cvs removed". For directories, it is only practical to
# determine whether they have been added.
name=cvscheck
changes=0
# If we can't run CVS commands in this directory
cvs status . > /dev/null 2>&1
if [ $? != 0 ] ; then
# Bail out
echo "$name: there is no version here; bailing out" 1>&2
exit 1
fi
# Identify files added to working directory
for file in .* * ; do
# Skip '.' and '..'
if [ $file = '.' -o $file = '..' ] ; then
continue
fi
# If a regular file
if [ -f $file ] ; then
if cvs status $file | grep -s '^From:[ ]*New file' ; then
echo "file added: $file - not CVS committed"
changes=`expr $changes + 1`
elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then
echo "file added: $file - not CVS added, not CVS committed"
changes=`expr $changes + 1`
fi
# Else if a directory
elif [ -d $file -a $file != CVS.adm ] ; then
# Move into it
cd $file
# If CVS commands don't work inside
cvs status . > /dev/null 2>&1
if [ $? != 0 ] ; then
echo "directory added: $file - not CVS added"
changes=`expr $changes + 1`
fi
# Move back up
cd ..
fi
done
# Identify changed files
changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'`
for file in $changedfiles ; do
echo "file changed: $file - not CVS committed"
changes=`expr $changes + 1`
done
# Identify files removed from working directory
removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'`
# Determine whether each file has been cvs removed
for file in $removedfiles ; do
if cvs status $file | grep -s '^From:[ ]*-' ; then
echo "file removed: $file - not CVS committed"
else
echo "file removed: $file - not CVS removed, not CVS committed"
fi
changes=`expr $changes + 1`
done
exit $changes

View File

@ -0,0 +1,116 @@
#! /bin/sh
# $Id: descend.sh,v 1.1 1995/07/10 02:26:32 kfogel Exp $
#
# descend - walk down a directory tree and execute a command at each node
fullname=$0
name=descend
usage="Usage: $name [-afqrv] command [directory ...]\n
\040\040-a\040\040All: descend into directories starting with '.'\n
\040\040-f\040\040Force: ignore errors during descent\n
\040\040-q\040\040Quiet: don't print directory names\n
\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n
\040\040-v\040\040Verbose: print command before executing it"
# Scan for options
while getopts afqrv option; do
case $option in
a)
alldirs=$option
options=$options" "-$option
;;
f)
force=$option
options=$options" "-$option
;;
q)
verbose=
quiet=$option
options=$options" "-$option
;;
r)
restricted=$option
options=$options" "-$option
;;
v)
verbose=$option
quiet=
options=$options" "-$option
;;
\?)
/usr/5bin/echo $usage 1>&2
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
# Get command to execute
if [ $# -lt 1 ] ; then
/usr/5bin/echo $usage 1>&2
exit 1
else
command=$1
shift
fi
# If no directory specified, use '.'
if [ $# -lt 1 ] ; then
default_dir=.
fi
# For each directory specified
for dir in $default_dir "$@" ; do
# Spawn sub-shell so we return to starting directory afterward
(cd $dir
# Execute specified command
if [ -z "$quiet" ] ; then
echo In directory `hostname`:`pwd`
fi
if [ -n "$verbose" ] ; then
echo $command
fi
eval "$command" || if [ -z "$force" ] ; then exit 1; fi
# Collect dot file names if necessary
if [ -n "$alldirs" ] ; then
dotfiles=.*
else
dotfiles=
fi
# For each file in current directory
for file in $dotfiles * ; do
# Skip '.' and '..'
if [ "$file" = "." -o "$file" = ".." ] ; then
continue
fi
# If a directory but not a symbolic link
if [ -d "$file" -a ! -h "$file" ] ; then
# If not skipping this type of directory
if [ \( "$file" != "RCS" -a \
"$file" != "SCCS" -a \
"$file" != "CVS" -a \
"$file" != "CVS.adm" \) \
-o -z "$restricted" ] ; then
# Recursively descend into it
$fullname $options "$command" "$file" \
|| if [ -z "$force" ] ; then exit 1; fi
fi
# Else if a directory AND a symbolic link
elif [ -d "$file" -a -h "$file" ] ; then
if [ -z "$quiet" ] ; then
echo In directory `hostname`:`pwd`/$file: symbolic link: skipping
fi
fi
done
) || if [ -z "$force" ] ; then exit 1; fi
done

View File

@ -0,0 +1,481 @@
echo 'directory.3':
sed 's/^X//' >'directory.3' <<'!'
X.TH DIRECTORY 3 imported
X.DA 9 Oct 1985
X.SH NAME
Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
X.SH SYNOPSIS
X.B #include <sys/types.h>
X.br
X.B #include <ndir.h>
X.PP
X.SM
X.B DIR
X.B *opendir(filename)
X.br
X.B char *filename;
X.PP
X.SM
X.B struct direct
X.B *readdir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B long
X.B telldir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B seekdir(dirp, loc)
X.br
X.B DIR *dirp;
X.br
X.B long loc;
X.PP
X.SM
X.B rewinddir(dirp)
X.br
X.B DIR *dirp;
X.PP
X.SM
X.B closedir(dirp)
X.br
X.B DIR *dirp;
X.SH DESCRIPTION
XThis library provides high-level primitives for directory scanning,
Xsimilar to those available for 4.2BSD's (very different) directory system.
X.\"The purpose of this library is to simulate
X.\"the new flexible length directory names of 4.2bsd UNIX
X.\"on top of the old directory structure of v7.
XIt incidentally provides easy portability to and from 4.2BSD (insofar
Xas such portability is not compromised by other 4.2/VAX dependencies).
X.\"It allows programs to be converted immediately
X.\"to the new directory access interface,
X.\"so that they need only be relinked
X.\"when moved to 4.2bsd.
X.\"It is obtained with the loader option
X.\".BR \-lndir .
X.PP
X.I Opendir
Xopens the directory named by
X.I filename
Xand associates a
X.I directory stream
Xwith it.
X.I Opendir
Xreturns a pointer to be used to identify the
X.I directory stream
Xin subsequent operations.
XThe pointer
X.SM
X.B NULL
Xis returned if
X.I filename
Xcannot be accessed or is not a directory.
X.PP
X.I Readdir
Xreturns a pointer to the next directory entry.
XIt returns
X.B NULL
Xupon reaching the end of the directory or detecting
Xan invalid
X.I seekdir
Xoperation.
X.PP
X.I Telldir
Xreturns the current location associated with the named
X.I directory stream.
X.PP
X.I Seekdir
Xsets the position of the next
X.I readdir
Xoperation on the
X.I directory stream.
XThe new position reverts to the one associated with the
X.I directory stream
Xwhen the
X.I telldir
Xoperation was performed.
XValues returned by
X.I telldir
Xare good only for the lifetime of the DIR pointer from
Xwhich they are derived.
XIf the directory is closed and then reopened,
Xthe
X.I telldir
Xvalue may be invalidated
Xdue to undetected directory compaction in 4.2BSD.
XIt is safe to use a previous
X.I telldir
Xvalue immediately after a call to
X.I opendir
Xand before any calls to
X.I readdir.
X.PP
X.I Rewinddir
Xresets the position of the named
X.I directory stream
Xto the beginning of the directory.
X.PP
X.I Closedir
Xcauses the named
X.I directory stream
Xto be closed,
Xand the structure associated with the DIR pointer to be freed.
X.PP
XA
X.I direct
Xstructure is as follows:
X.PP
X.RS
X.nf
Xstruct direct {
X /* unsigned */ long d_ino; /* inode number of entry */
X unsigned short d_reclen; /* length of this record */
X unsigned short d_namlen; /* length of string in d_name */
X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
X};
X.fi
X.RE
X.PP
XThe
X.I d_reclen
Xfield is meaningless in non-4.2BSD systems and should be ignored.
XThe use of a
X.I long
Xfor
X.I d_ino
Xis also a 4.2BSDism;
X.I ino_t
X(see
X.IR types (5))
Xshould be used elsewhere.
XThe macro
X.I DIRSIZ(dp)
Xgives the minimum memory size needed to hold the
X.I direct
Xvalue pointed to by
X.IR dp ,
Xwith the minimum necessary allocation for
X.IR d_name .
X.PP
XThe preferred way to search the current directory for entry ``name'' is:
X.PP
X.RS
X.nf
X len = strlen(name);
X dirp = opendir(".");
X if (dirp == NULL) {
X fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
X return NOT_FOUND;
X }
X while ((dp = readdir(dirp)) != NULL)
X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
X closedir(dirp);
X return FOUND;
X }
X closedir(dirp);
X return NOT_FOUND;
X.RE
X.\".SH LINKING
X.\"This library is accessed by specifying ``-lndir'' as the
X.\"last argument to the compile line, e.g.:
X.\".PP
X.\" cc -I/usr/include/ndir -o prog prog.c -lndir
X.SH "SEE ALSO"
Xopen(2),
Xclose(2),
Xread(2),
Xlseek(2)
X.SH HISTORY
XWritten by
XKirk McKusick at Berkeley (ucbvax!mckusick).
XMiscellaneous bug fixes from elsewhere.
XThe size of the data structure has been decreased to avoid excessive
Xspace waste under V7 (where filenames are 14 characters at most).
XFor obscure historical reasons, the include file is also available
Xas
X.IR <ndir/sys/dir.h> .
XThe Berkeley version lived in a separate library (\fI\-lndir\fR),
Xwhereas ours is
Xpart of the C library, although the separate library is retained to
Xmaximize compatibility.
X.PP
XThis manual page has been substantially rewritten to be informative in
Xthe absence of a 4.2BSD manual.
X.SH BUGS
XThe
X.I DIRSIZ
Xmacro actually wastes a bit of space due to some padding requirements
Xthat are an artifact of 4.2BSD.
X.PP
XThe returned value of
X.I readdir
Xpoints to a static area that will be overwritten by subsequent calls.
X.PP
XThere are some unfortunate name conflicts with the \fIreal\fR V7
Xdirectory structure definitions.
!
echo 'dir.h':
sed 's/^X//' >'dir.h' <<'!'
X/* dir.h 4.4 82/07/25 */
X
X/*
X * A directory consists of some number of blocks of DIRBLKSIZ
X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
X *
X * Each DIRBLKSIZ byte block contains some number of directory entry
X * structures, which are of variable length. Each directory entry has
X * a struct direct at the front of it, containing its inode number,
X * the length of the entry, and the length of the name contained in
X * the entry. These are followed by the name padded to a 4 byte boundary
X * with null bytes. All names are guaranteed null terminated.
X * The maximum length of a name in a directory is MAXNAMLEN.
X *
X * The macro DIRSIZ(dp) gives the amount of space required to represent
X * a directory entry. Free space in a directory is represented by
X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes
X * in a directory block are claimed by the directory entries. This
X * usually results in the last entry in a directory having a large
X * dp->d_reclen. When entries are deleted from a directory, the
X * space is returned to the previous entry in the same directory
X * block by increasing its dp->d_reclen. If the first entry of
X * a directory block is free, then its dp->d_ino is set to 0.
X * Entries other than the first in a directory do not normally have
X * dp->d_ino set to 0.
X */
X#define DIRBLKSIZ 512
X#ifdef VMUNIX
X#define MAXNAMLEN 255
X#else
X#define MAXNAMLEN 14
X#endif
X
Xstruct direct {
X /* unsigned */ long d_ino; /* inode number of entry */
X unsigned short d_reclen; /* length of this record */
X unsigned short d_namlen; /* length of string in d_name */
X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
X};
X
X/*
X * The DIRSIZ macro gives the minimum record length which will hold
X * the directory entry. This requires the amount of space in struct direct
X * without the d_name field, plus enough space for the name with a terminating
X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
X */
X#undef DIRSIZ
X#define DIRSIZ(dp) \
X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
X
X#ifndef KERNEL
X/*
X * Definitions for library routines operating on directories.
X */
Xtypedef struct _dirdesc {
X int dd_fd;
X long dd_loc;
X long dd_size;
X char dd_buf[DIRBLKSIZ];
X} DIR;
X#ifndef NULL
X#define NULL 0
X#endif
Xextern DIR *opendir();
Xextern struct direct *readdir();
Xextern long telldir();
X#ifdef void
Xextern void seekdir();
Xextern void closedir();
X#endif
X#define rewinddir(dirp) seekdir((dirp), (long)0)
X#endif KERNEL
!
echo 'makefile':
sed 's/^X//' >'makefile' <<'!'
XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
XCFLAGS=-O -I. -Dvoid=int
XDEST=..
X
Xall: $(DIR)
X
Xmv: $(DIR)
X mv $(DIR) $(DEST)
X
Xcpif: dir.h
X cp dir.h /usr/include/ndir.h
X
Xclean:
X rm -f *.o
!
echo 'closedir.c':
sed 's/^X//' >'closedir.c' <<'!'
Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * close a directory.
X */
Xvoid
Xclosedir(dirp)
X register DIR *dirp;
X{
X close(dirp->dd_fd);
X dirp->dd_fd = -1;
X dirp->dd_loc = 0;
X free((char *)dirp);
X}
!
echo 'opendir.c':
sed 's/^X//' >'opendir.c' <<'!'
X/* Copyright (c) 1982 Regents of the University of California */
X
Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <dir.h>
X
X/*
X * open a directory.
X */
XDIR *
Xopendir(name)
X char *name;
X{
X register DIR *dirp;
X register int fd;
X struct stat statbuf;
X char *malloc();
X
X if ((fd = open(name, 0)) == -1)
X return NULL;
X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
X close(fd);
X return NULL;
X }
X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
X close (fd);
X return NULL;
X }
X dirp->dd_fd = fd;
X dirp->dd_loc = 0;
X dirp->dd_size = 0; /* so that telldir will work before readdir */
X return dirp;
X}
!
echo 'readdir.c':
sed 's/^X//' >'readdir.c' <<'!'
X/* Copyright (c) 1982 Regents of the University of California */
X
Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * read an old stlye directory entry and present it as a new one
X */
X#define ODIRSIZ 14
X
Xstruct olddirect {
X ino_t od_ino;
X char od_name[ODIRSIZ];
X};
X
X/*
X * get next entry in a directory.
X */
Xstruct direct *
Xreaddir(dirp)
X register DIR *dirp;
X{
X register struct olddirect *dp;
X static struct direct dir;
X
X for (;;) {
X if (dirp->dd_loc == 0) {
X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
X DIRBLKSIZ);
X if (dirp->dd_size <= 0) {
X dirp->dd_size = 0;
X return NULL;
X }
X }
X if (dirp->dd_loc >= dirp->dd_size) {
X dirp->dd_loc = 0;
X continue;
X }
X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
X dirp->dd_loc += sizeof(struct olddirect);
X if (dp->od_ino == 0)
X continue;
X dir.d_ino = dp->od_ino;
X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
X dir.d_namlen = strlen(dir.d_name);
X dir.d_reclen = DIRBLKSIZ;
X return (&dir);
X }
X}
!
echo 'seekdir.c':
sed 's/^X//' >'seekdir.c' <<'!'
Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
X
X#include <sys/param.h>
X#include <dir.h>
X
X/*
X * seek to an entry in a directory.
X * Only values returned by "telldir" should be passed to seekdir.
X */
Xvoid
Xseekdir(dirp, loc)
X register DIR *dirp;
X long loc;
X{
X long curloc, base, offset;
X struct direct *dp;
X extern long lseek();
X
X curloc = telldir(dirp);
X if (loc == curloc)
X return;
X base = loc & ~(DIRBLKSIZ - 1);
X offset = loc & (DIRBLKSIZ - 1);
X (void) lseek(dirp->dd_fd, base, 0);
X dirp->dd_size = 0;
X dirp->dd_loc = 0;
X while (dirp->dd_loc < offset) {
X dp = readdir(dirp);
X if (dp == NULL)
X return;
X }
X}
!
echo 'telldir.c':
sed 's/^X//' >'telldir.c' <<'!'
Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
X
X#include <sys/types.h>
X#include <dir.h>
X
X/*
X * return a pointer into a directory
X */
Xlong
Xtelldir(dirp)
X DIR *dirp;
X{
X long lseek();
X
X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
X}
!
echo done

View File

@ -0,0 +1,185 @@
#! /bin/sh
#
# $Id: rcs-to-cvs.sh,v 1.2 1995/07/15 03:40:34 jimb Exp $
# Based on the CVS 1.0 checkin csh script.
# Contributed by Per Cederqvist <ceder@signum.se>.
# Rewritten in sh by David MacKenzie <djm@cygnus.com>.
#
# Copyright (c) 1989, Brian Berliner
#
# You may distribute under the terms of the GNU General Public License.
#
#############################################################################
#
# Check in sources that previously were under RCS or no source control system.
#
# The repository is the directory where the sources should be deposited.
#
# Traverses the current directory, ensuring that an
# identical directory structure exists in the repository directory. It
# then checks the files in in the following manner:
#
# 1) If the file doesn't yet exist, check it in as revision 1.1
#
# The script also is somewhat verbose in letting the user know what is
# going on. It prints a diagnostic when it creates a new file, or updates
# a file that has been modified on the trunk.
#
# Bugs: doesn't put the files in branch 1.1.1
# doesn't put in release and vendor tags
#
#############################################################################
usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
vbose=0
message=""
message_file=/usr/tmp/checkin.$$
got_one=0
if [ $# -lt 1 ]; then
echo "$usage" >&2
exit 1
fi
while [ $# -ne 0 ]; do
case "$1" in
-v)
vbose=1
;;
-m)
shift
echo $1 > $message_file
got_one=1
;;
-f)
shift
message_file=$1
got_one=2
;;
*)
break
esac
shift
done
if [ $# -lt 1 ]; then
echo "$usage" >&2
exit 1
fi
repository=$1
shift
if [ -z "$CVSROOT" ]; then
echo "Please the environmental variable CVSROOT to the root" >&2
echo " of the tree you wish to update" >&2
exit 1
fi
if [ $got_one -eq 0 ]; then
echo "Please Edit this file to contain the RCS log information" >$message_file
echo "to be associated with this directory (please remove these lines)">>$message_file
${EDITOR-/usr/ucb/vi} $message_file
got_one=1
fi
# Ya gotta share.
umask 0
update_dir=${CVSROOT}/${repository}
[ ! -d ${update_dir} ] && mkdir $update_dir
if [ -d SCCS ]; then
echo SCCS files detected! >&2
exit 1
fi
if [ -d RCS ]; then
co RCS/*
fi
for name in * .[a-zA-Z0-9]*
do
case "$name" in
RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;;
esac
echo $name
if [ $vbose -ne 0 ]; then
echo "Updating ${repository}/${name}"
fi
if [ -d "$name" ]; then
if [ ! -d "${update_dir}/${name}" ]; then
echo "WARNING: Creating new directory ${repository}/${name}"
mkdir "${update_dir}/${name}"
if [ $? -ne 0 ]; then
echo "ERROR: mkdir failed - aborting" >&2
exit 1
fi
fi
cd "$name"
if [ $? -ne 0 ]; then
echo "ERROR: Couldn\'t cd to $name - aborting" >&2
exit 1
fi
if [ $vbose -ne 0 ]; then
$0 -v -f $message_file "${repository}/${name}"
else
$0 -f $message_file "${repository}/${name}"
fi
if [ $? -ne 0 ]; then
exit 1
fi
cd ..
else # if not directory
if [ ! -f "$name" ]; then
echo "WARNING: $name is neither a regular file"
echo " nor a directory - ignored"
continue
fi
file="${update_dir}/${name},v"
comment=""
if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword
myext=`echo $name | sed 's,.*\.,,'`
[ "$myext" = "$name" ] && myext=
case "$myext" in
c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" )
;;
* )
echo "For file ${file}:"
grep '\$Log.*\$' "${name}"
echo -n "Please insert a comment leader for file ${name} > "
read comment
;;
esac
fi
if [ ! -f "$file" ]; then # If not exists in repository
if [ ! -f "${update_dir}/Attic/${name},v" ]; then
echo "WARNING: Creating new file ${repository}/${name}"
if [ -f RCS/"${name}",v ]; then
echo "MSG: Copying old rcs file."
cp RCS/"${name}",v "$file"
else
if [ -n "${comment}" ]; then
rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
fi
ci -q -u1.1 -t${message_file} -m'.' "$file"
if [ $? -ne 0 ]; then
echo "ERROR: Initial check-in of $file failed - aborting" >&2
exit 1
fi
fi
else
file="${update_dir}/Attic/${name},v"
echo "WARNING: IGNORED: ${repository}/Attic/${name}"
continue
fi
else # File existed
echo "ERROR: File exists in repository: Ignored: $file"
continue
fi
fi
done
[ $got_one -eq 1 ] && rm -f $message_file
exit 0

View File

@ -0,0 +1,592 @@
#! /bin/sh
# RCS to ChangeLog generator
# Generate a change log prefix from RCS files and the ChangeLog (if any).
# Output the new prefix to standard output.
# You can edit this prefix by hand, and then prepend it to ChangeLog.
# Ignore log entries that start with `#'.
# Clump together log entries that start with `{topic} ',
# where `topic' contains neither white space nor `}'.
# Author: Paul Eggert <eggert@twinsun.com>
# $Id: rcs2log.sh,v 1.2 1995/07/28 19:48:45 eggert Exp $
# Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
tab=' '
nl='
'
# Parse options.
# defaults
: ${AWK=awk}
: ${TMPDIR=/tmp}
hostname= # name of local host (if empty, will deduce it later)
indent=8 # indent of log line
length=79 # suggested max width of log line
logins= # login names for people we know fullnames and mailaddrs of
loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
recursive= # t if we want recursive rlog
rlog_options= # options to pass to rlog
tabwidth=8 # width of horizontal tab
while :
do
case $1 in
-i) indent=${2?}; shift;;
-h) hostname=${2?}; shift;;
-l) length=${2?}; shift;;
-[nu]) # -n is obsolescent; it is replaced by -u.
case $1 in
-n) case ${2?}${3?}${4?} in
*"$tab"* | *"$nl"*)
echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
exit 1
esac
loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
shift; shift; shift;;
-u)
# If $2 is not tab-separated, use colon for separator.
case ${2?} in
*"$nl"*)
echo >&2 "$0: -u '$2': newlines not allowed"
exit 1;;
*"$tab"*)
t=$tab;;
*)
t=:
esac
case $2 in
*"$t"*"$t"*"$t"*)
echo >&2 "$0: -u '$2': too many fields"
exit 1;;
*"$t"*"$t"*)
;;
*)
echo >&2 "$0: -u '$2': not enough fields"
exit 1
esac
loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
shift
esac
logins=$logins$nl$login
;;
-r) rlog_options=$rlog_options$nl${2?}; shift;;
-R) recursive=t;;
-t) tabwidth=${2?}; shift;;
-*) echo >&2 "$0: usage: $0 [options] [file ...]
Options:
[-h hostname] [-i indent] [-l length] [-R] [-r rlog_option]
[-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..."
exit 1;;
*) break
esac
shift
done
month_data='
m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
m[3]="Apr"; m[4]="May"; m[5]="Jun"
m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
# days in non-leap year thus far, indexed by month (0-12)
mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
mo[12]=365
'
# Put rlog output into $rlogout.
# If no rlog options are given,
# log the revisions checked in since the first ChangeLog entry.
case $rlog_options in
'')
date=1970
if test -s ChangeLog
then
# Add 1 to seconds to avoid duplicating most recent log.
e='
/^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
'"$month_data"'
year = $5
for (i=0; i<=11; i++) if (m[i] == $2) break
dd = $3
hh = substr($0,12,2)
mm = substr($0,15,2)
ss = substr($0,18,2)
ss++
if (ss == 60) {
ss = 0
mm++
if (mm == 60) {
mm = 0
hh++
if (hh == 24) {
hh = 0
dd++
monthdays = mo[i+1] - mo[i]
if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
if (dd == monthdays + 1) {
dd = 1
i++
if (i == 12) {
i = 0
year++
}
}
}
}
}
# Output comma instead of space to avoid CVS 1.5 bug.
printf "%d/%02d/%02d,%02d:%02d:%02d\n", year,i+1,dd,hh,mm,ss
exit
}
'
d=`$AWK "$e" <ChangeLog` || exit
case $d in
?*) date=$d
esac
fi
datearg="-d>$date"
esac
# If CVS is in use, examine its repository, not the normal RCS files.
if test ! -f CVS/Repository
then
rlog=rlog
repository=
else
rlog='cvs log'
repository=`sed 1q <CVS/Repository` || exit
test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
case $CVSROOT in
*:/*)
# remote repository
;;
*)
# local repository
case $repository in
/*) ;;
*) repository=${CVSROOT?}/$repository
esac
if test ! -d "$repository"
then
echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
exit 1
fi
esac
fi
# With no arguments, examine all files under the RCS directory.
case $# in
0)
case $repository in
'')
oldIFS=$IFS
IFS=$nl
case $recursive in
t)
RCSdirs=`find . -name RCS -type d -print`
filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
files=`
{
case $RCSdirs in
?*) find $RCSdirs -type f -print
esac
find . -name '*,v' -print
} |
sort -u |
sed "$filesFromRCSfiles"
`;;
*)
files=
for file in RCS/.* RCS/* .*,v *,v
do
case $file in
RCS/. | RCS/..) continue;;
RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
esac
files=$files$nl$file
done
case $files in
'') exit 0
esac
esac
set x $files
shift
IFS=$oldIFS
esac
esac
llogout=$TMPDIR/rcs2log$$l
rlogout=$TMPDIR/rcs2log$$r
trap exit 1 2 13 15
trap "rm -f $llogout $rlogout; exit 1" 0
case $rlog_options in
?*) $rlog $rlog_options ${1+"$@"} >$rlogout;;
'') $rlog "$datearg" ${1+"$@"} >$rlogout
esac || exit
# Get the full name of each author the logs mention, and set initialize_fullname
# to awk code that initializes the `fullname' awk associative array.
# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
# you have to fix the resulting output by hand.
initialize_fullname=
initialize_mailaddr=
case $loginFullnameMailaddrs in
?*)
case $loginFullnameMailaddrs in
*\"* | *\\*)
sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
$loginFullnameMailaddrs
EOF
loginFullnameMailaddrs=`cat $llogout`
esac
oldIFS=$IFS
IFS=$nl
for loginFullnameMailaddr in $loginFullnameMailaddrs
do
case $loginFullnameMailaddr in
*"$tab"*) IFS=$tab;;
*) IFS=:
esac
set x $loginFullnameMailaddr
login=$2
fullname=$3
mailaddr=$4
initialize_fullname="$initialize_fullname
fullname[\"$login\"] = \"$fullname\""
initialize_mailaddr="$initialize_mailaddr
mailaddr[\"$login\"] = \"$mailaddr\""
done
IFS=$oldIFS
esac
case $llogout in
?*) sort -u -o $llogout <<EOF || exit
$logins
EOF
esac
output_authors='/^date: / {
if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
print substr($5, 1, length($5)-1)
}
}'
authors=`
$AWK "$output_authors" <$rlogout |
case $llogout in
'') sort -u;;
?*) sort -u | comm -23 - $llogout
esac
`
case $authors in
?*)
cat >$llogout <<EOF || exit
$authors
EOF
initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
initialize_author=`sed -e "$initialize_author_script" <$llogout`
awkscript='
BEGIN {
alphabet = "abcdefghijklmnopqrstuvwxyz"
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
'"$initialize_author"'
}
{
if (author[$1]) {
fullname = $5
if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
# Remove the junk from fullnames like "0000-Admin(0000)".
fullname = substr(fullname, index(fullname, "-") + 1)
fullname = substr(fullname, 1, index(fullname, "(") - 1)
}
if (fullname ~ /,[^ ]/) {
# Some sites put comma-separated junk after the fullname.
# Remove it, but leave "Bill Gates, Jr" alone.
fullname = substr(fullname, 1, index(fullname, ",") - 1)
}
abbr = index(fullname, "&")
if (abbr) {
a = substr($1, 1, 1)
A = a
i = index(alphabet, a)
if (i) A = substr(ALPHABET, i, 1)
fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
}
# Quote quotes and backslashes properly in full names.
# Do not use gsub; traditional awk lacks it.
quoted = ""
rest = fullname
for (;;) {
p = index(rest, "\\")
q = index(rest, "\"")
if (p) {
if (q && q<p) p = q
} else {
if (!q) break
p = q
}
quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
rest = substr(rest, p+1)
}
printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
author[$1] = 0
}
}
'
initialize_fullname=`
(cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
$AWK -F: "$awkscript"
`$initialize_fullname
esac
# Function to print a single log line.
# We don't use awk functions, to stay compatible with old awk versions.
# `Log' is the log message (with \n replaced by \r).
# `files' contains the affected files.
printlogline='{
# Following the GNU coding standards, rewrite
# * file: (function): comment
# to
# * file (function): comment
if (Log ~ /^\([^)]*\): /) {
i = index(Log, ")")
files = files " " substr(Log, 1, i)
Log = substr(Log, i+3)
}
# If "label: comment" is too long, break the line after the ":".
sep = " "
if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
# Print the label.
printf "%s*%s:", indent_string, files
# Print each line of the log, transliterating \r to \n.
while ((i = index(Log, CR)) != 0) {
logline = substr(Log, 1, i-1)
if (logline ~ /[^'"$tab"' ]/) {
printf "%s%s\n", sep, logline
} else {
print ""
}
sep = indent_string
Log = substr(Log, i+1)
}
}'
case $hostname in
'')
hostname=`(
hostname || uname -n || uuname -l || cat /etc/whoami
) 2>/dev/null` || {
echo >&2 "$0: cannot deduce hostname"
exit 1
}
esac
# Process the rlog output, generating ChangeLog style entries.
# First, reformat the rlog output so that each line contains one log entry.
# Transliterate \n to \r so that multiline entries fit on a single line.
# Discard irrelevant rlog output.
$AWK <$rlogout '
BEGIN { repository = "'"$repository"'" }
/^RCS file:/ {
if (repository != "") {
filename = $3
if (substr(filename, 1, length(repository) + 1) == repository "/") {
filename = substr(filename, length(repository) + 2)
}
if (filename ~ /,v$/) {
filename = substr(filename, 1, length(filename) - 2)
}
}
}
/^Working file:/ { if (repository == "") filename = $3 }
/^date: /, /^(-----------*|===========*)$/ {
if ($0 ~ /^branches: /) { next }
if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) {
date = $2
if (date ~ /-/) {
# An ISO format date. Replace all "-"s with "/"s.
newdate = ""
while ((i = index(date, "-")) != 0) {
newdate = newdate substr(date, 1, i-1) "/"
date = substr(date, i+1)
}
date = newdate date
}
# Ignore any time zone; ChangeLog has no room for it.
time = substr($3, 1, 8)
author = substr($5, 1, length($5)-1)
printf "%s %s %s %s %c", filename, date, time, author, 13
next
}
if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
printf "%s%c", $0, 13
}
' |
# Now each line is of the form
# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
# where \r stands for a carriage return,
# and each line of the log is terminated by \r instead of \n.
# Sort the log entries, first by date+time (in reverse order),
# then by author, then by log entry, and finally by file name (just in case).
sort +1 -3r +3 +0 |
# Finally, reformat the sorted log entries.
$AWK '
BEGIN {
# Some awk variants do not understand "\r" or "\013", so we have to
# put a carriage return directly in the file.
CR=" " # <-- There is a single CR between the " chars here.
# Initialize the fullname and mailaddr associative arrays.
'"$initialize_fullname"'
'"$initialize_mailaddr"'
# Initialize indent string.
indent_string = ""
i = '"$indent"'
if (0 < '"$tabwidth"')
for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
indent_string = indent_string "\t"
while (1 <= i--)
indent_string = indent_string " "
# Set up date conversion tables.
# RCS uses a nice, clean, sortable format,
# but ChangeLog wants the traditional, ugly ctime format.
# January 1, 0 AD (Gregorian) was Saturday = 6
EPOCH_WEEKDAY = 6
# Of course, there was no 0 AD, but the algorithm works anyway.
w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
'"$month_data"'
}
{
newlog = substr($0, 1 + index($0, CR))
# Ignore log entries prefixed by "#".
if (newlog ~ /^#/) { next }
if (Log != newlog || date != $2 || author != $4) {
# The previous log and this log differ.
# Print the old log.
if (date != "") '"$printlogline"'
# Logs that begin with "{clumpname} " should be grouped together,
# and the clumpname should be removed.
# Extract the new clumpname from the log header,
# and use it to decide whether to output a blank line.
newclumpname = ""
sep = "\n"
if (date == "") sep = ""
if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
i = index(newlog, "}")
newclumpname = substr(newlog, 1, i)
while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
newlog = substr(newlog, i+1)
if (clumpname == newclumpname) sep = ""
}
printf sep
clumpname = newclumpname
# Get ready for the next log.
Log = newlog
if (files != "")
for (i in filesknown)
filesknown[i] = 0
files = ""
}
if (date != $2 || author != $4) {
# The previous date+author and this date+author differ.
# Print the new one.
date = $2
author = $4
# Convert nice RCS date like "1992/01/03 00:03:44"
# into ugly ctime date like "Fri Jan 3 00:03:44 1992".
# Calculate day of week from Gregorian calendar.
i = index($2, "/")
year = substr($2, 1, i-1) + 0
monthday = substr($2, i+1)
i = index(monthday, "/")
month = substr(monthday, 1, i-1) + 0
day = substr(monthday, i+1) + 0
leap = 0
if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
# Print "date fullname (email address)".
# Get fullname and email address from associative arrays;
# default to author and author@hostname if not in arrays.
if (fullname[author])
auth = fullname[author]
else
auth = author
printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth
if (mailaddr[author])
printf "<%s>\n\n", mailaddr[author]
else
printf "<%s@%s>\n\n", author, "'"$hostname"'"
}
if (! filesknown[$1]) {
filesknown[$1] = 1
if (files == "") files = " " $1
else files = files ", " $1
}
}
END {
# Print the last log.
if (date != "") {
'"$printlogline"'
printf "\n"
}
}
' &&
# Exit successfully.
exec rm -f $llogout $rlogout

View File

@ -0,0 +1,143 @@
#! /bin/sh
#
#
# OrigId: rcs2sccs,v 1.12 90/10/04 20:52:23 kenc Exp Locker: kenc
# $Id: rcs2sccs.sh,v 1.1 1995/07/10 02:26:45 kfogel Exp $
############################################################
# Error checking
#
if [ ! -d SCCS ] ; then
mkdir SCCS
fi
logfile=/tmp/rcs2sccs_$$_log
rm -f $logfile
tmpfile=/tmp/rcs2sccs_$$_tmp
rm -f $tmpfile
emptyfile=/tmp/rcs2sccs_$$_empty
echo -n "" > $emptyfile
initialfile=/tmp/rcs2sccs_$$_init
echo "Initial revision" > $initialfile
sedfile=/tmp/rcs2sccs_$$_sed
rm -f $sedfile
revfile=/tmp/rcs2sccs_$$_rev
rm -f $revfile
commentfile=/tmp/rcs2sccs_$$_comment
rm -f $commentfile
# create the sed script
cat > $sedfile << EOF
s,;Id;,%Z%%M% %I% %E%,g
s,;SunId;,%Z%%M% %I% %E%,g
s,;RCSfile;,%M%,g
s,;Revision;,%I%,g
s,;Date;,%E%,g
s,;Id:.*;,%Z%%M% %I% %E%,g
s,;SunId:.*;,%Z%%M% %I% %E%,g
s,;RCSfile:.*;,%M%,g
s,;Revision:.*;,%I%,g
s,;Date:.*;,%E%,g
EOF
sed -e 's/;/\\$/g' $sedfile > $tmpfile
cp $tmpfile $sedfile
############################################################
# Loop over every RCS file in RCS dir
#
for vfile in *,v; do
# get rid of the ",v" at the end of the name
file=`echo $vfile | sed -e 's/,v$//'`
# work on each rev of that file in ascending order
firsttime=1
rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
for rev in `cat $revfile`; do
if [ $? != 0 ]; then
echo ERROR - revision
exit
fi
# get file into current dir and get stats
date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19//'`
time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'`
author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'`
date="$date $time"
echo ""
rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile
echo "==> file $file, rev=$rev, date=$date, author=$author"
rm -f $file
co -r$rev $file >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - co
exit
fi
echo checked out of RCS
# add SCCS keywords in place of RCS keywords
sed -f $sedfile $file > $tmpfile
if [ $? != 0 ]; then
echo ERROR - sed
exit
fi
echo performed keyword substitutions
rm -f $file
cp $tmpfile $file
# check file into SCCS
if [ "$firsttime" = "1" ]; then
firsttime=0
echo about to do sccs admin
echo sccs admin -n -i$file $file < $commentfile
sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - sccs admin
exit
fi
echo initial rev checked into SCCS
else
case $rev in
*.*.*.*)
brev=`echo $rev | sed -e 's/\.[0-9]*$//'`
sccs admin -fb $file 2>>$logfile
echo sccs get -e -p -r$brev $file
sccs get -e -p -r$brev $file >/dev/null 2>>$logfile
;;
*)
echo sccs get -e -p $file
sccs get -e -p $file >/dev/null 2>> $logfile
;;
esac
if [ $? != 0 ]; then
echo ERROR - sccs get
exit
fi
sccs delta $file < $commentfile >> $logfile 2>&1
if [ $? != 0 ]; then
echo ERROR - sccs delta -r$rev $file
exit
fi
echo checked into SCCS
fi
sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile
rm -f SCCS/s.$file
cp $tmpfile SCCS/s.$file
chmod 444 SCCS/s.$file
sccs admin -z $file
if [ $? != 0 ]; then
echo ERROR - sccs admin -z
exit
fi
done
rm -f $file
done
############################################################
# Clean up
#
echo cleaning up...
rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile
echo ===================================================
echo " Conversion Completed Successfully"
echo ===================================================
rm -f *,v

View File

@ -0,0 +1,277 @@
#! xCSH_PATHx -f
#
# Sccs2rcs is a script to convert an existing SCCS
# history into an RCS history without losing any of
# the information contained therein.
# It has been tested under the following OS's:
# SunOS 3.5, 4.0.3, 4.1
# Ultrix-32 2.0, 3.1
#
# Things to note:
# + It will NOT delete or alter your ./SCCS history under any circumstances.
#
# + Run in a directory where ./SCCS exists and where you can
# create ./RCS
#
# + /usr/local/bin is put in front of the default path.
# (SCCS under Ultrix is set-uid sccs, bad bad bad, so
# /usr/local/bin/sccs here fixes that)
#
# + Date, time, author, comments, branches, are all preserved.
#
# + If a command fails somewhere in the middle, it bombs with
# a message -- remove what it's done so far and try again.
# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean"
# There is no recovery and exit is far from graceful.
# If a particular module is hanging you up, consider
# doing it separately; move it from the current area so that
# the next run will have a better chance or working.
# Also (for the brave only) you might consider hacking
# the s-file for simpler problems: I've successfully changed
# the date of a delta to be in sync, then run "sccs admin -z"
# on the thing.
#
# + After everything finishes, ./SCCS will be moved to ./old-SCCS.
#
# This file may be copied, processed, hacked, mutilated, and
# even destroyed as long as you don't tell anyone you wrote it.
#
# Ken Cox
# Viewlogic Systems, Inc.
# kenstir@viewlogic.com
# ...!harvard!cg-atla!viewlog!kenstir
#
# Various hacks made by Brian Berliner before inclusion in CVS contrib area.
#
# $Id: sccs2rcs.csh,v 1.1 1995/07/10 02:26:48 kfogel Exp $
#we'll assume the user set up the path correctly
# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain
# /usr/local/bin/sccs should override /usr/ucb/sccs there
set path = (/usr/local/bin $path)
############################################################
# Error checking
#
if (! -w .) then
echo "Error: ./ not writeable by you."
exit 1
endif
if (! -d SCCS) then
echo "Error: ./SCCS directory not found."
exit 1
endif
set edits = (`sccs tell`)
if ($#edits) then
echo "Error: $#edits file(s) out for edit...clean up before converting."
exit 1
endif
if (-d RCS) then
echo "Warning: RCS directory exists"
if (`ls -a RCS | wc -l` > 2) then
echo "Error: RCS directory not empty
exit 1
endif
else
mkdir RCS
endif
sccs clean
set logfile = /tmp/sccs2rcs_$$_log
rm -f $logfile
set tmpfile = /tmp/sccs2rcs_$$_tmp
rm -f $tmpfile
set emptyfile = /tmp/sccs2rcs_$$_empty
echo -n "" > $emptyfile
set initialfile = /tmp/sccs2rcs_$$_init
echo "Initial revision" > $initialfile
set sedfile = /tmp/sccs2rcs_$$_sed
rm -f $sedfile
set revfile = /tmp/sccs2rcs_$$_rev
rm -f $revfile
# the quotes surround the dollar signs to fool RCS when I check in this script
set sccs_keywords = (\
'%W%[ ]*%G%'\
'%W%[ ]*%E%'\
'%W%'\
'%Z%%M%[ ]*%I%[ ]*%G%'\
'%Z%%M%[ ]*%I%[ ]*%E%'\
'%M%[ ]*%I%[ ]*%G%'\
'%M%[ ]*%I%[ ]*%E%'\
'%M%'\
'%I%'\
'%G%'\
'%E%'\
'%U%')
set rcs_keywords = (\
'$'Id'$'\
'$'Id'$'\
'$'Id'$'\
'$'SunId'$'\
'$'SunId'$'\
'$'Id'$'\
'$'Id'$'\
'$'RCSfile'$'\
'$'Revision'$'\
'$'Date'$'\
'$'Date'$'\
'')
############################################################
# Get some answers from user
#
echo ""
echo "Do you want to be prompted for a description of each"
echo "file as it is checked in to RCS initially?"
echo -n "(y=prompt for description, n=null description) [y] ?"
set ans = $<
if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then
set nodesc = 0
else
set nodesc = 1
endif
echo ""
echo "The default keyword substitutions are as follows and are"
echo "applied in the order specified:"
set i = 1
while ($i <= $#sccs_keywords)
# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\"
echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]"
@ i = $i + 1
end
echo ""
echo -n "Do you want to change them [n] ?"
set ans = $<
if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then
echo "You can't always get what you want."
echo "Edit this script file and change the variables:"
echo ' $sccs_keywords'
echo ' $rcs_keywords'
else
echo "good idea."
endif
# create the sed script
set i = 1
while ($i <= $#sccs_keywords)
echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile
@ i = $i + 1
end
onintr ERROR
############################################################
# Loop over every s-file in SCCS dir
#
foreach sfile (SCCS/s.*)
# get rid of the "s." at the beginning of the name
set file = `echo $sfile:t | sed -e "s/^..//"`
# work on each rev of that file in ascending order
set firsttime = 1
sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile
foreach rev (`cat $revfile`)
if ($status != 0) goto ERROR
# get file into current dir and get stats
set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'`
set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'`
echo ""
echo "==> file $file, rev=$rev, date=$date, author=$author"
sccs edit -r$rev $file >>& $logfile
if ($status != 0) goto ERROR
echo checked out of SCCS
# add RCS keywords in place of SCCS keywords
sed -f $sedfile $file > $tmpfile
if ($status != 0) goto ERROR
echo performed keyword substitutions
cp $tmpfile $file
# check file into RCS
if ($firsttime) then
set firsttime = 0
if ($nodesc) then
echo about to do ci
echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file
ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile
if ($status != 0) goto ERROR
echo initial rev checked into RCS without description
else
echo ""
echo Enter a brief description of the file $file \(end w/ Ctrl-D\):
cat > $tmpfile
ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile
if ($status != 0) goto ERROR
echo initial rev checked into RCS
endif
else
# get RCS lock
set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'`
if ("$lckrev" =~ [0-9]*.*) then
# need to lock the brach -- it is OK if the lock fails
rcs -l$lckrev $file >>& $logfile
else
# need to lock the trunk -- must succeed
rcs -l $file >>& $logfile
if ($status != 0) goto ERROR
endif
echo got lock
sccs prs -r$rev $file | grep "." > $tmpfile
# it's OK if grep fails here and gives status == 1
# put the delta message in $tmpfile
ed $tmpfile >>& $logfile <<EOF
/COMMENTS
1,.d
w
q
EOF
ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile
if ($status != 0) goto ERROR
echo checked into RCS
endif
sccs unedit $file >>& $logfile
if ($status != 0) goto ERROR
end
rm -f $file
end
############################################################
# Clean up
#
echo cleaning up...
mv SCCS old-SCCS
rm -f $tmpfile $emptyfile $initialfile $sedfile
echo ===================================================
echo " Conversion Completed Successfully"
echo ""
echo " SCCS history now in old-SCCS/"
echo ===================================================
set exitval = 0
goto cleanup
ERROR:
foreach f (`sccs tell`)
sccs unedit $f
end
echo ""
echo ""
echo Danger\! Danger\!
echo Some command exited with a non-zero exit status.
echo Log file exists in $logfile.
echo ""
echo Incomplete history in ./RCS -- remove it
echo Original unchanged history in ./SCCS
set exitval = 1
cleanup:
# leave log file
rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile
exit $exitval

View File

@ -0,0 +1,48 @@
WHAT THE "DEATH SUPPORT" FEATURES DO:
(this really should be in the main manual, but noone has gotten around
to updating it).
CVS with death support can record when a file is active, or alive, and
when it is removed, or dead. With this facility you can record the
history of a file, including the fact that at some point in its life
the file was removed and then later added.
First, the following now works as expected:
touch foo
cvs add foo ; cvs ci -m "added" foo
rm foo
cvs rm foo ; cvs ci -m "removed" foo
touch foo
cvs add foo ; cvs ci -m "resurrected" foo
Second, files can now be added or removed in a branch and later merged
into the trunk.
cvs update -A
touch a b c
cvs add a b c ; cvs ci -m "added" a b c
cvs tag -b branchtag
cvs update -r branchtag
touch d ; cvs add d
rm a ; cvs rm a
cvs ci -m "added d, removed a"
cvs update -A
cvs update -jbranchtag
Added and removed files may also be merged between branches.
Files removed in the trunk may be merged into branches.
Files added on the trunk are a special case. They cannot be merged
into a branch. Instead, simply branch the file by hand.
I also extended the "cvs update -j" semantic slightly. Like before,
if you use two -j options, the changes made between the first and the
second will be merged into your working files. This has not changed.
If you use only one -j option, it is used as the second -j option.
The first is assumed to be the greatest common ancestor revision
between the revision specified by the -j and the BASE revision of your
working file.

3542
gnu/usr.bin/cvs/cvs/client.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
/* Interface between the client and the rest of CVS. */
/* Stuff shared with the server. */
extern char *mode_to_string PROTO((mode_t));
extern int change_mode PROTO((char *, char *));
extern int gzip_level;
extern int filter_through_gzip PROTO((int, int, int, pid_t *));
extern int filter_through_gunzip PROTO((int, int, pid_t *));
#ifdef CLIENT_SUPPORT
/*
* Functions to perform CVS commands via the protocol. argc and argv
* are the arguments and the return value is the exit status (zero success
* nonzero failure).
*/
extern int client_commit PROTO((int argc, char **argv));
extern int client_update PROTO((int argc, char **argv));
extern int client_checkout PROTO((int argc, char **argv));
extern int client_diff PROTO((int argc, char **argv));
extern int client_log PROTO((int argc, char **argv));
extern int client_add PROTO((int argc, char **argv));
extern int client_remove PROTO((int argc, char **argv));
extern int client_status PROTO((int argc, char **argv));
extern int client_rdiff PROTO((int argc, char **argv));
extern int client_tag PROTO((int argc, char **argv));
extern int client_rtag PROTO((int argc, char **argv));
extern int client_import PROTO((int argc, char **argv));
extern int client_admin PROTO((int argc, char **argv));
extern int client_export PROTO((int argc, char **argv));
extern int client_history PROTO((int argc, char **argv));
extern int client_release PROTO((int argc, char **argv));
/*
* Flag variable for seeing whether common code is running as a client
* or to do a local operation.
*/
extern int client_active;
/* Is the -P option to checkout or update specified? */
extern int client_prune_dirs;
/* Stream to write to the server. */
extern FILE *to_server;
/* Stream to read from the server. */
extern FILE *from_server;
/* Internal functions that handle client communication to server, etc. */
int supported_request PROTO ((char *));
void option_with_arg PROTO((char *option, char *arg));
/* Get the responses and then close the connection. */
extern int get_responses_and_close PROTO((void));
extern int get_server_responses PROTO((void));
/* Start up the connection to the server on the other end. */
void
start_server PROTO((void));
/* Send the names of all the argument files to the server. */
void
send_file_names PROTO((int argc, char **argv));
/*
* Send Repository, Modified and Entry. argc and argv contain only
* the files to operate on (or empty for everything), not options.
* local is nonzero if we should not recurse (-l option). Also sends
* Argument lines for argc and argv, so should be called after options
* are sent.
*/
void
send_files PROTO((int argc, char **argv, int local, int aflag));
/*
* Like send_files but never send "Unchanged"--just send the contents of the
* file in that case. This is used to fix it if you import a directory which
* happens to have CVS directories (yes it is obscure but the testsuite tests
* it).
*/
void
send_files_contents PROTO((int argc, char **argv, int local, int aflag));
/* Send an argument to the remote server. */
void
send_arg PROTO((char *string));
/* Send a string of single-char options to the remote server, one by one. */
void
send_option_string PROTO((char *string));
#endif /* CLIENT_SUPPORT */
/*
* This structure is used to catalog the responses the client is
* prepared to see from the server.
*/
struct response
{
/* Name of the response. */
char *name;
#ifdef CLIENT_SUPPORT
/*
* Function to carry out the response. ARGS is the text of the
* command after name and, if present, a single space, have been
* stripped off. The function can scribble into ARGS if it wants.
*/
void (*func) PROTO((char *args, int len));
/*
* ok and error are special; they indicate we are at the end of the
* responses, and error indicates we should exit with nonzero
* exitstatus.
*/
enum {response_type_normal, response_type_ok, response_type_error} type;
#endif
/* Used by the server to indicate whether response is supported by
the client, as set by the Valid-responses request. */
enum {
/*
* Failure to implement this response can imply a fatal
* error. This should be set only for responses which were in the
* original version of the protocol; it should not be set for new
* responses.
*/
rs_essential,
/* Some clients might not understand this response. */
rs_optional,
/*
* Set by the server to one of the following based on what this
* client actually supports.
*/
rs_supported,
rs_not_supported
} status;
};
/* Table of responses ending in an entry with a NULL name. */
extern struct response responses[];
#ifdef CLIENT_SUPPORT
extern void client_senddate PROTO((const char *date));
extern void client_expand_modules PROTO((int argc, char **argv, int local));
extern void client_send_expansions PROTO((int local));
extern void client_nonexpanded_setup PROTO((void));
extern char **failed_patches;
extern int failed_patches_count;
extern char toplevel_wd[];
extern void client_import_setup PROTO((char *repository));
extern int client_process_import_file
PROTO((char *message, char *vfile, char *vtag,
int targc, char *targv[], char *repository));
extern void client_import_done PROTO((void));
#endif /* CLIENT_SUPPORT */

View File

@ -0,0 +1,139 @@
/* expand_path.c -- expand environmental variables in passed in string
The main routine is expand_pathname, it is the routine
that handles the '~' character in four forms:
~name
~name/
~/
~
and handles environment variables contained within the pathname
which are defined by:
c is some character
${var_name} var_name is the name of the environ variable
$var_name var_name ends with a non ascii character
char *expand_pathname(char *name)
This routine will expand the pathname to account for ~
and $ characters as described above.If an error occurs, NULL
is returned.
Will only expand Built in CVS variables all others are ignored.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "cvs.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
static char *expand_variable PROTO((char *env));
extern char *xmalloc ();
extern void free ();
char *
expand_path (name)
char *name;
{
char *s;
char *d;
char mybuf[PATH_MAX];
char buf[PATH_MAX];
char *result;
s = name;
d = mybuf;
while ((*d++ = *s))
if (*s++ == '$')
{
char *p = d;
char *e;
int flag = (*s == '{');
for (; (*d++ = *s); s++)
if (flag ? *s =='}' :
isalnum (*s) == 0 && *s!='_' )
break;
*--d = 0;
e = expand_variable (&p[flag]);
if (e)
{
for (d = &p[-1]; (*d++ = *e++);)
;
--d;
if (flag && *s)
s++;
}
else
return NULL; /* no env variable */
}
*d = 0;
s = mybuf;
d = buf;
/* If you don't want ~username ~/ to be expanded simply remove
* This entire if statement including the else portion
*/
if (*s++ == '~')
{
char *t;
char *p=s;
if (*s=='/' || *s==0)
t = getenv ("HOME");
else
{
struct passwd *ps;
for (; *p!='/' && *p; p++)
;
*p = 0;
ps = getpwnam (s);
if (ps == 0)
return NULL; /* no such user */
t = ps->pw_dir;
}
while ((*d++ = *t++))
;
--d;
if (*p == 0)
*p = '/'; /* always add / */
s=p;
}
else
--s;
/* Kill up to here */
while ((*d++ = *s++))
;
*d=0;
result = xmalloc (sizeof(char) * strlen(buf)+1);
strcpy (result, buf);
return result;
}
static char *
expand_variable (name)
char *name;
{
/* There is nothing expanding this function to allow it
* to read a file in the $CVSROOT/CVSROOT directory that
* says which environmental variables could be expanded
* or just say everything is fair game to be expanded
*/
if ( strcmp (name, CVSROOT_ENV) == 0 )
return CVSroot;
else
if ( strcmp (name, RCSBIN_ENV) == 0 )
return Rcsbin;
else
if ( strcmp (name, EDITOR1_ENV) == 0 )
return Editor;
else
if ( strcmp (name, EDITOR2_ENV) == 0 )
return Editor;
else
if ( strcmp (name, EDITOR3_ENV) == 0 )
return Editor;
else
return NULL;
/* The code here could also just
* return whatever getenv would
* return.
*/
}

287
gnu/usr.bin/cvs/cvs/login.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with CVS.
*
* Allow user to log in for an authenticating server.
*/
#include "cvs.h"
#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#ifndef lint
static const char rcsid[] = "$CVSid: @(#)login.c 1.1 95/10/01 $";
USE(rcsid);
#endif
#ifndef CVS_PASSWORD_FILE
#define CVS_PASSWORD_FILE ".cvspass"
#endif
/* The return value will need to be freed. */
char *
construct_cvspass_filename ()
{
char *homedir;
char *passfile;
/* Construct absolute pathname to user's password file. */
/* todo: does this work under Win-NT and OS/2 ? */
homedir = getenv ("HOME");
if (! homedir)
{
error (1, errno, "could not find out home directory");
return (char *) NULL;
}
passfile =
(char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3);
strcpy (passfile, homedir);
strcat (passfile, "/");
strcat (passfile, CVS_PASSWORD_FILE);
/* Safety first and last, Scouts. */
if (isfile (passfile))
/* xchmod() is too polite. */
chmod (passfile, 0600);
return passfile;
}
/* Prompt for a password, and store it in the file "CVS/.cvspass".
*
* Because the user might be accessing multiple repositories, with
* different passwords for each one, the format of ~/.cvspass is:
*
* user@host:/path cleartext_password
* user@host:/path cleartext_password
* ...
*
* Of course, the "user@" might be left off -- it's just based on the
* value of CVSroot.
*
* Like .netrc, the file's permissions are the only thing preventing
* it from being read by others. Unlike .netrc, we will not be
* fascist about it, at most issuing a warning, and never refusing to
* work.
*/
int
login (argc, argv)
int argc;
char **argv;
{
char *username;
int i;
char *passfile;
FILE *fp;
char *typed_password, *found_password;
char linebuf[MAXLINELEN];
int root_len, already_entered = 0;
/* Make this a "fully-qualified" CVSroot if necessary. */
if (! strchr (CVSroot, '@'))
{
/* We need to prepend "user@host:". */
char *tmp;
printf ("Repository \"%s\" not fully-qualified.\n", CVSroot);
printf ("Please enter \"user@host:/path\": ");
fflush (stdout);
fgets (linebuf, MAXLINELEN, stdin);
tmp = xmalloc (strlen (linebuf) + 1);
strcpy (tmp, linebuf);
tmp[strlen (linebuf) - 1] = '\0';
CVSroot = tmp;
}
/* Check to make sure it's fully-qualified before going on. */
if (! CVSroot)
{
error (1, 0, "CVSroot is NULL");
}
else if ((! strchr (CVSroot, '@')) && (! strchr (CVSroot, ':')))
{
error (1, 0, "CVSroot not fully-qualified: %s", CVSroot);
}
passfile = construct_cvspass_filename ();
typed_password = getpass ("Enter CVS password: ");
/* IF we have a password for this "[user@]host:/path" already
* THEN
* IF it's the same as the password we read from the prompt
* THEN
* do nothing
* ELSE
* replace the old password with the new one
* ELSE
* append new entry to the end of the file.
*/
root_len = strlen (CVSroot);
/* Yes, the method below reads the user's password file twice. It's
inefficient, but we're not talking about a gig of data here. */
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (1, errno, "unable to open %s", passfile);
return 1;
}
/* Check each line to see if we have this entry already. */
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (! strncmp (CVSroot, linebuf, root_len))
{
already_entered = 1;
break;
}
}
fclose (fp);
if (already_entered)
{
/* This user/host has a password in the file already. */
/* todo: what about these charsets??? */
strtok (linebuf, " \n");
found_password = strtok (NULL, " \n");
if (strcmp (found_password, typed_password))
{
/* typed_password and found_password don't match, so we'll
* have to update passfile. We replace the old password
* with the new one by writing a tmp file whose contents are
* exactly the same as passfile except that this one entry
* gets typed_password instead of found_password. Then we
* rename the tmp file on top of passfile.
*/
char *tmp_name;
FILE *tmp_fp;
tmp_name = tmpnam (NULL);
if ((tmp_fp = fopen (tmp_name, "w")) == NULL)
{
error (1, errno, "unable to open temp file %s", tmp_name);
return 1;
}
chmod (tmp_name, 0600);
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (1, errno, "unable to open %s", passfile);
return 1;
}
/* I'm not paranoid, they really ARE out to get me: */
chmod (passfile, 0600);
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (strncmp (CVSroot, linebuf, root_len))
fprintf (tmp_fp, "%s", linebuf);
else
fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password);
}
fclose (tmp_fp);
fclose (fp);
rename_file (tmp_name, passfile);
chmod (passfile, 0600);
}
}
else
{
if ((fp = fopen (passfile, "a")) == NULL)
{
error (1, errno, "could not open %s", passfile);
free (passfile);
return 1;
}
/* It's safer this way, and blank lines in the file are OK. */
fprintf (fp, "\n%s %s\n", CVSroot, typed_password);
fclose (fp);
}
/* Utter, total, raving paranoia, I know. */
chmod (passfile, 0600);
memset (typed_password, 0, strlen (typed_password));
free (passfile);
return 0;
}
/* todo: "cvs logout" could erase an entry from the file.
* But to what purpose?
*/
char *
get_cvs_password (user, host, cvsroot)
{
int root_len;
int found_it = 0;
char *password;
char linebuf[MAXLINELEN];
FILE *fp;
char *passfile;
passfile = construct_cvspass_filename ();
fp = fopen (passfile, "r");
if (fp == NULL)
{
error (0, errno, "could not open %s", passfile);
free (passfile);
goto prompt_for_it;
}
root_len = strlen (CVSroot);
/* Check each line to see if we have this entry already. */
while (fgets (linebuf, MAXLINELEN, fp) != NULL)
{
if (strncmp (CVSroot, linebuf, root_len) == 0)
{
/* This is it! So break out and deal with linebuf. */
found_it = 1;
break;
}
}
if (found_it)
{
/* linebuf now contains the line with the password. */
char *tmp;
strtok (linebuf, " ");
password = strtok (NULL, "\n");
/* Give it permanent storage. */
tmp = xmalloc (strlen (password) + 1);
strcpy (tmp, password);
tmp[strlen (password)] = '\0';
memset (password, 0, strlen (password));
return tmp;
}
else
{
prompt_for_it:
return getpass ("CVS password: ");
}
}
#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.4 kit.
*
* The functions in this file provide an interface for performing
* operations directly on RCS files.
*/
#include "cvs.h"
int
RCS_settag(path, tag, rev)
const char *path;
const char *tag;
const char *rev;
{
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
/* NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_deltag(path, tag, noerr)
const char *path;
const char *tag;
int noerr;
{
run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* set RCS branch to REV */
int
RCS_setbranch(path, rev)
const char *path;
const char *rev;
{
run_setup ("%s%s -q -b%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
/* Lock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_lock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
{
run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* Unlock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
RCS_unlock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
{
run_setup ("%s%s -q -u%s", Rcsbin, RCS, rev ? rev : "");
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
}
/* Merge revisions REV1 and REV2. */
int
RCS_merge(path, options, rev1, rev2)
const char *path;
const char *options;
const char *rev1;
const char *rev2;
{
int status;
/* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */
run_setup ("%s%s %s -r%s -r%s %s", Rcsbin, RCS_RCSMERGE,
options, rev1, rev2, path);
status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
#ifndef HAVE_RCS5
if (status == 0)
{
/* Run GREP to see if there appear to be conflicts in the file */
run_setup ("%s", GREP);
run_arg (RCS_MERGE_PAT);
run_arg (path);
status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0);
}
#endif
return status;
}

3992
gnu/usr.bin/cvs/cvs/server.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
/* Interface between the server and the rest of CVS. */
/* Miscellaneous stuff which isn't actually particularly server-specific. */
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif
#ifdef SERVER_SUPPORT
/*
* Nonzero if we are using the server. Used by various places to call
* server-specific functions.
*/
extern int server_active;
extern int server_expanding;
/* Server functions exported to the rest of CVS. */
/* Run the server. */
extern int server PROTO((int argc, char **argv));
/* We have a new Entries line for a file. TAG or DATE can be NULL. */
extern void server_register
PROTO((char *name, char *version, char *timestamp,
char *options, char *tag, char *date, char *conflict));
/*
* We want to nuke the Entries line for a file, and (unless
* server_scratch_entry_only is subsequently called) the file itself.
*/
extern void server_scratch PROTO((char *name));
/*
* The file which just had server_scratch called on it needs to have only
* the Entries line removed, not the file itself.
*/
extern void server_scratch_entry_only PROTO((void));
/*
* We just successfully checked in FILE (which is just the bare
* filename, with no directory). REPOSITORY is the directory for the
* repository.
*/
extern void server_checked_in
PROTO((char *file, char *update_dir, char *repository));
extern void server_copy_file
PROTO((char *file, char *update_dir, char *repository, char *newfile));
/*
* We just successfully updated FILE (bare filename, no directory).
* REPOSITORY is the directory for the repository. This is called
* after server_register or server_scratch, in the latter case the
* file is to be removed. UPDATED indicates whether the file is now
* up to date (SERVER_UPDATED, yes, SERVER_MERGED, no, SERVER_PATCHED,
* yes, but file is a diff from user version to repository version).
*/
enum server_updated_arg4 {SERVER_UPDATED, SERVER_MERGED, SERVER_PATCHED};
extern void server_updated
PROTO((char *file, char *update_dir, char *repository,
enum server_updated_arg4 updated, struct stat *,
unsigned char *checksum));
/* Set the Entries.Static flag. */
extern void server_set_entstat PROTO((char *update_dir, char *repository));
/* Clear it. */
extern void server_clear_entstat PROTO((char *update_dir, char *repository));
/* Set or clear a per-directory sticky tag or date. */
extern void server_set_sticky PROTO((char *update_dir, char *repository,
char *tag,
char *date));
extern void server_update_entries
PROTO((char *file, char *update_dir, char *repository,
enum server_updated_arg4 updated));
enum progs {PROG_CHECKIN, PROG_UPDATE};
extern void server_prog PROTO((char *, char *, enum progs));
extern void server_cleanup PROTO((int sig));
#ifdef SERVER_FLOWCONTROL
/* Pause if it's convenient to avoid memory blowout */
extern void server_check_pause PROTO((void));
#endif /* SERVER_FLOWCONTROL */
#endif /* SERVER_SUPPORT */
/* Stuff shared with the client. */
struct request
{
/* Name of the request. */
char *name;
#ifdef SERVER_SUPPORT
/*
* Function to carry out the request. ARGS is the text of the command
* after name and, if present, a single space, have been stripped off.
*/
void (*func) PROTO((char *args));
#endif
/* Stuff for use by the client. */
enum {
/*
* Failure to implement this request can imply a fatal
* error. This should be set only for commands which were in the
* original version of the protocol; it should not be set for new
* commands.
*/
rq_essential,
/* Some servers might lack this request. */
rq_optional,
/*
* Set by the client to one of the following based on what this
* server actually supports.
*/
rq_supported,
rq_not_supported,
/*
* If the server supports this request, and we do too, tell the
* server by making the request.
*/
rq_enableme
} status;
};
/* Table of requests ending with an entry with a NULL name. */
extern struct request requests[];
extern int use_unchanged;

View File

@ -0,0 +1,9 @@
/* Definitions of routines shared between local and client/server
"update" code. */
/* List of files that we have either processed or are willing to
ignore. Any file not on this list gets a question mark printed. */
extern List *ignlist;
extern int
update_filesdone_proc PROTO((int err, char *repository, char *update_dir));

View File

@ -0,0 +1,371 @@
#include "cvs.h"
/*
Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94
Modified By: vdemarco@bou.shl.com
This package was written to support the NEXTSTEP concept of
"wrappers." These are essentially directories that are to be
treated as "files." This package allows such wrappers to be
"processed" on the way in and out of CVS. The intended use is to
wrap up a wrapper into a single tar, such that that tar can be
treated as a single binary file in CVS. To solve the problem
effectively, it was also necessary to be able to prevent rcsmerge
application at appropriate times.
------------------
Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
wildcard [option value][option value]...
where option is one of
-f from cvs filter value: path to filter
-t to cvs filter value: path to filter
-m update methodology value: MERGE or COPY
and value is a single-quote delimited value.
E.g:
*.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY'
*/
typedef struct {
char *wildCard;
char *tocvsFilter;
char *fromcvsFilter;
char *conflictHook;
WrapMergeMethod mergeMethod;
} WrapperEntry;
static WrapperEntry **wrap_list=NULL;
static WrapperEntry **wrap_saved_list=NULL;
static int wrap_size=0;
static int wrap_count=0;
static int wrap_tempcount=0;
static int wrap_saved_count=0;
static int wrap_saved_tempcount=0;
#define WRAPPER_GROW 8
void wrap_add_entry PROTO((WrapperEntry *e,int temp));
void wrap_kill PROTO((void));
void wrap_kill_temp PROTO((void));
void wrap_free_entry PROTO((WrapperEntry *e));
void wrap_free_entry_internal PROTO((WrapperEntry *e));
void wrap_restore_saved PROTO((void));
void wrap_setup()
{
char file[PATH_MAX];
struct passwd *pw;
/* Then add entries found in repository, if it exists */
(void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_WRAPPER);
if (isfile (file)){
wrap_add_file(file,0);
}
/* Then add entries found in home dir, (if user has one) and file exists */
if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir){
(void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTWRAPPER);
if (isfile (file)){
wrap_add_file (file, 0);
}
}
/* Then add entries found in CVSWRAPPERS environment variable. */
wrap_add (getenv (WRAPPER_ENV), 0);
}
/*
* Open a file and read lines, feeding each line to a line parser. Arrange
* for keeping a temporary list of wrappers at the end, if the "temp"
* argument is set.
*/
void
wrap_add_file (file, temp)
const char *file;
int temp;
{
FILE *fp;
char line[1024];
wrap_restore_saved();
wrap_kill_temp();
/* load the file */
if (!(fp = fopen (file, "r")))
return;
while (fgets (line, sizeof (line), fp))
wrap_add (line, temp);
(void) fclose (fp);
}
void
wrap_kill()
{
wrap_kill_temp();
while(wrap_count)
wrap_free_entry(wrap_list[--wrap_count]);
}
void
wrap_kill_temp()
{
WrapperEntry **temps=wrap_list+wrap_count;
while(wrap_tempcount)
wrap_free_entry(temps[--wrap_tempcount]);
}
void
wrap_free_entry(e)
WrapperEntry *e;
{
wrap_free_entry_internal(e);
free(e);
}
void
wrap_free_entry_internal(e)
WrapperEntry *e;
{
free(e->wildCard);
if(e->tocvsFilter)
free(e->tocvsFilter);
if(e->fromcvsFilter)
free(e->fromcvsFilter);
if(e->conflictHook)
free(e->conflictHook);
}
void
wrap_restore_saved()
{
if(!wrap_saved_list)
return;
wrap_kill();
free(wrap_list);
wrap_list=wrap_saved_list;
wrap_count=wrap_saved_count;
wrap_tempcount=wrap_saved_tempcount;
wrap_saved_list=NULL;
wrap_saved_count=0;
wrap_saved_tempcount=0;
}
void
wrap_add (line, isTemp)
char *line;
int isTemp;
{
char *temp;
char ctemp;
WrapperEntry e;
char opt;
if (!line || line[0] == '#')
return;
memset (&e, 0, sizeof(e));
/* Search for the wild card */
while(*line && isspace(*line))
++line;
for(temp=line;*line && !isspace(*line);++line)
;
if(temp==line)
return;
ctemp=*line;
*line='\0';
e.wildCard=xstrdup(temp);
*line=ctemp;
while(*line){
/* Search for the option */
while(*line && *line!='-')
++line;
if(!*line)
break;
++line;
if(!*line)
break;
opt=*line;
/* Search for the filter commandline */
for(++line;*line && *line!='\'';++line);
if(!*line)
break;
for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line)
;
if(line==temp+1)
break;
ctemp=*line;
*line='\0';
switch(opt){
case 'f':
if(e.fromcvsFilter)
free(e.fromcvsFilter);
e.fromcvsFilter=expand_path (temp);
if (!e.fromcvsFilter)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 't':
if(e.tocvsFilter)
free(e.tocvsFilter);
e.tocvsFilter=expand_path (temp);
if (!e.tocvsFilter)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 'c':
if(e.conflictHook)
free(e.conflictHook);
e.conflictHook=expand_path (temp);
if (!e.conflictHook)
error (1, 0,
"Invalid environmental variable string '%s'",temp);
break;
case 'm':
if(*temp=='C' || *temp=='c')
e.mergeMethod=WRAP_COPY;
else
e.mergeMethod=WRAP_MERGE;
break;
default:
break;
}
*line=ctemp;
if(!*line)break;
++line;
}
wrap_add_entry(&e, isTemp);
}
void
wrap_add_entry(e, temp)
WrapperEntry *e;
int temp;
{
int x;
if(wrap_count+wrap_tempcount>=wrap_size){
wrap_size += WRAPPER_GROW;
wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list,
wrap_size *
sizeof (WrapperEntry *));
}
if(!temp && wrap_tempcount){
for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x)
wrap_list[x+1]=wrap_list[x];
}
x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++));
wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry));
wrap_list[x]->wildCard=e->wildCard;
wrap_list[x]->fromcvsFilter=e->fromcvsFilter;
wrap_list[x]->tocvsFilter=e->tocvsFilter;
wrap_list[x]->conflictHook=e->conflictHook;
wrap_list[x]->mergeMethod=e->mergeMethod;
}
/* Return 1 if the given filename is a wrapper filename */
int
wrap_name_has (name,has)
const char *name;
WrapMergeHas has;
{
int x,count=wrap_count+wrap_saved_count;
char *temp;
for(x=0;x<count;++x)
if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0){
switch(has){
case WRAP_TOCVS:
temp=wrap_list[x]->tocvsFilter;
break;
case WRAP_FROMCVS:
temp=wrap_list[x]->fromcvsFilter;
break;
case WRAP_CONFLICT:
temp=wrap_list[x]->conflictHook;
break;
default:
abort ();
}
if(temp==NULL)
return (0);
else
return (1);
}
return (0);
}
WrapperEntry *
wrap_matching_entry (name)
const char *name;
{
int x,count=wrap_count+wrap_saved_count;
for(x=0;x<count;++x)
if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0)
return wrap_list[x];
return (WrapperEntry *)NULL;
}
char *
wrap_tocvs_process_file(fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
static char buf[L_tmpnam+1];
if(e==NULL || e->tocvsFilter==NULL)
return NULL;
tmpnam(buf);
run_setup(e->tocvsFilter,fileName,buf);
run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
return buf;
}
int
wrap_merge_is_copy (fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
if(e==NULL || e->mergeMethod==WRAP_MERGE)
return 0;
return 1;
}
char *
wrap_fromcvs_process_file(fileName)
const char *fileName;
{
WrapperEntry *e=wrap_matching_entry(fileName);
static char buf[PATH_MAX];
if(e==NULL || e->fromcvsFilter==NULL)
return NULL;
run_setup(e->fromcvsFilter,fileName);
run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );
return buf;
}

View File

@ -0,0 +1,269 @@
.\" -*- nroff -*-
.\" ---------------------------------------------------------------------------
.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
.\"
.\" This file is part of the Problem Report Management System (GNATS)
.\" Copyright 1992 Cygnus Support
.\"
.\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public
.\" License as published by the Free Software Foundation; either
.\" version 2 of the License, or (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU Library General Public
.\" License along with this program; if not, write to the Free
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
.\"
.\" ---------------------------------------------------------------------------
.nh
.TH CVSBUG 1 xVERSIONx "February 1993"
.SH NAME
cvsbug \- send problem report (PR) about CVS to a central support site
.SH SYNOPSIS
.B cvsbug
[
.I site
]
[
.B \-f
.I problem-report
]
[
.B \-t
.I mail-address
]
.br
.in +0.8i
[
.B \-P
]
[
.B \-L
]
[
.B \-\-request-id
]
[
.B \-v
]
.SH DESCRIPTION
.B cvsbug
is a tool used to submit
.I problem reports
.\" SITE ADMINISTRATORS - change this if you use a local default
(PRs) to a central support site. In most cases the correct
.I site
will be the default. This argument indicates the support site which
is responsible for the category of problem involved. Some sites may
use a local address as a default.
.I site
values are defined by using the
.BR aliases (5).
.LP
.B cvsbug
invokes an editor on a problem report template (after trying to fill
in some fields with reasonable default values). When you exit the
editor,
.B cvsbug
sends the completed form to the
.I Problem Report Management System
(\fBGNATS\fR) at a central support site. At the support site, the PR
is assigned a unique number and is stored in the \fBGNATS\fR database
according to its category and submitter-id. \fBGNATS\fR automatically
replies with an acknowledgement, citing the category and the PR
number.
.LP
To ensure that a PR is handled promptly, it should contain your (unique)
\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
problem area. (Use
.B `cvsbug -L'
to see a list of categories.)
.LP
The
.B cvsbug
template at your site should already be customized with your
submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
accomplish this is part of the installation procedures for
.BR cvsbug ).
If this hasn't been done, see your system administrator for your
submitter-id, or request one from your support site by invoking
.B `cvsbug \-\-request\-id'.
If your site does not distinguish between different user sites, or if
you are not affiliated with the support site, use
.B `net'
for this field.
.LP
The more precise your problem description and the more complete your
information, the faster your support team can solve your problems.
.SH OPTIONS
.TP
.BI \-f " problem-report"
specify a file (\fIproblem-report\fR) which already contains a
complete problem report.
.B cvsbug
sends the contents of the file without invoking the editor. If
the value for
.I problem-report
is
.BR `\|\-\|' ,
then
.B cvsbug
reads from standard input.
.TP
.BI \-t " mail-address"
Change mail address at the support site for problem reports. The
default
.I mail-address
is the address used for the default
.IR site .
Use the
.I site
argument rather than this option in nearly all cases.
.TP
.B \-P
print the form specified by the environment variable
.B PR_FORM
on standard output. If
.B PR_FORM
is not set, print the standard blank PR template. No mail is sent.
.TP
.B -L
print the list of available categories. No mail is sent.
.TP
.B \-\-request\-id
sends mail to the default support site, or
.I site
if specified, with a request for your
.IR submitter-id .
If you are
not affiliated with
.IR site ,
use a
.I submitter-id
of
.BR net \|'.
.TP
.B \-v
Display the
.B cvsbug
version number.
.LP
Note: use
.B cvsbug
to submit problem reports rather than mailing them directly. Using
both the template and
.B cvsbug
itself will help ensure all necessary information will reach the
support site.
.SH ENVIRONMENT
The environment variable
.B EDITOR
specifies the editor to invoke on the template.
.br
default:
.B vi
.sp
If the environment variable
.B PR_FORM
is set, then its value is used as the file name of the template for
your problem-report editing session. You can use this to start with a
partially completed form (for example, a form with the identification
fields already completed).
.SH "HOW TO FILL OUT A PROBLEM REPORT"
Problem reports have to be in a particular form so that a program can
easily manage them. Please remember the following guidelines:
.IP \(bu 3m
describe only
.B one problem
with each problem report.
.IP \(bu 3m
For follow-up mail, use the same subject line as the one in the automatic
acknowledgent. It consists of category, PR number and the original synopsis
line. This allows the support site to relate several mail messages to a
particular PR and to record them automatically.
.IP \(bu 3m
Please try to be as accurate as possible in the subject and/or synopsis line.
.IP \(bu 3m
The subject and the synopsis line are not confidential. This is
because open-bugs lists are compiled from them. Avoid confidential
information there.
.LP
See the GNU
.B Info
file
.B cvsbug.info
or the document \fIReporting Problems With cvsbug\fR\ for detailed
information on reporting problems
.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
Submit small code samples with the PR. Contact the support site for
instructions on submitting larger test cases and problematic source
code.
.SH FILES
.ta \w'/tmp/pbad$$ 'u
/tmp/p$$ copy of PR used in editing session
.br
/tmp/pf$$ copy of empty PR form, for testing purposes
.br
/tmp/pbad$$ file for rejected PRs
.SH EMACS USER INTERFACE
An Emacs user interface for
.B cvsbug
with completion of field values is part of the
.B cvsbug
distribution (invoked with
.BR "M-x cvsbug" ).
See the file
.B cvsbug.info
or the ASCII file
.B INSTALL
in the top level directory of the distribution for configuration and
installation information. The Emacs LISP template file is
.B cvsbug-el.in
and is installed as
.BR cvsbug.el .
.SH INSTALLATION AND CONFIGURATION
See
.B cvsbug.info
or
.B INSTALL
for installation instructions.
.SH SEE ALSO
.I Reporting Problems Using cvsbug
(also installed as the GNU Info file
.BR cvsbug.info ).
.LP
.BR gnats (l),
.BR query-pr (1),
.BR edit-pr (1),
.BR gnats (8),
.BR queue-pr (8),
.BR at-pr (8),
.BR mkcat (8),
.BR mkdist (8).
.SH AUTHORS
Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
Support)
.SH COPYING
Copyright (c) 1992, 1993 Free Software Foundation, Inc.
.PP
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
.PP
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the
entire resulting derived work is distributed under the terms of a
permission notice identical to this one.
.PP
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be included in
translations approved by the Free Software Foundation instead of in
the original English.

View File

@ -0,0 +1,528 @@
#! /bin/sh
# Submit a problem report to a GNATS site.
# Copyright (C) 1993 Free Software Foundation, Inc.
# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
# version written by Heinz G. Seidl (hgs@ide.com).
#
# This file is part of GNU GNATS.
# Modified by Berliner for CVS.
#
#ident "@(#)cvs/src:$Name: $:$Id: cvsbug.sh,v 1.10 1995/11/15 00:18:00 woods Exp $"
#
# GNU GNATS is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# GNU GNATS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU GNATS; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
# The version of this send-pr.
VERSION=3.2
# The submitter-id for your site.
SUBMITTER=net
## # Where the GNATS directory lives, if at all.
## [ -z "$GNATS_ROOT" ] &&
## GNATS_ROOT=/usr/local/lib/gnats/gnats-db
# The default mail address for PR submissions.
GNATS_ADDR=bug-cvs@prep.ai.mit.edu
## # Where the gnats category tree lives.
## DATADIR=/usr/local/lib
## # If we've been moved around, try using GCC_EXEC_PREFIX.
## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}..
# The default release for this host.
DEFAULT_RELEASE="xVERSIONx"
# The default organization.
DEFAULT_ORGANIZATION="net"
## # The default site to look for.
## GNATS_SITE=unknown
## # Newer config information?
## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
# What mailer to use. This must come after the config file, since it is
# host-dependent.
if [ -f /usr/sbin/sendmail ]; then
MAIL_AGENT="/usr/sbin/sendmail -oi -t"
else
MAIL_AGENT="/usr/lib/sendmail -oi -t"
fi
MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'`
if [ ! -f "$MAILER" ] ; then
echo "$COMMAND: Cannot file mail program \"$MAILER\"."
echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file."
exit 1
fi
if test "`echo -n foo`" = foo ; then
ECHON=bsd
elif test "`echo 'foo\c'`" = foo ; then
ECHON=sysv
else
ECHON=none
fi
if [ $ECHON = bsd ] ; then
ECHON1="echo -n"
ECHON2=
elif [ $ECHON = sysv ] ; then
ECHON1=echo
ECHON2='\c'
else
ECHON1=echo
ECHON2=
fi
#
[ -z "$TMPDIR" ] && TMPDIR=/tmp
TEMP=$TMPDIR/p$$
BAD=$TMPDIR/pbad$$
REF=$TMPDIR/pf$$
if [ -z "$LOGNAME" -a -n "$USER" ]; then
LOGNAME=$USER
fi
FROM="$LOGNAME"
REPLY_TO="$LOGNAME"
# Find out the name of the originator of this PR.
if [ -n "$NAME" ]; then
ORIGINATOR="$NAME"
elif [ -f $HOME/.fullname ]; then
ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
elif [ -f /bin/domainname ]; then
if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then
# Must use temp file due to incompatibilities in quoting behavior
# and to protect shell metacharacters in the expansion of $LOGNAME
/usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" |
cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
ORIGINATOR="`cat $TEMP`"
rm -f $TEMP
fi
fi
if [ "$ORIGINATOR" = "" ]; then
grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP
ORIGINATOR="`cat $TEMP`"
rm -f $TEMP
fi
if [ -n "$ORGANIZATION" ]; then
if [ -f "$ORGANIZATION" ]; then
ORGANIZATION="`cat $ORGANIZATION`"
fi
else
if [ -n "$DEFAULT_ORGANIZATION" ]; then
ORGANIZATION="$DEFAULT_ORGANIZATION"
elif [ -f $HOME/.organization ]; then
ORGANIZATION="`cat $HOME/.organization`"
elif [ -f $HOME/.signature ]; then
ORGANIZATION="`cat $HOME/.signature`"
fi
fi
# If they don't have a preferred editor set, then use
if [ -z "$VISUAL" ]; then
if [ -z "$EDITOR" ]; then
EDIT=vi
else
EDIT="$EDITOR"
fi
else
EDIT="$VISUAL"
fi
# Find out some information.
SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""`
ARCH=`[ -f /bin/arch ] && /bin/arch`
MACHINE=`[ -f /bin/machine ] && /bin/machine`
COMMAND=`echo $0 | sed -e 's,.*/,,'`
## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id]
USAGE="Usage: $COMMAND [-PVL]
[--version]"
REMOVE=
BATCH=
while [ $# -gt 0 ]; do
case "$1" in
-r) ;; # Ignore for backward compat.
## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
## shift ; GNATS_ADDR="$1"
## EXPLICIT_GNATS_ADDR=true
## ;;
## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
## shift ; IN_FILE="$1"
## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
## echo "$COMMAND: cannot read $IN_FILE"
## exit 1
## fi
## ;;
-b | --batch) BATCH=true ;;
-p | -P | --print) PRINT=true ;;
-L | --list) FORMAT=norm ;;
-l | -CL | --lisp) FORMAT=lisp ;;
## --request-id) REQUEST_ID=true ;;
-h | --help) echo "$USAGE"; exit 0 ;;
-V | --version) echo "$VERSION"; exit 0 ;;
-*) echo "$USAGE" ; exit 1 ;;
*) echo "$USAGE" ; exit 1
## if [ -z "$USER_GNATS_SITE" ]; then
## if [ ! -r "$DATADIR/gnats/$1" ]; then
## echo "$COMMAND: the GNATS site $1 does not have a categories list."
## exit 1
## else
## # The site name is the alias they'll have to have created.
## USER_GNATS_SITE=$1
## fi
## else
## echo "$USAGE" ; exit 1
## fi
;;
esac
shift
done
if [ -n "$USER_GNATS_SITE" ]; then
GNATS_SITE=$USER_GNATS_SITE
GNATS_ADDR=$USER_GNATS_SITE-gnats
fi
if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
cat << '__EOF__'
It seems that send-pr is not installed with your unique submitter-id.
You need to run
install-sid YOUR-SID
where YOUR-SID is the identification code you received with `send-pr'.
`send-pr' will automatically insert this value into the template field
`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net'
for this value. If you do not know your id, run `send-pr --request-id' to
get one from your support site.
__EOF__
exit 1
fi
## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then
## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort`
## else
## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list."
## exit 1
## fi
CATEGORIES="contrib cvs doc pcl-cvs portability"
if [ -z "$CATEGORIES" ]; then
echo "$COMMAND: the categories list for $GNATS_SITE was empty!"
exit 1
fi
case "$FORMAT" in
lisp) echo "$CATEGORIES" | \
awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}'
exit 0
;;
norm) l=`echo "$CATEGORIES" | \
awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
END {print max + 1;}'`
c=`expr 70 / $l`
if [ $c -eq 0 ]; then c=1; fi
echo "$CATEGORIES" | \
awk 'BEGIN {print "Known categories:"; i = 0 }
{ printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } }
END { print ""; }'
exit 0
;;
esac
ORIGINATOR_C='<name of the PR author (one line)>'
ORGANIZATION_C='<organization of PR author (multiple lines)>'
CONFIDENTIAL_C='<[ yes | no ] (one line)>'
SYNOPSIS_C='<synopsis of the problem (one line)>'
SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
PRIORITY_C='<[ low | medium | high ] (one line)>'
CATEGORY_C='<name of the product (one line)>'
CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
RELEASE_C='<release number or tag (one line)>'
ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>'
DESCRIPTION_C='<precise description of the problem (multiple lines)>'
HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>'
FIX_C='<how to correct or work around the problem, if known (multiple lines)>'
# Catch some signals. ($xs kludge needed by Sun /bin/sh)
xs=0
trap 'rm -f $REF $TEMP; exit $xs' 0
trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15
# If they told us to use a specific file, then do so.
if [ -n "$IN_FILE" ]; then
if [ "$IN_FILE" = "-" ]; then
# The PR is coming from the standard input.
if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP
else
cat > $TEMP
fi
else
# Use the file they named.
if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP
else
cat $IN_FILE > $TEMP
fi
fi
else
if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
# If their PR_FORM points to a bogus entry, then bail.
if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then
echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM"
sleep 1
PRINT_INTERN=bad_prform
fi
fi
if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
cp $PR_FORM $TEMP ||
( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit )
else
for file in $TEMP $REF ; do
cat > $file << '__EOF__'
SEND-PR: -*- send-pr -*-
SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
SEND-PR: will all comments (text enclosed in `<' and `>').
SEND-PR:
SEND-PR: Choose from the following categories:
SEND-PR:
__EOF__
# Format the categories so they fit onto lines.
l=`echo "$CATEGORIES" | \
awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
END {print max + 1;}'`
c=`expr 61 / $l`
if [ $c -eq 0 ]; then c=1; fi
echo "$CATEGORIES" | \
awk 'BEGIN {printf "SEND-PR: "; i = 0 }
{ printf ("%-'$l'.'$l's", $0);
if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
END { printf "\nSEND-PR:\n"; }' >> $file
cat >> $file << __EOF__
To: $GNATS_ADDR
Subject:
From: $FROM
Reply-To: $REPLY_TO
X-send-pr-version: $VERSION
>Submitter-Id: $SUBMITTER
>Originator: $ORIGINATOR
>Organization:
${ORGANIZATION-$ORGANIZATION_C}
>Confidential: $CONFIDENTIAL_C
>Synopsis: $SYNOPSIS_C
>Severity: $SEVERITY_C
>Priority: $PRIORITY_C
>Category: $CATEGORY_C
>Class: $CLASS_C
>Release: ${DEFAULT_RELEASE-$RELEASE_C}
>Environment:
$ENVIRONMENT_C
`[ -n "$SYSTEM" ] && echo System: $SYSTEM`
`[ -n "$ARCH" ] && echo Architecture: $ARCH`
`[ -n "$MACHINE" ] && echo Machine: $MACHINE`
>Description:
$DESCRIPTION_C
>How-To-Repeat:
$HOW_TO_REPEAT_C
>Fix:
$FIX_C
__EOF__
done
fi
if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
cat $TEMP
xs=0; exit
fi
chmod u+w $TEMP
if [ -z "$REQUEST_ID" ]; then
eval $EDIT $TEMP
else
ed -s $TEMP << '__EOF__'
/^Subject/s/^Subject:.*/Subject: request for a customer id/
/^>Category/s/^>Category:.*/>Category: send-pr/
w
q
__EOF__
fi
if cmp -s $REF $TEMP ; then
echo "$COMMAND: problem report not filled out, therefore not sent"
xs=1; exit
fi
fi
#
# Check the enumeration fields
# This is a "sed-subroutine" with one keyword parameter
# (with workaround for Sun sed bug)
#
SED_CMD='
/$PATTERN/{
s|||
s|<.*>||
s|^[ ]*||
s|[ ]*$||
p
q
}'
while [ -z "$REQUEST_ID" ]; do
CNT=0
# 1) Confidential
#
PATTERN=">Confidential:"
CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
case "$CONFIDENTIAL" in
""|yes|no) CNT=`expr $CNT + 1` ;;
*) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;;
esac
#
# 2) Severity
#
PATTERN=">Severity:"
SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
case "$SEVERITY" in
""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
*) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
esac
#
# 3) Priority
#
PATTERN=">Priority:"
PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
case "$PRIORITY" in
""|low|medium|high) CNT=`expr $CNT + 1` ;;
*) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
esac
#
# 4) Category
#
PATTERN=">Category:"
CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
FOUND=
for C in $CATEGORIES
do
if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi
done
if [ -n "$FOUND" ]; then
CNT=`expr $CNT + 1`
else
if [ -z "$CATEGORY" ]; then
echo "$COMMAND: you must include a Category: field in your report."
else
echo "$COMMAND: \`$CATEGORY' is not a known category."
fi
fi
#
# 5) Class
#
PATTERN=">Class:"
CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
case "$CLASS" in
""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
*) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
esac
[ $CNT -lt 5 -a -z "$BATCH" ] &&
echo "Errors were found with the problem report."
while true; do
if [ -z "$BATCH" ]; then
$ECHON1 "a)bort, e)dit or s)end? $ECHON2"
read input
else
if [ $CNT -eq 5 ]; then
input=s
else
input=a
fi
fi
case "$input" in
a*)
if [ -z "$BATCH" ]; then
echo "$COMMAND: the problem report remains in $BAD and is not sent."
mv $TEMP $BAD
else
echo "$COMMAND: the problem report is not sent."
fi
xs=1; exit
;;
e*)
eval $EDIT $TEMP
continue 2
;;
s*)
break 2
;;
esac
done
done
#
# Remove comments and send the problem report
# (we have to use patterns, where the comment contains regex chars)
#
# /^>Originator:/s;$ORIGINATOR;;
sed -e "
/^SEND-PR:/d
/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
/^>Confidential:/s;<.*>;;
/^>Synopsis:/s;$SYNOPSIS_C;;
/^>Severity:/s;<.*>;;
/^>Priority:/s;<.*>;;
/^>Category:/s;$CATEGORY_C;;
/^>Class:/s;<.*>;;
/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
" $TEMP > $REF
if $MAIL_AGENT < $REF; then
echo "$COMMAND: problem report sent"
xs=0; exit
else
echo "$COMMAND: mysterious mail failure."
if [ -z "$BATCH" ]; then
echo "$COMMAND: the problem report remains in $BAD and is not sent."
mv $REF $BAD
else
echo "$COMMAND: the problem report is not sent."
fi
xs=1; exit
fi

View File

@ -0,0 +1,161 @@
#! /bin/sh
:
#
#ident "@(#)cvs:$Name: $:$Id: cvsinit.sh,v 1.7 1995/11/14 23:44:18 woods Exp $"
# Copyright (c) 1992, Brian Berliner
#
# You may distribute under the terms of the GNU General Public License as
# specified in the README file that comes with the CVS 1.4 kit.
# This script should be run for each repository you create to help you
# setup your site for CVS. You may also run it to update existing
# repositories if you install a new version of CVS.
# this line is edited by Makefile when creating cvsinit.inst
CVSLIB="/usr/share/examples/cvs"
CVS_VERSION="cvs-1.6.3"
# All purpose usage message, also suffices for --help and --version.
if test $# -gt 0; then
echo "cvsinit version $CVS_VERSION"
echo "usage: $0"
echo "(set CVSROOT to the repository that you want to initialize)"
exit 0
fi
# Make sure that the CVSROOT variable is set
if [ "x$CVSROOT" = x ]; then
echo "The CVSROOT environment variable is not set."
echo ""
echo "You should choose a location for your source repository"
echo "that can be shared by many developers. It also helps to"
echo "place the source repository on a file system that has"
echo "plenty of free space."
echo ""
echo "Please enter the full path for your CVSROOT source repository:"
read CVSROOT junk
unset junk
remind_cvsroot=yes
else
remind_cvsroot=no
fi
# Now, create the $CVSROOT if it is not already there
if [ ! -d $CVSROOT ]; then
echo "Creating $CVSROOT..."
path=
for comp in `echo $CVSROOT | sed -e 's,/, ,g'`; do
path=$path/$comp
if [ ! -d $path ]; then
mkdir $path
fi
done
else
true
fi
# Next, check for $CVSROOT/CVSROOT
if [ ! -d $CVSROOT/CVSROOT ]; then
if [ -d $CVSROOT/CVSROOT.adm ]; then
echo "You have the old $CVSROOT/CVSROOT.adm directory."
echo "I will rename it to $CVSROOT/CVSROOT for you..."
mv $CVSROOT/CVSROOT.adm $CVSROOT/CVSROOT
else
echo "Creating the $CVSROOT/CVSROOT directory..."
mkdir $CVSROOT/CVSROOT
fi
else
true
fi
if [ ! -d $CVSROOT/CVSROOT ]; then
echo "Unable to create $CVSROOT/CVSROOT."
echo "I give up."
exit 1
fi
# Create the special control files and templates within $CVSROOT/CVSROOT
EXAMPLES="checkoutlist commitinfo cvswrappers editinfo loginfo modules
rcsinfo rcstemplate taginfo wrap unwrap"
NEWSAMPLE=false
for info in $EXAMPLES; do
if [ -f $CVSROOT/CVSROOT/${info},v ]; then
if [ ! -f $CVSROOT/CVSROOT/$info ]; then
echo "Checking out $CVSROOT/CVSROOT/$info"
echo " from $CVSROOT/CVSROOT/${info},v..."
(cd $CVSROOT/CVSROOT; co -q $info)
fi
else
NEWSAMPLE=true
if [ -f $CVSROOT/CVSROOT/$info ]; then
echo "Checking in $CVSROOT/CVSROOT/${info},v"
echo " from $CVSROOT/CVSROOT/$info..."
else
echo "Creating a sample $CVSROOT/CVSROOT/$info file..."
case $info in
modules)
sed -n -e '/END_REQUIRED_CONTENT/q' \
-e p $CVSLIB/examples/modules > $CVSROOT/CVSROOT/modules
;;
rcstemplate)
cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info
;;
wrap|unwrap)
cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info
chmod +x $CVSROOT/CVSROOT/$info
;;
*)
# comment out everything in all the other examples....
sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info > $CVSROOT/CVSROOT/$info
;;
esac
fi
(cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m"initial checkin of $info" $info)
fi
done
if $NEWSAMPLE ; then
echo "NOTE: You may wish to check out the CVSROOT module and edit any new"
echo "configuration files to match your local requirements."
echo ""
fi
# check to see if there are any references to the old CVSROOT.adm directory
if grep CVSROOT.adm $CVSROOT/CVSROOT/modules >/dev/null 2>&1; then
echo "Warning: your $CVSROOT/CVSROOT/modules file still"
echo " contains references to the old CVSROOT.adm directory"
echo " You should really change these to the new CVSROOT directory"
echo ""
fi
# These files are generated from the contrib files.
# FIXME: Is it really wise to overwrite possible local changes like this?
# Normal folks will keep these up to date by modifying the source in
# their CVS module and re-installing CVS, but is everyone OK with that?
#
#
CONTRIBS="log commit_prep log_accum cln_hist"
#
for contrib in $CONTRIBS; do
echo "Copying the new version of '${contrib}'"
echo " to $CVSROOT/CVSROOT for you..."
cp $CVSLIB/contrib/$contrib $CVSROOT/CVSROOT/$contrib
done
# XXX - also add a stub for the cvsignore file
# Turn on history logging by default
if [ ! -f $CVSROOT/CVSROOT/history ]; then
echo "Enabling CVS history logging..."
touch $CVSROOT/CVSROOT/history
chmod g+w $CVSROOT/CVSROOT/history
echo "(Remove $CVSROOT/CVSROOT/history to disable.)"
fi
# finish up by running mkmodules
echo "All done! Running 'mkmodules' as my final step..."
mkmodules $CVSROOT/CVSROOT
exit 0

View File

@ -0,0 +1,142 @@
.de Id
.ds Rv \\$4
.ds Dt \\$5
..
.Id @(#)ccvs/man:$Name: $:$Id: cvsinit.8,v 1.2 1995/11/14 20:48:54 woods Exp $
.TH CVSINIT 8 "\*(Dt"
.\" Full space in nroff; half space in troff
.de SP
.if n .sp
.if t .sp .5
..
.\" quoted command
.de `
.RB ` "\|\\$1\|" '\\$2
..
.\"
.SH "NAME"
cvsinit \- Concurrent Versions System repository initialization script
.SH "SYNOPSIS"
.TP
.B cvsinit
.\"
.SH "DESCRIPTION"
.\"
The
.B cvsinit
script initializes a repository in the location specified by the
.SM CVSROOT
environment variable.
.SH "FILES"
For more detailed information on
.B cvs
supporting files, see
.BR cvs ( 5 ).
.LP
Files in source repositories (created by
.BR cvsinit ):
.TP
$CVSROOT/CVSROOT
Directory of global administrative files for repository.
.TP
$CVSROOT/commitinfo,v
Records programs for filtering
.` "cvs commit"
requests.
.TP
$CVSROOT/history
Log file of \fBcvs\fP transactions.
.TP
$CVSROOT/modules,v
Definitions for modules in this repository.
.TP
$CVSROOT/loginfo,v
Records programs for piping
.` "cvs commit"
log entries.
.TP
$CVSROOT/rcsinfo,v
Records pathnames to templates used during a
.` "cvs commit"
operation.
.TP
$CVSROOT/editinfo,v
Records programs for editing/validating
.` "cvs commit"
log entries.
.TP
$CVSROOT/log
Sample logging script for use in
.IR loginfo .
.TP
$CVSROOT/commit_prep
Sample logging script for use in
.I commitinfo
with the
.I log_accum
script
.TP
$CVSROOT/log_accum
Sample loggin script for use in
.I loginfo
with the
.I commit_prep
script
.\"
.SH "ENVIRONMENT VARIABLES"
.TP
.SM CVSROOT
Should contain the full pathname to the root of the
.B cvs
source repository (where the
.SM RCS
files are kept). This information must be available to \fBcvs\fP for
most commands to execute; if
.SM CVSROOT
is not set, or if you wish to override it for one invocation, you can
supply it on the command line:
.` "cvs \-d \fIcvsroot cvs_command\fP\|.\|.\|."
You may not need to set
.SM CVSROOT
if your \fBcvs\fP binary has the right path compiled in; use
.` "cvs \-v"
to display all compiled-in paths.
.\"
.SH "AUTHORS"
.TP
Dick Grune
Original author of the
.B cvs
shell script version posted to
.B comp.sources.unix
in the volume6 release of December, 1986.
Credited with much of the
.B cvs
conflict resolution algorithms.
.TP
Brian Berliner
Coder and designer of the
.B cvs
program itself in April, 1989, based on the original work done by Dick.
.TP
Jeff Polk
Helped Brian with the design of the
.B cvs
module and vendor branch support and author of the
.BR checkin ( 1 )
shell script (the ancestor of
.` "cvs import").
.SH "SEE ALSO"
.BR ci ( 1 ),
.BR co ( 1 ),
.BR cvs ( 5 ),
.BR diff ( 1 ),
.BR grep ( 1 ),
.BR mkmodules ( 1 ),
.BR patch ( 1 ),
.BR rcs ( 1 ),
.BR rcsdiff ( 1 ),
.BR rcsmerge ( 1 ),
.BR rlog ( 1 ),
.BR rm ( 1 ),
.BR sort ( 1 ).

View File

@ -0,0 +1,673 @@
\input texinfo
@setfilename cvsclient.info
@node Top
@top CVS Client/Server
This manual describes the client/server protocol used by CVS. It does
not describe how to use or administer client/server CVS; see the
regular CVS manual for that.
@menu
* Goals:: Basic design decisions, requirements, scope, etc.
* Notes:: Notes on the current implementation
* How To:: How to remote your favorite CVS command
* Protocol Notes:: Possible enhancements, limitations, etc. of the protocol
* Protocol:: Complete description of the protocol
@end menu
@node Goals
@chapter Goals
@itemize @bullet
@item
Do not assume any access to the repository other than via this protocol.
It does not depend on NFS, rdist, etc.
@item
Providing a reliable transport is outside this protocol. It is expected
that it runs over TCP, UUCP, etc.
@item
Security and authentication are handled outside this protocol (but see
below about @samp{cvs kserver}).
@item
This might be a first step towards adding transactions to CVS (i.e. a
set of operations is either executed atomically or none of them is
executed), improving the locking, or other features. The current server
implementation is a long way from being able to do any of these
things. The protocol, however, is not known to contain any defects
which would preclude them.
@item
The server never has to have any CVS locks in place while it is waiting
for communication with the client. This makes things robust in the face
of flaky networks.
@item
Data is transferred in large chunks, which is necessary for good
performance. In fact, currently the client uploads all the data
(without waiting for server responses), and then waits for one server
response (which consists of a massive download of all the data). There
may be cases in which it is better to have a richer interraction, but
the need for the server to release all locks whenever it waits for the
client makes it complicated.
@end itemize
@node Notes
@chapter Notes on the Current Implementation
The client is built in to the normal @code{cvs} program, triggered by a
@code{CVSROOT} variable containing a colon, for example
@code{cygnus.com:/rel/cvsfiles}.
The client stores what is stored in checked-out directories (including
@file{CVS}). The way these are stored is totally compatible with
standard CVS. The server requires no storage other than the repository,
which also is totally compatible with standard CVS.
The server is started by @code{cvs server}. There is no particularly
compelling reason for this rather than making it a separate program
which shares a lot of sources with cvs.
The server can also be started by @code{cvs kserver}, in which case it
does an initial Kerberos authentication on stdin. If the authentication
succeeds, it subsequently runs identically to @code{cvs server}.
The current server implementation can use up huge amounts of memory
when transmitting a lot of data over a slow link (i.e. the network is
slower than the server can generate the data). Avoiding this is
tricky because of the goal of not having the server block on the
network when it has locks open (this could lock the repository for
hours if things are running smoothly or longer if not). Several
solutions are possible. The two-pass design would involve first
noting what versions of everything we need (with locks in place) and
then sending the data, blocking on the network, with no locks needed.
The lather-rinse-repeat design would involve doing things as it does
now until a certain amount of server memory is being used (10M?), then
releasing locks, and trying the whole update again (some of it is
presumably already done). One problem with this is getting merges to
work right. The two-pass design appears to be the more elegant of the
two (it actually reduces the amount of time that locks need to be in
place), but people have expressed concerns about whether it would be
slower (because it traverses the repository twice). It is not clear
whether this is a real problem (looking for whether a file needs to be
updated and actually checking it out are done separately already), but
I don't think anyone has investigated carefully. One hybrid approach
which avoids the problem with merges would be to start out in one-pass
mode and switch to two-pass mode if data is backing up--but this
complicates the code and should be undertaken only if the pure
two-pass design is shown to be flawed.
@node How To
@chapter How to add more remote commands
It's the usual simple twelve step process. Let's say you're making
the existing @code{cvs fix} command work remotely.
@itemize @bullet
@item
Add a declaration for the @code{fix} function, which already implements
the @code{cvs fix} command, to @file{server.c}.
@item
Now, the client side.
Add a function @code{client_fix} to @file{client.c}, which calls
@code{parse_cvsroot} and then calls the usual @code{fix} function.
@item
Add a declaration for @code{client_fix} to @file{client.h}.
@item
Add @code{client_fix} to the "fix" entry in the table of commands in
@file{main.c}.
@item
Now for the server side.
Add the @code{serve_fix} routine to @file{server.c}; make it do:
@example @code
static void
serve_fix (arg)
char *arg;
@{
do_cvs_command (fix);
@}
@end example
@item
Add the server command @code{"fix"} to the table of requests in @file{server.c}.
@item
The @code{fix} function can now be entered in three different situations:
local (the old situation), client, and server. On the server side it probably
will not need any changes to cope.
Modify the @code{fix} function so that if it is run when the variable
@code{client_active} is set, it starts the server, sends over parsed
arguments and possibly files, sends a "fix" command to the server,
and handles responses from the server. Sample code:
@example @code
if (!client_active) @{
/* Do whatever you used to do */
@} else @{
/* We're the local client. Fire up the remote server. */
start_server ();
if (local)
if (fprintf (to_server, "Argument -l\n") == EOF)
error (1, errno, "writing to server");
send_option_string (options);
send_files (argc, argv, local);
if (fprintf (to_server, "fix\n") == EOF)
error (1, errno, "writing to server");
err = get_responses_and_close ();
@}
@end example
@item
Build it locally. Copy the new version into somewhere on the
remote system, in your path so that @code{rsh host cvs} finds it.
Now you can test it.
@item
You may want to set the environment variable @code{CVS_CLIENT_PORT} to
-1 to prevent the client from contacting the server via a direct TCP
link. That will force the client to fall back to using @code{rsh},
which will run your new binary.
@item
Set the environment variable @code{CVS_CLIENT_LOG} to a filename prefix
such as @file{/tmp/cvslog}. Whenever you run a remote CVS command,
the commands and responses sent across the client/server connection
will be logged in @file{/tmp/cvslog.in} and @file{/tmp/cvslog.out}.
Examine them for problems while you're testing.
@end itemize
This should produce a good first cut at a working remote @code{cvs fix}
command. You may have to change exactly how arguments are passed,
whether files or just their names are sent, and how some of the deeper
infrastructure of your command copes with remoteness.
@node Protocol Notes
@chapter Notes on the Protocol
A number of enhancements are possible:
@itemize @bullet
@item
The @code{Modified} request could be speeded up by sending diffs rather
than entire files. The client would need some way to keep the version
of the file which was originally checked out, which would double client
disk space requirements or require coordination with editors (e.g. maybe
it could use emacs numbered backups). This would also allow local
operation of @code{cvs diff} without arguments.
@item
Have the client keep a copy of some part of the repository. This allows
all of @code{cvs diff} and large parts of @code{cvs update} and
@code{cvs ci} to be local. The local copy could be made consistent with
the master copy at night (but if the master copy has been updated since
the latest nightly re-sync, then it would read what it needs to from the
master).
@item
Provide encryption using kerberos.
@item
The current procedure for @code{cvs update} is highly sub-optimal if
there are many modified files. One possible alternative would be to
have the client send a first request without the contents of every
modified file, then have the server tell it what files it needs. Note
the server needs to do the what-needs-to-be-updated check twice (or
more, if changes in the repository mean it has to ask the client for
more files), because it can't keep locks open while waiting for the
network. Perhaps this whole thing is irrelevant if client-side
repositories are implemented, and the rcsmerge is done by the client.
@end itemize
@node Protocol
@chapter The CVS client/server protocol
@menu
* Entries Lines::
* Modes::
* Requests::
* Responses::
* Example::
@end menu
@node Entries Lines
@section Entries Lines
Entries lines are transmitted as:
@example
/ @var{name} / @var{version} / @var{conflict} / @var{options} / @var{tag_or_date}
@end example
@var{tag_or_date} is either @samp{T} @var{tag} or @samp{D} @var{date}
or empty. If it is followed by a slash, anything after the slash
shall be silently ignored.
@var{version} can be empty, or start with @samp{0} or @samp{-}, for no
user file, new user file, or user file to be removed, respectively.
@var{conflict}, if it starts with @samp{+}, indicates that the file had
conflicts in it. The rest of @var{conflict} is @samp{=} if the
timestamp matches the file, or anything else if it doesn't. If
@var{conflict} does not start with a @samp{+}, it is silently ignored.
@node Modes
@section Modes
A mode is any number of repetitions of
@example
@var{mode-type} = @var{data}
@end example
separated by @samp{,}.
@var{mode-type} is an identifier composed of alphanumeric characters.
Currently specified: @samp{u} for user, @samp{g} for group, @samp{o} for
other, as specified in POSIX. If at all possible, give these their
POSIX meaning and use other mode-types for other behaviors. For
example, on VMS it shouldn't be hard to make the groups behave like
POSIX, but you would need to use ACLs for some cases.
@var{data} consists of any data not containing @samp{,}, @samp{\0} or
@samp{\n}. For @samp{u}, @samp{g}, and @samp{o} mode types, data
consists of alphanumeric characters, where @samp{r} means read, @samp{w}
means write, @samp{x} means execute, and unrecognized letters are
silently ignored.
@node Requests
@section Requests
File contents (noted below as @var{file transmission}) can be sent in
one of two forms. The simpler form is a number of bytes, followed by a
newline, followed by the specified number of bytes of file contents.
These are the entire contents of the specified file. Second, if both
client and server support @samp{gzip-file-contents}, a @samp{z} may
precede the length, and the `file contents' sent are actually compressed
with @samp{gzip}. The length specified is that of the compressed
version of the file.
In neither case are the file content followed by any additional data.
The transmission of a file will end with a newline iff that file (or its
compressed form) ends with a newline.
@table @code
@item Root @var{pathname} \n
Response expected: no.
Tell the server which @code{CVSROOT} to use.
@item Valid-responses @var{request-list} \n
Response expected: no.
Tell the server what responses the client will accept.
request-list is a space separated list of tokens.
@item valid-requests \n
Response expected: yes.
Ask the server to send back a @code{Valid-requests} response.
@item Repository @var{repository} \n
Response expected: no. Tell the server what repository to use. This
should be a directory name from a previous server response. Note that
this both gives a default for @code{Entry } and @code{Modified } and
also for @code{ci} and the other commands; normal usage is to send a
@code{Repository } for each directory in which there will be an
@code{Entry } or @code{Modified }, and then a final @code{Repository }
for the original directory, then the command.
@item Directory @var{local-directory} \n
Additional data: @var{repository} \n. This is like @code{Repository},
but the local name of the directory may differ from the repository name.
If the client uses this request, it affects the way the server returns
pathnames; see @ref{Responses}. @var{local-directory} is relative to
the top level at which the command is occurring (i.e. the last
@code{Directory} or @code{Repository} which is sent before the command).
@item Max-dotdot @var{level} \n
Tell the server that @var{level} levels of directories above the
directory which @code{Directory} requests are relative to will be
needed. For example, if the client is planning to use a
@code{Directory} request for @file{../../foo}, it must send a
@code{Max-dotdot} request with a @var{level} of at least 2.
@code{Max-dotdot} must be sent before the first @code{Directory}
request.
@item Static-directory \n
Response expected: no. Tell the server that the directory most recently
specified with @code{Repository} or @code{Directory} should not have
additional files checked out unless explicitly requested. The client
sends this if the @code{Entries.Static} flag is set, which is controlled
by the @code{Set-static-directory} and @code{Clear-static-directory}
responses.
@item Sticky @var{tagspec} \n
Response expected: no. Tell the server that the directory most recently
specified with @code{Repository} has a sticky tag or date @var{tagspec}.
The first character of @var{tagspec} is @samp{T} for a tag, or @samp{D}
for a date. The remainder of @var{tagspec} contains the actual tag or
date.
@item Checkin-prog @var{program} \n
Response expected: no. Tell the server that the directory most recently
specified with @code{Directory} has a checkin program @var{program}.
Such a program would have been previously set with the
@code{Set-checkin-prog} response.
@item Update-prog @var{program} \n
Response expected: no. Tell the server that the directory most recently
specified with @code{Directory} has an update program @var{program}.
Such a program would have been previously set with the
@code{Set-update-prog} response.
@item Entry @var{entry-line} \n
Response expected: no. Tell the server what version of a file is on the
local machine. The name in @var{entry-line} is a name relative to the
directory most recently specified with @code{Repository}. If the user
is operating on only some files in a directory, @code{Entry} requests
for only those files need be included. If an @code{Entry} request is
sent without @code{Modified}, @code{Unchanged}, or @code{Lost} for that
file the meaning depends on whether @code{UseUnchanged} has been sent;
if it has been it means the file is lost, if not it means the file is
unchanged.
@item Modified @var{filename} \n
Response expected: no. Additional data: mode, \n, file transmission.
Send the server a copy of one locally modified file. @var{filename} is
relative to the most recent repository sent with @code{Repository}. If
the user is operating on only some files in a directory, only those
files need to be included. This can also be sent without @code{Entry},
if there is no entry for the file.
@item Lost @var{filename} \n
Response expected: no. Tell the server that @var{filename} no longer
exists. The name is relative to the most recent repository sent with
@code{Repository}. This is used for any case in which @code{Entry} is
being sent but the file no longer exists. If the client has issued the
@code{UseUnchanged} request, then this request is not used.
@item Unchanged @var{filename} \n
Response expected: no. Tell the server that @var{filename} has not been
modified in the checked out directory. The name is relative to the most
recent repository sent with @code{Repository}. This request can only be
issued if @code{UseUnchanged} has been sent.
@item UseUnchanged \n
Response expected: no. Tell the server that the client will be
indicating unmodified files with @code{Unchanged}, and that files for
which no information is sent are nonexistent on the client side, not
unchanged. This is necessary for correct behavior since only the server
knows what possible files may exist, and thus what files are
nonexistent.
@item Argument @var{text} \n
Response expected: no.
Save argument for use in a subsequent command. Arguments
accumulate until an argument-using command is given, at which point
they are forgotten.
@item Argumentx @var{text} \n
Response expected: no. Append \n followed by text to the current
argument being saved.
@item Global_option @var{option} \n
Transmit one of the global options @samp{-q}, @samp{-Q}, @samp{-l},
@samp{-t}, @samp{-r}, or @samp{-n}. @var{option} must be one of those
strings, no variations (such as combining of options) are allowed. For
graceful handling of @code{valid-requests}, it is probably better to
make new global options separate requests, rather than trying to add
them to this request.
@item expand-modules \n
Response expected: yes. Expand the modules which are specified in the
arguments. Returns the data in @code{Module-expansion} responses. Note
that the server can assume that this is checkout or export, not rtag or
rdiff; the latter do not access the working directory and thus have no
need to expand modules on the client side.
@item co \n
@itemx update \n
@itemx ci \n
@itemx diff \n
@itemx tag \n
@itemx status \n
@itemx log \n
@itemx add \n
@itemx remove \n
@itemx rdiff \n
@itemx rtag \n
@itemx import \n
@itemx admin \n
@itemx export \n
@itemx history \n
@itemx release \n
Response expected: yes. Actually do a cvs command. This uses any
previous @code{Argument}, @code{Repository}, @code{Entry},
@code{Modified}, or @code{Lost} requests, if they have been sent. The
last @code{Repository} sent specifies the working directory at the time
of the operation. No provision is made for any input from the user.
This means that @code{ci} must use a @code{-m} argument if it wants to
specify a log message.
@item update-patches \n
This request does not actually do anything. It is used as a signal that
the server is able to generate patches when given an @code{update}
request. The client must issue the @code{-u} argument to @code{update}
in order to receive patches.
@item gzip-file-contents @var{level} \n
This request asks the server to filter files it sends to the client
through the @samp{gzip} program, using the specified level of
compression. If this request is not made, the server must not do any
compression.
This is only a hint to the server. It may still decide (for example, in
the case of very small files, or files that already appear to be
compressed) not to do the compression. Compression is indicated by a
@samp{z} preceding the file length.
Availability of this request in the server indicates to the client that
it may compress files sent to the server, regardless of whether the
client actually uses this request.
@item @var{other-request} @var{text} \n
Response expected: yes.
Any unrecognized request expects a response, and does not
contain any additional data. The response will normally be something like
@samp{error unrecognized request}, but it could be a different error if
a previous command which doesn't expect a response produced an error.
@end table
When the client is done, it drops the connection.
@node Responses
@section Responses
After a command which expects a response, the server sends however many
of the following responses are appropriate. Pathnames are of the actual
files operated on (i.e. they do not contain @samp{,v} endings), and are
suitable for use in a subsequent @code{Repository} request. However, if
the client has used the @code{Directory} request, then it is instead a
local directory name relative to the directory in which the command was
given (i.e. the last @code{Directory} before the command). Then a
newline and a repository name (the pathname which is sent if
@code{Directory} is not used). Then the slash and the filename. For
example, for a file @file{i386.mh} which is in the local directory
@file{gas.clean/config} and for which the repository is
@file{/rel/cvsfiles/devo/gas/config}:
@example
gas.clean/config/
/rel/cvsfiles/devo/gas/config/i386.mh
@end example
Any response always ends with @samp{error} or @samp{ok}. This indicates
that the response is over.
@table @code
@item Valid-requests @var{request-list} \n
Indicate what requests the server will accept. @var{request-list}
is a space separated list of tokens. If the server supports sending
patches, it will include @samp{update-patches} in this list. The
@samp{update-patches} request does not actually do anything.
@item Checked-in @var{pathname} \n
Additional data: New Entries line, \n. This means a file @var{pathname}
has been successfully operated on (checked in, added, etc.). name in
the Entries line is the same as the last component of @var{pathname}.
@item New-entry @var{pathname} \n
Additional data: New Entries line, \n. Like @code{Checked-in}, but the
file is not up to date.
@item Updated @var{pathname} \n
Additional data: New Entries line, \n, mode, \n, file transmission. A
new copy of the file is enclosed. This is used for a new revision of an
existing file, or for a new file, or for any other case in which the
local (client-side) copy of the file needs to be updated, and after
being updated it will be up to date. If any directory in pathname does
not exist, create it.
@item Merged @var{pathname} \n
This is just like @code{Updated} and takes the same additional data,
with the one difference that after the new copy of the file is enclosed,
it will still not be up to date. Used for the results of a merge, with
or without conflicts.
@item Patched @var{pathname} \n
This is just like @code{Updated} and takes the same additional data,
with the one difference that instead of sending a new copy of the file,
the server sends a patch produced by @samp{diff -u}. This client must
apply this patch, using the @samp{patch} program, to the existing file.
This will only be used when the client has an exact copy of an earlier
revision of a file. This response is only used if the @code{update}
command is given the @samp{-u} argument.
@item Checksum @var{checksum}\n
The @var{checksum} applies to the next file sent over via
@code{Updated}, @code{Merged}, or @code{Patched}. In the case of
@code{Patched}, the checksum applies to the file after being patched,
not to the patch itself. The client should compute the checksum itself,
after receiving the file or patch, and signal an error if the checksums
do not match. The checksum is the 128 bit MD5 checksum represented as
32 hex digits. This response is optional, and is only used if the
client supports it (as judged by the @code{Valid-responses} request).
@item Copy-file @var{pathname} \n
Additional data: @var{newname} \n. Copy file @var{pathname} to
@var{newname} in the same directory where it already is. This does not
affect @code{CVS/Entries}.
@item Removed @var{pathname} \n
The file has been removed from the repository (this is the case where
cvs prints @samp{file foobar.c is no longer pertinent}).
@item Remove-entry @var{pathname} \n
The file needs its entry removed from @code{CVS/Entries}, but the file
itself is already gone (this happens in response to a @code{ci} request
which involves committing the removal of a file).
@item Set-static-directory @var{pathname} \n
This instructs the client to set the @code{Entries.Static} flag, which
it should then send back to the server in a @code{Static-directory}
request whenever the directory is operated on. @var{pathname} ends in a
slash; its purpose is to specify a directory, not a file within a
directory.
@item Clear-static-directory @var{pathname} \n
Like @code{Set-static-directory}, but clear, not set, the flag.
@item Set-sticky @var{pathname} \n
Additional data: @var{tagspec} \n. Tell the client to set a sticky tag
or date, which should be supplied with the @code{Sticky} request for
future operations. @var{pathname} ends in a slash; its purpose is to
specify a directory, not a file within a directory. The first character
of @var{tagspec} is @samp{T} for a tag, or @samp{D} for a date. The
remainder of @var{tagspec} contains the actual tag or date.
@item Clear-sticky @var{pathname} \n
Clear any sticky tag or date set by @code{Set-sticky}.
@item Set-checkin-prog @var{dir} \n
Additional data: @var{prog} \n. Tell the client to set a checkin
program, which should be supplied with the @code{Checkin-prog} request
for future operations.
@item Set-update-prog @var{dir} \n
Additional data: @var{prog} \n. Tell the client to set an update
program, which should be supplied with the @code{Update-prog} request
for future operations.
@item Module-expansion @var{pathname} \n
Return a file or directory which is included in a particular module.
@var{pathname} is relative to cvsroot, unlike most pathnames in
responses.
@item M @var{text} \n
A one-line message for the user.
@item E @var{text} \n
Same as @code{M} but send to stderr not stdout.
@item error @var{errno-code} @samp{ } @var{text} \n
The command completed with an error. @var{errno-code} is a symbolic
error code (e.g. @code{ENOENT}); if the server doesn't support this
feature, or if it's not appropriate for this particular message, it just
omits the errno-code (in that case there are two spaces after
@samp{error}). Text is an error message such as that provided by
strerror(), or any other message the server wants to use.
@item ok \n
The command completed successfully.
@end table
@node Example
@section Example
Lines beginning with @samp{c>} are sent by the client; lines beginning
with @samp{s>} are sent by the server; lines beginning with @samp{#} are
not part of the actual exchange.
@example
c> Root /rel/cvsfiles
# In actual practice the lists of valid responses and requests would
# be longer
c> Valid-responses Updated Checked-in M ok error
c> valid-requests
s> Valid-requests Root co Modified Entry Repository ci Argument Argumentx
s> ok
# cvs co devo/foo
c> Argument devo/foo
c> co
s> Updated /rel/cvsfiles/devo/foo/foo.c
s> /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
s> 26
s> int mein () @{ abort (); @}
s> Updated /rel/cvsfiles/devo/foo/Makefile
s> /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
s> 28
s> foo: foo.c
s> $(CC) -o foo $<
s> ok
# In actual practice the next part would be a separate connection.
# Here it is shown as part of the same one.
c> Repository /rel/cvsfiles/devo/foo
# foo.c relative to devo/foo just set as Repository.
c> Entry /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
c> Entry /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993//
c> Modified foo.c
c> 26
c> int main () @{ abort (); @}
# cvs ci -m <log message> foo.c
c> Argument -m
c> Argument Well, you see, it took me hours and hours to find this typo and I
c> Argumentx searched and searched and eventually had to ask John for help.
c> Argument foo.c
c> ci
s> Checked-in /rel/cvsfiles/devo/foo/foo.c
s> /foo.c/1.5/ Mon Apr 19 15:54:22 CDT 1993//
s> M Checking in foo.c;
s> M /cygint/rel/cvsfiles/devo/foo/foo.c,v <-- foo.c
s> M new revision: 1.5; previous revision: 1.4
s> M done
s> ok
@end example
@bye

View File

@ -0,0 +1,20 @@
#
#ident "@(#)cvs/examples:$Name: $:$Id: checkoutlist,v 1.2 1995/11/14 23:24:49 woods Exp $"
#
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
#
rcstemplate
wrap
unwrap

View File

@ -0,0 +1,29 @@
#
#ident "@(#)cvs/examples:$Name: $:$Id: cvswrappers,v 1.3 1995/11/14 23:23:11 woods Exp $"
#
# This file describes wrappers and other binary files to CVS.
#
# Wrappers are the concept where directories of files are to be
# treated as a single file. The intended use is to wrap up a wrapper
# into a single tar such that the tar archive can be treated as a
# single binary file in CVS.
#
# To solve the problem effectively, it was also necessary to be able to
# prevent rcsmerge from merging these files.
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
#
# and value is a single-quote delimited value.
#
#
*.nib -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
*.rtfd -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
*.draw -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s'
*.tiff -m 'COPY'

View File

@ -0,0 +1,7 @@
CVS:
CVS: WARNING: You are commiting a change to the main source repository.
CVS:
CVS: This change will be immediately available to all other users
CVS: of this repository! Please be sure your changes have been
CVS: adequately tested.
CVS:

View File

@ -0,0 +1,25 @@
#
#ident "@(#)cvs/examples:$Name: $:$Id: taginfo,v 1.3 1995/11/14 23:27:52 woods Exp $"
#
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
#
DEFAULT $CVSROOT/CVSROOT/tag_logging_program

View File

@ -0,0 +1,21 @@
#! /bin/sh
#
# unwrap - extract the combined package (created with wrap)
#
#ident "@(#)cvs/examples:$Name: $:$Id: unwrap,v 1.1 1995/11/14 23:20:30 woods Exp $"
# move the file to a new name with an extension
rm -rf $1.cvswrap
mv $1 $1.cvswrap
# untar the file
if `gzip -t $1.cvswrap > /dev/null 2>&1`
then
gzcat -d $1.cvswrap | gnutar --preserve --sparse -x -f -
else
gnutar --preserve --sparse -x -f $1.cvswrap
fi
# remove the original
rm -rf $1.cvswrap

View File

@ -0,0 +1,21 @@
#! /bin/sh
#
# wrap - Combine a directory into a single tar package.
#
#ident "@(#)cvs/examples:$Name: $:$Id: wrap,v 1.1 1995/11/14 23:20:32 woods Exp $"
# This script is always called with the current directory set to
# where the file to be combined exists. but i may get called with a
# path to where cvs first started executing. (this probably should be
# fixed in cvs) so strip out all of the directory information. The
# first sed expression will only work if the path has a leading /
# if it doesn't the one in the if statement will work.
DIRNAME=`echo $1 | sed -e "s|/.*/||g"`
if [ ! -d $DIRNAME ] ; then
DIRNAME=`echo $1 | sed -e "s|.*/||g"`
fi
#
# Now tar up the directory but we now will only get a relative path
# even if the user did a cvs commit . at the top.
#
gnutar --preserve --sparse -cf - $DIRNAME | gzip --no-name --best -c > $2

View File

@ -0,0 +1,47 @@
/* error.h -- declaration for error-reporting function
Copyright (C) 1995 Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _error_h_
#define _error_h_
#ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
# define __attribute__(Spec) /* empty */
# endif
/* The __-protected variants of `format' and `printf' attributes
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __format__ format
# define __printf__ printf
# endif
#endif
#if __STDC__
void error (int, int, const char *, ...) \
__attribute__ ((__format__ (__printf__, 3, 4)));
#else
void error ();
#endif
/* If non-zero, error will use the CVS protocol to report error
messages. This will only be set in the CVS server parent process;
most other code is run via do_cvs_command, which forks off a child
process and packages up its stderr in the protocol. */
extern int error_use_protocol;
#endif /* _error_h_ */

View File

@ -0,0 +1,640 @@
/* filesubr.c --- subroutines for dealing with files
Jim Blandy <jimb@cyclic.com>
This file is part of GNU CVS.
GNU CVS is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* These functions were moved out of subr.c because they need different
definitions under operating systems (like, say, Windows NT) with different
file system semantics. */
#include "cvs.h"
#ifndef lint
static const char rcsid[] = "$CVSid:$";
USE(rcsid);
#endif
/*
* I don't know of a convenient way to test this at configure time, or else
* I'd certainly do it there.
*/
#if defined(NeXT)
#define LOSING_TMPNAM_FUNCTION
#endif
static int deep_remove_dir PROTO((const char *path));
/*
* Copies "from" to "to".
*/
void
copy_file (from, to)
const char *from;
const char *to;
{
struct stat sb;
struct utimbuf t;
int fdin, fdout;
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
#endif
if (noexec)
return;
if ((fdin = open (from, O_RDONLY)) < 0)
error (1, errno, "cannot open %s for copying", from);
if (fstat (fdin, &sb) < 0)
error (1, errno, "cannot fstat %s", from);
if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
error (1, errno, "cannot create %s for copying", to);
if (sb.st_size > 0)
{
char buf[BUFSIZ];
int n;
for (;;)
{
n = read (fdin, buf, sizeof(buf));
if (n == -1)
{
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
error (1, errno, "cannot read file %s for copying", from);
}
else if (n == 0)
break;
if (write(fdout, buf, n) != n) {
error (1, errno, "cannot write file %s for copying", to);
}
}
#ifdef HAVE_FSYNC
if (fsync (fdout))
error (1, errno, "cannot fsync file %s after copying", to);
#endif
}
if (close (fdin) < 0)
error (0, errno, "cannot close %s", from);
if (close (fdout) < 0)
error (1, errno, "cannot close %s", to);
/* now, set the times for the copied file to match those of the original */
memset ((char *) &t, 0, sizeof (t));
t.actime = sb.st_atime;
t.modtime = sb.st_mtime;
(void) utime (to, &t);
}
/* FIXME-krp: these functions would benefit from caching the char * &
stat buf. */
/*
* Returns non-zero if the argument file is a directory, or is a symbolic
* link which points to a directory.
*/
int
isdir (file)
const char *file;
{
struct stat sb;
if (stat (file, &sb) < 0)
return (0);
return (S_ISDIR (sb.st_mode));
}
/*
* Returns non-zero if the argument file is a symbolic link.
*/
int
islink (file)
const char *file;
{
#ifdef S_ISLNK
struct stat sb;
if (lstat (file, &sb) < 0)
return (0);
return (S_ISLNK (sb.st_mode));
#else
return (0);
#endif
}
/*
* Returns non-zero if the argument file exists.
*/
int
isfile (file)
const char *file;
{
return isaccessible(file, F_OK);
}
/*
* Returns non-zero if the argument file is readable.
*/
int
isreadable (file)
const char *file;
{
return isaccessible(file, R_OK);
}
/*
* Returns non-zero if the argument file is writable.
*/
int
iswritable (file)
const char *file;
{
return isaccessible(file, W_OK);
}
/*
* Returns non-zero if the argument file is accessable according to
* mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
* bits set.
*/
int
isaccessible (file, mode)
const char *file;
const int mode;
{
#ifdef SETXID_SUPPORT
struct stat sb;
int umask = 0;
int gmask = 0;
int omask = 0;
int uid;
if (stat(file, &sb) == -1)
return 0;
if (mode == F_OK)
return 1;
uid = geteuid();
if (uid == 0) /* superuser */
{
if (mode & X_OK)
return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
else
return 1;
}
if (mode & R_OK)
{
umask |= S_IRUSR;
gmask |= S_IRGRP;
omask |= S_IROTH;
}
if (mode & W_OK)
{
umask |= S_IWUSR;
gmask |= S_IWGRP;
omask |= S_IWOTH;
}
if (mode & X_OK)
{
umask |= S_IXUSR;
gmask |= S_IXGRP;
omask |= S_IXOTH;
}
if (sb.st_uid == uid)
return (sb.st_mode & umask) == umask;
else if (sb.st_gid == getegid())
return (sb.st_mode & gmask) == gmask;
else
return (sb.st_mode & omask) == omask;
#else
return access(file, mode) == 0;
#endif
}
/*
* Open a file and die if it fails
*/
FILE *
open_file (name, mode)
const char *name;
const char *mode;
{
FILE *fp;
if ((fp = fopen (name, mode)) == NULL)
error (1, errno, "cannot open %s", name);
return (fp);
}
/*
* Make a directory and die if it fails
*/
void
make_directory (name)
const char *name;
{
struct stat sb;
if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
error (0, 0, "%s already exists but is not a directory", name);
if (!noexec && mkdir (name, 0777) < 0)
error (1, errno, "cannot make directory %s", name);
}
/*
* Make a path to the argument directory, printing a message if something
* goes wrong.
*/
void
make_directories (name)
const char *name;
{
char *cp;
if (noexec)
return;
if (mkdir (name, 0777) == 0 || errno == EEXIST)
return;
if (! existence_error (errno))
{
error (0, errno, "cannot make path to %s", name);
return;
}
if ((cp = strrchr (name, '/')) == NULL)
return;
*cp = '\0';
make_directories (name);
*cp++ = '/';
if (*cp == '\0')
return;
(void) mkdir (name, 0777);
}
/*
* Change the mode of a file, either adding write permissions, or removing
* all write permissions. Either change honors the current umask setting.
*/
void
xchmod (fname, writable)
char *fname;
int writable;
{
struct stat sb;
mode_t mode, oumask;
if (stat (fname, &sb) < 0)
{
if (!noexec)
error (0, errno, "cannot stat %s", fname);
return;
}
oumask = umask (0);
(void) umask (oumask);
if (writable)
{
mode = sb.st_mode | (~oumask
& (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
| ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
| ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
}
else
{
mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
}
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
(server_active) ? 'S' : ' ', fname, mode);
#else
(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
#endif
if (noexec)
return;
if (chmod (fname, mode) < 0)
error (0, errno, "cannot change mode of file %s", fname);
}
/*
* Rename a file and die if it fails
*/
void
rename_file (from, to)
const char *from;
const char *to;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
#endif
if (noexec)
return;
if (rename (from, to) < 0)
error (1, errno, "cannot rename file %s to %s", from, to);
}
/*
* link a file, if possible.
*/
int
link_file (from, to)
const char *from;
const char *to;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> link(%s,%s)\n",
(server_active) ? 'S' : ' ', from, to);
#else
(void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
#endif
if (noexec)
return (0);
return (link (from, to));
}
/*
* unlink a file, if possible.
*/
int
unlink_file (f)
const char *f;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink(%s)\n",
(server_active) ? 'S' : ' ', f);
#else
(void) fprintf (stderr, "-> unlink(%s)\n", f);
#endif
if (noexec)
return (0);
return (unlink (f));
}
/*
* Unlink a file or dir, if possible. If it is a directory do a deep
* removal of all of the files in the directory. Return -1 on error
* (in which case errno is set).
*/
int
unlink_file_dir (f)
const char *f;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
(server_active) ? 'S' : ' ', f);
#else
(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
#endif
if (noexec)
return (0);
if (unlink (f) != 0)
{
/* under NEXTSTEP errno is set to return EPERM if
* the file is a directory,or if the user is not
* allowed to read or write to the file.
* [This is probably a bug in the O/S]
* other systems will return EISDIR to indicate
* that the path is a directory.
*/
if (errno == EISDIR || errno == EPERM)
return deep_remove_dir (f);
else
/* The file wasn't a directory and some other
* error occured
*/
return -1;
}
/* We were able to remove the file from the disk */
return 0;
}
/* Remove a directory and everything it contains. Returns 0 for
* success, -1 for failure (in which case errno is set).
*/
static int
deep_remove_dir (path)
const char *path;
{
DIR *dirp;
struct dirent *dp;
char buf[PATH_MAX];
if ( rmdir (path) != 0 && errno == ENOTEMPTY )
{
if ((dirp = opendir (path)) == NULL)
/* If unable to open the directory return
* an error
*/
return -1;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
strcmp (dp->d_name, "..") == 0)
continue;
sprintf (buf, "%s/%s", path, dp->d_name);
if (unlink (buf) != 0 )
{
if (errno == EISDIR || errno == EPERM)
{
if (deep_remove_dir (buf))
{
closedir (dirp);
return -1;
}
}
else
{
/* buf isn't a directory, or there are
* some sort of permision problems
*/
closedir (dirp);
return -1;
}
}
}
closedir (dirp);
return rmdir (path);
}
/* Was able to remove the directory return 0 */
return 0;
}
/* Read NCHARS bytes from descriptor FD into BUF.
Return the number of characters successfully read.
The number returned is always NCHARS unless end-of-file or error. */
static size_t
block_read (fd, buf, nchars)
int fd;
char *buf;
size_t nchars;
{
char *bp = buf;
size_t nread;
do
{
nread = read (fd, bp, nchars);
if (nread == (size_t)-1)
{
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
return (size_t)-1;
}
if (nread == 0)
break;
bp += nread;
nchars -= nread;
} while (nchars != 0);
return bp - buf;
}
/*
* Compare "file1" to "file2". Return non-zero if they don't compare exactly.
*/
int
xcmp (file1, file2)
const char *file1;
const char *file2;
{
char *buf1, *buf2;
struct stat sb1, sb2;
int fd1, fd2;
int ret;
if ((fd1 = open (file1, O_RDONLY)) < 0)
error (1, errno, "cannot open file %s for comparing", file1);
if ((fd2 = open (file2, O_RDONLY)) < 0)
error (1, errno, "cannot open file %s for comparing", file2);
if (fstat (fd1, &sb1) < 0)
error (1, errno, "cannot fstat %s", file1);
if (fstat (fd2, &sb2) < 0)
error (1, errno, "cannot fstat %s", file2);
/* A generic file compare routine might compare st_dev & st_ino here
to see if the two files being compared are actually the same file.
But that won't happen in CVS, so we won't bother. */
if (sb1.st_size != sb2.st_size)
ret = 1;
else if (sb1.st_size == 0)
ret = 0;
else
{
/* FIXME: compute the optimal buffer size by computing the least
common multiple of the files st_blocks field */
size_t buf_size = 8 * 1024;
size_t read1;
size_t read2;
buf1 = xmalloc (buf_size);
buf2 = xmalloc (buf_size);
do
{
read1 = block_read (fd1, buf1, buf_size);
if (read1 == (size_t)-1)
error (1, errno, "cannot read file %s for comparing", file1);
read2 = block_read (fd2, buf2, buf_size);
if (read2 == (size_t)-1)
error (1, errno, "cannot read file %s for comparing", file2);
/* assert (read1 == read2); */
ret = memcmp(buf1, buf2, read1);
} while (ret == 0 && read1 == buf_size);
free (buf1);
free (buf2);
}
(void) close (fd1);
(void) close (fd2);
return (ret);
}
#ifdef LOSING_TMPNAM_FUNCTION
char *tmpnam(char *s)
{
static char value[L_tmpnam+1];
if (s){
strcpy(s,"/tmp/cvsXXXXXX");
mktemp(s);
return s;
}else{
strcpy(value,"/tmp/cvsXXXXXX");
mktemp(s);
return value;
}
}
#endif
/* Return non-zero iff FILENAME is absolute.
Trivial under Unix, but more complicated under other systems. */
int
isabsolute (filename)
const char *filename;
{
return filename[0] == '/';
}
/* Return a pointer into PATH's last component. */
char *
last_component (path)
char *path;
{
char *last = strrchr (path, '/');
if (last)
return last + 1;
else
return path;
}

View File

@ -0,0 +1,126 @@
/* getline.c -- Replacement for GNU C library function getline
Copyright (C) 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#define NDEBUG
#include <assert.h>
#if STDC_HEADERS
#include <stdlib.h>
#else
char *malloc (), *realloc ();
#endif
/* Always add at least this many bytes when extending the buffer. */
#define MIN_CHUNK 64
/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
malloc (or NULL), pointing to *N characters of space. It is realloc'd
as necessary. Return the number of characters read (not including the
null terminator), or -1 on error or EOF. */
int
getstr (lineptr, n, stream, terminator, offset)
char **lineptr;
size_t *n;
FILE *stream;
char terminator;
int offset;
{
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
char *read_pos; /* Where we're reading into *LINEPTR. */
int ret;
if (!lineptr || !n || !stream)
return -1;
if (!*lineptr)
{
*n = MIN_CHUNK;
*lineptr = malloc (*n);
if (!*lineptr)
return -1;
}
nchars_avail = *n - offset;
read_pos = *lineptr + offset;
for (;;)
{
register int c = getc (stream);
/* We always want at least one char left in the buffer, since we
always (unless we get an error while reading the first char)
NUL-terminate the line buffer. */
assert(*n - nchars_avail == read_pos - *lineptr);
if (nchars_avail < 2)
{
if (*n > MIN_CHUNK)
*n *= 2;
else
*n += MIN_CHUNK;
nchars_avail = *n + *lineptr - read_pos;
*lineptr = realloc (*lineptr, *n);
if (!*lineptr)
return -1;
read_pos = *n - nchars_avail + *lineptr;
assert(*n - nchars_avail == read_pos - *lineptr);
}
if (c == EOF || ferror (stream))
{
/* Return partial line, if any. */
if (read_pos == *lineptr)
return -1;
else
break;
}
*read_pos++ = c;
nchars_avail--;
if (c == terminator)
/* Return the line. */
break;
}
/* Done - NUL terminate and return the number of chars read. */
*read_pos = '\0';
ret = read_pos - (*lineptr + offset);
return ret;
}
int
getline (lineptr, n, stream)
char **lineptr;
size_t *n;
FILE *stream;
{
return getstr (lineptr, n, stream, '\n', 0);
}

View File

@ -0,0 +1,15 @@
#ifndef _getline_h_
#define _getline_h_ 1
#include <stdio.h>
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
#define __PROTO(args) args
#else
#define __PROTO(args) ()
#endif /* GCC. */
int
getline __PROTO ((char **_lineptr, size_t *_n, FILE *_stream));
#endif /* _getline_h_ */

277
gnu/usr.bin/cvs/lib/md5.c Normal file
View File

@ -0,0 +1,277 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include "config.h"
#if HAVE_STRING_H || STDC_HEADERS
#include <string.h> /* for memcpy() */
#endif
/* Add prototype support. */
#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define PROTO(ARGS) ARGS
#else
#define PROTO(ARGS) ()
#endif
#endif
#include "md5.h"
void byteReverse PROTO ((unsigned char *buf, unsigned longs));
#ifndef ASM_MD5
/*
* Note: this code is harmless on little-endian machines.
*/
void byteReverse (buf, longs)
unsigned char *buf;
unsigned longs;
{
uint32 t;
do {
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
((unsigned)buf[1]<<8 | buf[0]);
*(uint32 *)buf = t;
buf += 4;
} while (--longs);
}
#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void
MD5Init(ctx)
struct MD5Context *ctx;
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void
MD5Update(ctx, buf, len)
struct MD5Context *ctx;
unsigned char const *buf;
unsigned len;
{
uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if ( t ) {
unsigned char *p = (unsigned char *)ctx->in + t;
t = 64-t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
MD5Final(digest, ctx)
unsigned char digest[16];
struct MD5Context *ctx;
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count-8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *)ctx->in);
byteReverse((unsigned char *)ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
#ifndef ASM_MD5
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void
MD5Transform(buf, in)
uint32 buf[4];
uint32 const in[16];
{
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
#endif

31
gnu/usr.bin/cvs/lib/md5.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef MD5_H
#define MD5_H
#if SIZEOF_LONG == 4
typedef unsigned long uint32;
#else
#if SIZEOF_INT == 4
typedef unsigned int uint32;
#else
Congratulations! You get to rewrite this code so that it does not require
a 32-bit integer type! (Or maybe you just need to reconfigure.)
#endif
#endif
struct MD5Context {
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
void MD5Init PROTO((struct MD5Context *context));
void MD5Update PROTO((struct MD5Context *context, unsigned char const *buf, unsigned len));
void MD5Final PROTO((unsigned char digest[16], struct MD5Context *context));
void MD5Transform PROTO((uint32 buf[4], uint32 const in[16]));
/*
* This is needed to make RSAREF happy on some MS-DOS compilers.
*/
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */

533
gnu/usr.bin/cvs/lib/run.c Normal file
View File

@ -0,0 +1,533 @@
/* run.c --- routines for executing subprocesses.
This file is part of GNU CVS.
GNU CVS is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "cvs.h"
#ifdef HAVE_VPRINTF
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#include <stdarg.h>
#define VA_START(args, lastarg) va_start(args, lastarg)
#else
#include <varargs.h>
#define VA_START(args, lastarg) va_start(args)
#endif
#else
#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
#endif
static void run_add_arg PROTO((const char *s));
static void run_init_prog PROTO((void));
extern char *strtok ();
/*
* To exec a program under CVS, first call run_setup() to setup any initial
* arguments. The options to run_setup are essentially like printf(). The
* arguments will be parsed into whitespace separated words and added to the
* global run_argv list.
*
* Then, optionally call run_arg() for each additional argument that you'd like
* to pass to the executed program.
*
* Finally, call run_exec() to execute the program with the specified arguments.
* The execvp() syscall will be used, so that the PATH is searched correctly.
* File redirections can be performed in the call to run_exec().
*/
static char *run_prog;
static char **run_argv;
static int run_argc;
static int run_argc_allocated;
/* VARARGS */
#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
void
run_setup (const char *fmt,...)
#else
void
run_setup (fmt, va_alist)
char *fmt;
va_dcl
#endif
{
#ifdef HAVE_VPRINTF
va_list args;
#endif
char *cp;
int i;
run_init_prog ();
/* clean out any malloc'ed values from run_argv */
for (i = 0; i < run_argc; i++)
{
if (run_argv[i])
{
free (run_argv[i]);
run_argv[i] = (char *) 0;
}
}
run_argc = 0;
/* process the varargs into run_prog */
#ifdef HAVE_VPRINTF
VA_START (args, fmt);
(void) vsprintf (run_prog, fmt, args);
va_end (args);
#else
(void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
/* put each word into run_argv, allocating it as we go */
for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
run_add_arg (cp);
}
void
run_arg (s)
const char *s;
{
run_add_arg (s);
}
/* VARARGS */
#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__))
void
run_args (const char *fmt,...)
#else
void
run_args (fmt, va_alist)
char *fmt;
va_dcl
#endif
{
#ifdef HAVE_VPRINTF
va_list args;
#endif
run_init_prog ();
/* process the varargs into run_prog */
#ifdef HAVE_VPRINTF
VA_START (args, fmt);
(void) vsprintf (run_prog, fmt, args);
va_end (args);
#else
(void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
/* and add the (single) argument to the run_argv list */
run_add_arg (run_prog);
}
static void
run_add_arg (s)
const char *s;
{
/* allocate more argv entries if we've run out */
if (run_argc >= run_argc_allocated)
{
run_argc_allocated += 50;
run_argv = (char **) xrealloc ((char *) run_argv,
run_argc_allocated * sizeof (char **));
}
if (s)
run_argv[run_argc++] = xstrdup (s);
else
run_argv[run_argc] = (char *) 0; /* not post-incremented on purpose! */
}
static void
run_init_prog ()
{
/* make sure that run_prog is allocated once */
if (run_prog == (char *) 0)
run_prog = xmalloc (10 * 1024); /* 10K of args for _setup and _arg */
}
int
run_exec (stin, stout, sterr, flags)
char *stin;
char *stout;
char *sterr;
int flags;
{
int shin, shout, sherr;
int mode_out, mode_err;
int status;
int rc = -1;
int rerrno = 0;
int pid, w;
#ifdef POSIX_SIGNALS
sigset_t sigset_mask, sigset_omask;
struct sigaction act, iact, qact;
#else
#ifdef BSD_SIGNALS
int mask;
struct sigvec vec, ivec, qvec;
#else
RETSIGTYPE (*istat) (), (*qstat) ();
#endif
#endif
if (trace)
{
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> system(", (server_active) ? 'S' : ' ');
#else
(void) fprintf (stderr, "-> system(");
#endif
run_print (stderr);
(void) fprintf (stderr, ")\n");
}
if (noexec && (flags & RUN_REALLY) == 0)
return (0);
/* make sure that we are null terminated, since we didn't calloc */
run_add_arg ((char *) 0);
/* setup default file descriptor numbers */
shin = 0;
shout = 1;
sherr = 2;
/* set the file modes for stdout and stderr */
mode_out = mode_err = O_WRONLY | O_CREAT;
mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC);
mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC);
if (stin && (shin = open (stin, O_RDONLY)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for reading (prog %s)",
stin, run_argv[0]);
goto out0;
}
if (stout && (shout = open (stout, mode_out, 0666)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for writing (prog %s)",
stout, run_argv[0]);
goto out1;
}
if (sterr && (flags & RUN_COMBINED) == 0)
{
if ((sherr = open (sterr, mode_err, 0666)) == -1)
{
rerrno = errno;
error (0, errno, "cannot open %s for writing (prog %s)",
sterr, run_argv[0]);
goto out2;
}
}
/* Make sure we don't flush this twice, once in the subprocess. */
fflush (stdout);
fflush (stderr);
/* The output files, if any, are now created. Do the fork and dups */
#ifdef HAVE_VFORK
pid = vfork ();
#else
pid = fork ();
#endif
if (pid == 0)
{
if (shin != 0)
{
(void) dup2 (shin, 0);
(void) close (shin);
}
if (shout != 1)
{
(void) dup2 (shout, 1);
(void) close (shout);
}
if (flags & RUN_COMBINED)
(void) dup2 (1, 2);
else if (sherr != 2)
{
(void) dup2 (sherr, 2);
(void) close (sherr);
}
/* dup'ing is done. try to run it now */
(void) execvp (run_argv[0], run_argv);
error (0, errno, "cannot exec %s", run_argv[0]);
_exit (127);
}
else if (pid == -1)
{
rerrno = errno;
goto out;
}
/* the parent. Ignore some signals for now */
#ifdef POSIX_SIGNALS
if (flags & RUN_SIGIGNORE)
{
act.sa_handler = SIG_IGN;
(void) sigemptyset (&act.sa_mask);
act.sa_flags = 0;
(void) sigaction (SIGINT, &act, &iact);
(void) sigaction (SIGQUIT, &act, &qact);
}
else
{
(void) sigemptyset (&sigset_mask);
(void) sigaddset (&sigset_mask, SIGINT);
(void) sigaddset (&sigset_mask, SIGQUIT);
(void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask);
}
#else
#ifdef BSD_SIGNALS
if (flags & RUN_SIGIGNORE)
{
memset ((char *) &vec, 0, sizeof (vec));
vec.sv_handler = SIG_IGN;
(void) sigvec (SIGINT, &vec, &ivec);
(void) sigvec (SIGQUIT, &vec, &qvec);
}
else
mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT));
#else
istat = signal (SIGINT, SIG_IGN);
qstat = signal (SIGQUIT, SIG_IGN);
#endif
#endif
/* wait for our process to die and munge return status */
#ifdef POSIX_SIGNALS
while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
;
#else
while ((w = wait (&status)) != pid)
{
if (w == -1 && errno != EINTR)
break;
}
#endif
if (w == -1)
{
rc = -1;
rerrno = errno;
}
else if (WIFEXITED (status))
rc = WEXITSTATUS (status);
else if (WIFSIGNALED (status))
{
if (WTERMSIG (status) == SIGPIPE)
error (1, 0, "broken pipe");
rc = 2;
}
else
rc = 1;
/* restore the signals */
#ifdef POSIX_SIGNALS
if (flags & RUN_SIGIGNORE)
{
(void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
(void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
}
else
(void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL);
#else
#ifdef BSD_SIGNALS
if (flags & RUN_SIGIGNORE)
{
(void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
(void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
}
else
(void) sigsetmask (mask);
#else
(void) signal (SIGINT, istat);
(void) signal (SIGQUIT, qstat);
#endif
#endif
/* cleanup the open file descriptors */
out:
if (sterr)
(void) close (sherr);
out2:
if (stout)
(void) close (shout);
out1:
if (stin)
(void) close (shin);
out0:
if (rerrno)
errno = rerrno;
return (rc);
}
void
run_print (fp)
FILE *fp;
{
int i;
for (i = 0; i < run_argc; i++)
{
(void) fprintf (fp, "'%s'", run_argv[i]);
if (i != run_argc - 1)
(void) fprintf (fp, " ");
}
}
FILE *
Popen (cmd, mode)
const char *cmd;
const char *mode;
{
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> Popen(%s,%s)\n",
(server_active) ? 'S' : ' ', cmd, mode);
#else
(void) fprintf (stderr, "-> Popen(%s,%s)\n", cmd, mode);
#endif
if (noexec)
return (NULL);
return (popen (cmd, mode));
}
extern int evecvp PROTO((char *file, char **argv));
int
piped_child (command, tofdp, fromfdp)
char **command;
int *tofdp;
int *fromfdp;
{
int pid;
int to_child_pipe[2];
int from_child_pipe[2];
if (pipe (to_child_pipe) < 0)
error (1, errno, "cannot create pipe");
if (pipe (from_child_pipe) < 0)
error (1, errno, "cannot create pipe");
pid = fork ();
if (pid < 0)
error (1, errno, "cannot fork");
if (pid == 0)
{
if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
error (1, errno, "cannot dup2");
if (close (to_child_pipe[1]) < 0)
error (1, errno, "cannot close");
if (close (from_child_pipe[0]) < 0)
error (1, errno, "cannot close");
if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
error (1, errno, "cannot dup2");
execvp (command[0], command);
error (1, errno, "cannot exec");
}
if (close (to_child_pipe[0]) < 0)
error (1, errno, "cannot close");
if (close (from_child_pipe[1]) < 0)
error (1, errno, "cannot close");
*tofdp = to_child_pipe[1];
*fromfdp = from_child_pipe[0];
return pid;
}
void
close_on_exec (fd)
int fd;
{
#if defined (FD_CLOEXEC) && defined (F_SETFD)
if (fcntl (fd, F_SETFD, 1))
error (1, errno, "can't set close-on-exec flag on %d", fd);
#endif
}
/*
* dir = 0 : main proc writes to new proc, which writes to oldfd
* dir = 1 : main proc reads from new proc, which reads from oldfd
*/
int
filter_stream_through_program (oldfd, dir, prog, pidp)
int oldfd, dir;
char **prog;
pid_t *pidp;
{
int p[2], newfd;
pid_t newpid;
if (pipe (p))
error (1, errno, "cannot create pipe");
newpid = fork ();
if (pidp)
*pidp = newpid;
switch (newpid)
{
case -1:
error (1, errno, "cannot fork");
case 0:
/* child */
if (dir)
{
/* write to new pipe */
close (p[0]);
dup2 (oldfd, 0);
dup2 (p[1], 1);
}
else
{
/* read from new pipe */
close (p[1]);
dup2 (p[0], 0);
dup2 (oldfd, 1);
}
/* Should I be blocking some signals here? */
execvp (prog[0], prog);
error (1, errno, "couldn't exec %s", prog[0]);
default:
/* parent */
close (oldfd);
if (dir)
{
/* read from new pipe */
close (p[1]);
newfd = p[0];
}
else
{
/* write to new pipe */
close (p[0]);
newfd = p[1];
}
close_on_exec (newfd);
return newfd;
}
}

View File

@ -0,0 +1,141 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
#ifdef HAVE_DIRECT_H
# include <direct.h>
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
#include <errno.h>
# ifndef errno
extern int errno;
#endif
#include "save-cwd.h"
#include "error.h"
char *xgetwd __PROTO((void));
/* Record the location of the current working directory in CWD so that
the program may change to other directories and later use restore_cwd
to return to the recorded location. This function may allocate
space using malloc (via xgetwd) or leave a file descriptor open;
use free_cwd to perform the necessary free or close. Upon failure,
no memory is allocated, any locally opened file descriptors are
closed; return non-zero -- in that case, free_cwd need not be
called, but doing so is ok. Otherwise, return zero. */
int
save_cwd (cwd)
struct saved_cwd *cwd;
{
static int have_working_fchdir = 1;
cwd->desc = -1;
cwd->name = NULL;
if (have_working_fchdir)
{
#ifdef HAVE_FCHDIR
cwd->desc = open (".", O_RDONLY);
if (cwd->desc < 0)
{
error (0, errno, "cannot open current directory");
return 1;
}
# if __sun__ || sun
/* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
so we have to fall back to chdir. */
if (fchdir (cwd->desc))
{
if (errno == EINVAL)
{
close (cwd->desc);
cwd->desc = -1;
have_working_fchdir = 0;
}
else
{
error (0, errno, "current directory");
close (cwd->desc);
cwd->desc = -1;
return 1;
}
}
# endif /* __sun__ || sun */
#else
#define fchdir(x) (abort (), 0)
have_working_fchdir = 0;
#endif
}
if (!have_working_fchdir)
{
cwd->name = xgetwd ();
if (cwd->name == NULL)
{
error (0, errno, "cannot get current directory");
return 1;
}
}
return 0;
}
/* Change to recorded location, CWD, in directory hierarchy.
If "saved working directory", NULL))
*/
int
restore_cwd (cwd, dest)
const struct saved_cwd *cwd;
const char *dest;
{
int fail = 0;
if (cwd->desc >= 0)
{
if (fchdir (cwd->desc))
{
error (0, errno, "cannot return to %s",
(dest ? dest : "saved working directory"));
fail = 1;
}
}
else if (chdir (cwd->name) < 0)
{
error (0, errno, "%s", cwd->name);
fail = 1;
}
return fail;
}
void
free_cwd (cwd)
struct saved_cwd *cwd;
{
if (cwd->desc >= 0)
close (cwd->desc);
if (cwd->name)
free (cwd->name);
}

View File

@ -0,0 +1,20 @@
#ifndef SAVE_CWD_H
#define SAVE_CWD_H 1
struct saved_cwd
{
int desc;
char *name;
};
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
#define __PROTO(args) args
#else
#define __PROTO(args) ()
#endif /* GCC. */
int save_cwd __PROTO((struct saved_cwd *cwd));
int restore_cwd __PROTO((const struct saved_cwd *cwd, const char *dest));
void free_cwd __PROTO((struct saved_cwd *cwd));
#endif /* SAVE_CWD_H */

View File

@ -0,0 +1,79 @@
/* xgetwd.c -- return current directory with unlimited length
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Derived from xgetcwd.c in e.g. the GNU sh-utils. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "system.h"
#include <stdio.h>
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#include <sys/types.h>
#ifndef HAVE_GETWD
char *getwd ();
#define GETWD(buf, max) getwd (buf)
#else
char *getcwd ();
#define GETWD(buf, max) getcwd (buf, max)
#endif
/* Amount by which to increase buffer size when allocating more space. */
#define PATH_INCR 32
char *xmalloc ();
char *xrealloc ();
/* Return the current directory, newly allocated, arbitrarily long.
Return NULL and set errno on error. */
char *
xgetwd ()
{
char *cwd;
char *ret;
unsigned path_max;
errno = 0;
path_max = (unsigned) PATH_MAX;
path_max += 2; /* The getcwd docs say to do this. */
cwd = xmalloc (path_max);
errno = 0;
while ((ret = GETWD (cwd, path_max)) == NULL && errno == ERANGE)
{
path_max += PATH_INCR;
cwd = xrealloc (cwd, path_max);
errno = 0;
}
if (ret == NULL)
{
int save_errno = errno;
free (cwd);
errno = save_errno;
return NULL;
}
return cwd;
}