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:
commit
c294469919
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=12751
248
gnu/usr.bin/cvs/BUGS
Normal file
248
gnu/usr.bin/cvs/BUGS
Normal 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
356
gnu/usr.bin/cvs/INSTALL
Normal 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.
|
||||
-------------------------------------------------------------------------------
|
60
gnu/usr.bin/cvs/MINOR-BUGS
Normal file
60
gnu/usr.bin/cvs/MINOR-BUGS
Normal 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
863
gnu/usr.bin/cvs/NEWS
Normal 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
59
gnu/usr.bin/cvs/PROJECTS
Normal 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.
|
97
gnu/usr.bin/cvs/contrib/ccvs-rsh.pl
Normal file
97
gnu/usr.bin/cvs/contrib/ccvs-rsh.pl
Normal 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);
|
||||
}
|
||||
}
|
152
gnu/usr.bin/cvs/contrib/clmerge.pl
Normal file
152
gnu/usr.bin/cvs/contrib/clmerge.pl
Normal 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;
|
||||
}
|
84
gnu/usr.bin/cvs/contrib/cvscheck.sh
Normal file
84
gnu/usr.bin/cvs/contrib/cvscheck.sh
Normal 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
|
116
gnu/usr.bin/cvs/contrib/descend.sh
Normal file
116
gnu/usr.bin/cvs/contrib/descend.sh
Normal 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
|
481
gnu/usr.bin/cvs/contrib/dirfns.shar
Normal file
481
gnu/usr.bin/cvs/contrib/dirfns.shar
Normal 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
|
185
gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh
Normal file
185
gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh
Normal 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
|
592
gnu/usr.bin/cvs/contrib/rcs2log.sh
Normal file
592
gnu/usr.bin/cvs/contrib/rcs2log.sh
Normal 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
|
143
gnu/usr.bin/cvs/contrib/rcs2sccs.sh
Normal file
143
gnu/usr.bin/cvs/contrib/rcs2sccs.sh
Normal 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
|
277
gnu/usr.bin/cvs/contrib/sccs2rcs.csh
Normal file
277
gnu/usr.bin/cvs/contrib/sccs2rcs.csh
Normal 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
|
48
gnu/usr.bin/cvs/cvs/README-rm-add
Normal file
48
gnu/usr.bin/cvs/cvs/README-rm-add
Normal 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
3542
gnu/usr.bin/cvs/cvs/client.c
Normal file
File diff suppressed because it is too large
Load Diff
163
gnu/usr.bin/cvs/cvs/client.h
Normal file
163
gnu/usr.bin/cvs/cvs/client.h
Normal 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 */
|
139
gnu/usr.bin/cvs/cvs/expand_path.c
Normal file
139
gnu/usr.bin/cvs/cvs/expand_path.c
Normal 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
287
gnu/usr.bin/cvs/cvs/login.c
Normal 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. */
|
||||
|
102
gnu/usr.bin/cvs/cvs/rcscmds.c
Normal file
102
gnu/usr.bin/cvs/cvs/rcscmds.c
Normal 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
3992
gnu/usr.bin/cvs/cvs/server.c
Normal file
File diff suppressed because it is too large
Load Diff
136
gnu/usr.bin/cvs/cvs/server.h
Normal file
136
gnu/usr.bin/cvs/cvs/server.h
Normal 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;
|
9
gnu/usr.bin/cvs/cvs/update.h
Normal file
9
gnu/usr.bin/cvs/cvs/update.h
Normal 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));
|
371
gnu/usr.bin/cvs/cvs/wrapper.c
Normal file
371
gnu/usr.bin/cvs/cvs/wrapper.c
Normal 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;
|
||||
}
|
269
gnu/usr.bin/cvs/cvsbug/cvsbug.8
Normal file
269
gnu/usr.bin/cvs/cvsbug/cvsbug.8
Normal 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.
|
||||
|
528
gnu/usr.bin/cvs/cvsbug/cvsbug.sh
Normal file
528
gnu/usr.bin/cvs/cvsbug/cvsbug.sh
Normal 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
|
161
gnu/usr.bin/cvs/cvsinit/cvsinit
Normal file
161
gnu/usr.bin/cvs/cvsinit/cvsinit
Normal 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
|
142
gnu/usr.bin/cvs/cvsinit/cvsinit.8
Normal file
142
gnu/usr.bin/cvs/cvsinit/cvsinit.8
Normal 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 ).
|
673
gnu/usr.bin/cvs/doc/cvsclient.texi
Normal file
673
gnu/usr.bin/cvs/doc/cvsclient.texi
Normal 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
|
20
gnu/usr.bin/cvs/examples/checkoutlist
Normal file
20
gnu/usr.bin/cvs/examples/checkoutlist
Normal 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
|
29
gnu/usr.bin/cvs/examples/cvswrappers
Normal file
29
gnu/usr.bin/cvs/examples/cvswrappers
Normal 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'
|
7
gnu/usr.bin/cvs/examples/rcstemplate
Normal file
7
gnu/usr.bin/cvs/examples/rcstemplate
Normal 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:
|
25
gnu/usr.bin/cvs/examples/taginfo
Normal file
25
gnu/usr.bin/cvs/examples/taginfo
Normal 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
|
21
gnu/usr.bin/cvs/examples/unwrap
Normal file
21
gnu/usr.bin/cvs/examples/unwrap
Normal 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
|
21
gnu/usr.bin/cvs/examples/wrap
Normal file
21
gnu/usr.bin/cvs/examples/wrap
Normal 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
|
47
gnu/usr.bin/cvs/lib/error.h
Normal file
47
gnu/usr.bin/cvs/lib/error.h
Normal 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_ */
|
640
gnu/usr.bin/cvs/lib/filesubr.c
Normal file
640
gnu/usr.bin/cvs/lib/filesubr.c
Normal 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;
|
||||
}
|
126
gnu/usr.bin/cvs/lib/getline.c
Normal file
126
gnu/usr.bin/cvs/lib/getline.c
Normal 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);
|
||||
}
|
15
gnu/usr.bin/cvs/lib/getline.h
Normal file
15
gnu/usr.bin/cvs/lib/getline.h
Normal 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
277
gnu/usr.bin/cvs/lib/md5.c
Normal 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
31
gnu/usr.bin/cvs/lib/md5.h
Normal 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
533
gnu/usr.bin/cvs/lib/run.c
Normal 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;
|
||||
}
|
||||
}
|
141
gnu/usr.bin/cvs/lib/save-cwd.c
Normal file
141
gnu/usr.bin/cvs/lib/save-cwd.c
Normal 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);
|
||||
}
|
||||
|
20
gnu/usr.bin/cvs/lib/save-cwd.h
Normal file
20
gnu/usr.bin/cvs/lib/save-cwd.h
Normal 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 */
|
79
gnu/usr.bin/cvs/lib/xgetwd.c
Normal file
79
gnu/usr.bin/cvs/lib/xgetwd.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user