您最多能選擇 25 個主題 主題必須以字母或數字為開頭,可包含連接號「-」且最長為 35 個字元。
 
 
 
 
 
 

5041 行
154 KiB

Index: src/README.RSE
===================================================================
RCS file: src/README.RSE
diff -N src/README.RSE
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/README.RSE 16 Feb 2002 12:35:28 -0000
@@ -0,0 +1,353 @@
+
+ CVS RSE Patches
+ ===============
+
+ This is the patched version of CVS from Ralf S. Engelschall
+ <rse@engelschall.com> - an enhanced version of the official
+ Cyclic/OpenAvenue's CVS version 1.11.1p1 (see http://www.cvshome.org/).
+
+ The following changes against the avendor CVS version are provided:
+ - support for .cvsrc files in $HOME _AND_ working and and its parent dirs
+ - support for $HOME/.cvsroot to alias roots and to support root mirrors
+ - support global but command specific options in .cvsrc files
+ - support for stand-alone external custom commands `cvs <command>'
+ - support for prolog and epilog hooks
+ - allow `verifymsg' hooks to _change_ the log message
+ - support `$LocalId$, a local keyword variant of `$Id$'
+ - support `$CVSHeader$, a variant of `$Header$', but without root path
+ - new `cvs -u' option in addition to `cvs -n' for _REAL_ read-only access
+ - support for additional `%x' variables on `loginfo' hook command lines
+ - support a `UMask=<mask>' variable in `$CVSROOT/CVSROOT/config'
+ - speeded up `cvs update' by sending whole file if smaller than the diff
+ - disabled keyword expansions during branch merges
+ - adjusted `cvs diff -rHEAD' to be consistent with other commands
+ - made `cvs diff' aware of removed/dead files in the trunk
+ - set `$LOGNAME' to the real user and not the CVS user
+ - support for `HistoryFile=<rel-path-under-CVSROOT>' variable in config.
+ - support for an `admininfo' hook to ACL `cvs admin' commands.
+ - support for an `importinfo' hook to ACL `cvs import' commands.
+ - support for a `-h<handle>' option to `cvs diff' for compressed time spec.
+ - use prefix 'T' ("touched/tagged") instead of 'U' ("updated") on `cvs import'
+ - allow `LockDir' configuration directive to use relative paths
+ - allow a hard-coded CVS super-user to override CVS user via $CVSUSER
+ - additional SetUID/SetGID support for `cvs server' situations.
+ - new `cvs pserverd' for running stand-alone pserver daemons
+ - new global --map-root=/oldpath:/newpath option for mapping root paths
+ - support for wildcards in CVSROOT/passwd files to decrease admin efforts
+ - various cosmetic changes
+
+ Some of my RSE functional patches are only useful for the server side,
+ others are also useful on the client side. All source patches to
+ *.[ch] files were entirely wrapped with ``#ifdef RSE_PATCH_<NAME> ...
+ #endif'' pairs. So, a particular patch is enabled by building CVS with
+ -DRSE_PATCH_<NAME>. All patches are enabled with -DRSE_PATCHES.
+
+ Ralf S. Engelschall
+ rse@engelschall.com
+ www.engelschall.com
+ ________________________________________________________________________
+
+ The following particular patches are available:
+
+ RSE_PATCH_CVSRC:
+ In addition to processing `$HOME/.cvsrc', process also `.cvsrc'
+ files in the current working directory and the parent directories of
+ the current working directory. This allows one to use for instance a
+ `commit -m ""' locally (as used for GNU Pth development where CVS is
+ only used for plain revision control and not for bookkeeping changes
+ or group communication - instead a plain manually edited ChangeLog
+ exists) or `commit -d <master>' (if working with a local repository
+ copy). Additionally this adds support for quoted strings inside
+ .cvsrc files.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_CVSROOT:
+ This adds support for a new dot-file ~/.cvsroot which is used
+ optionally by CVS. It can be used by the user to configure a
+ nickname for a CVS repository root (the master location) plus a
+ possibly existing local repository copy (the slave location). An
+ entry in ~/.cvsroot is of the format ``<nickname> <master-path>
+ [<slave-path> [<sync-prog>]]''. Those entries can be either created
+ manually in ~/.cvsroot or with the `cvs root -e' command.
+
+ The idea is this: if a global `-d' option is used with <nickname> it is
+ automatically expanded to <master-path>. If no global `-d' option is used,
+ the CVS command is checked. If it is one of the commands which are known
+ to CVS to modify the repository, and the $CVSROOT or CVS/Root specify a
+ slave location, the repository is switched to the corresponding master
+ location (because modifications have to be performed there). If the
+ command is one of the commands which are known to CVS to NOT modify the
+ repository, and the $CVSROOT or CVS/Root specify a master location, the
+ repository is switched to the corresponding slave location (because the
+ slave location is faster than the master location per definition).
+
+ After a modifying operation, CVS can either run a synchronization job
+ automatically to bring slave in sync with master again or the user can run
+ `cvs root -s <nickname>' manually to perform this task.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_GLOBALOPTION:
+ RSE_PATCH_GLOBALOPTION_PARTLY:
+ By default, global options in `.cvsrc' files are specified with a
+ `cvs' prefix. These options then apply to _all_ cvs commands. If
+ RSE_PATCH_GLOBALOPTION is enabled, a second pass is done where all
+ global options are read with prefix `cvs/<command>' where <command>
+ is the official cvs command (for instance `commit' or `checkout',
+ even if `ci' or `co' are used on the command line). This is useful
+ for instance to override CVSROOT in commit commands if using a local
+ repository copy. The drawback of this feature is that it obviously
+ slows down cvs calls, because a second pass has to be done. But
+ usually this feature is intended only for use with `commit', `tag',
+ `rtag', `history', `admin', `import' and `rdiff' commands, so if
+ RSE_PATCH_GLOBALOPTION_PARTLY is additionally enabled, this second
+ pass is only done for those commands (which is the recommended use
+ of this feature).
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_CUSTOMCMD:
+ This provides an additional global option `-C
+ <cmd-name>:<cmd-program>' which defines an additional CVS command
+ <cmd-name>. It is intended for use on `cvs' lines inside .cvsrc
+ files. The effect of having `cvs -Csync:$CVSROOT/CVSROOT/sync' in a
+ .cvsrc file is (and assuming $CVSROOT is /e/ossp/cvs) that if you
+ run `cvs sync <arg1> <arg2>', CVS executes `/e/ossp/cvs/CVSROOT/sync
+ <arg1> <arg2>'. So this is a way to externally extend CVS with
+ additional commands.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_PROLOGEPILOG:
+ Provides the two additional CVS options `-P <program>' and `-E
+ <program>' for running prolog and epilog programs before and
+ after the usual CVS processing. This is mainly intended as local
+ hooks for implicitly wrapping CVS commands (without having to
+ create slow wrapping shell scripts, etc.). Developers usually
+ use it to automatically start their RSYNC command to update the
+ local repository copy after a commit. The <program> is called
+ with four arguments: $1 is either `prolog' or `epilog' (useful
+ if one just wants to use a single hook program), $2 is the cvs
+ command (it is `commit' even `ci' is used, etc.), $3 is the current
+ working directory from which the cvs command was run and $4 is the
+ corresponding $CVSROOT variable.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_VERIFY:
+ This patch forces CVS to read in again the log messages after the
+ verification step (via the `verifymsg' hook) to allow the hook
+ script to actually _update_ the log message. This is useful for
+ stripping out unnecessary stuff, like not filled out custom fields
+ of the log template text.
+ [Origin: Peter Wemm, FreeBSD]
+
+ RSE_PATCH_LOCALID:
+ Support a local keyword variant of `$Id$'. By default this is
+ `$LocalId$', but if -DRSE_PATCH_LOCALID_NAME=\"<name>\" is
+ additionally defined, then the keyword is `$<name>$'. Alternatively
+ one can define the name also in the `$CVSROOT/CVSROOT/config' file
+ with `LocalIdName=<name>'.
+ [Origin: NetBSD, OpenBSD, Ralf S. Engelschall]
+
+ RSE_PATCH_CVSHEADER:
+ Support the `$CVSHeader' variant of `$Header$' which has the
+ $CVSROOT prefix stripped of from the path. This is useful because
+ the prefix usually useless outside the server environment.
+ [Origin: FreeBSD]
+
+ RSE_PATCH_NOLOCK:
+ Provide a `cvs -u' option in addition to `cvs -n' to force CVS to
+ not create any lock files in the repository. This is for supporting
+ read-only access to the repository. This is useful for working
+ with CVS repositories on CD-ROMs and for providing anonymous CVS
+ services.
+ [Origin: NetBSD]
+
+ RSE_PATCH_EXTRAPERCENT:
+ This adds extra percent expansions to `loginfo' command lines:
+ `%o' to expand the operation (`A' = added, `M' = modified, `R' =
+ removed), `%t' to expand the tag, `%d' to expand the date.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_READDNEW:
+ If a file was re-added to the repository, log the revision in the
+ `commitlog' as `NONE' instead of the previous dead revision.
+ [Origin: NetBSD]
+
+ RSE_PATCH_CONFIGUMASK:
+ Provide a `UMask=<mask>' variable in `$CVSROOT/CVSROOT/config' which
+ overrides the umask of the CVS server process.
+ [Origin: OpenBSD]
+
+ RSE_PATCH_FASTERUPDATE:
+ This speeds up `cvs update' by sending the whole file over the
+ network if it is smaller than the diff content. This is useful for
+ working remotely over slow Internet links.
+ [Origin: OpenBSD]
+
+ RSE_PATCH_MERGENOKEYWORD:
+ This disables keyword expansions during branch merges which is
+ very useful in long-term branching. Without this the so-called
+ `spurious merging conflicts' occur because the keywords cause
+ spurious conflicts on every merge after the first (if those text
+ files have been modified on the trunk since the previous merge out
+ to the branch).
+ [Origin: Jay Sachs <jsachs@iclick.com>]
+
+ RSE_PATCH_DIFFHEAD:
+ This patch changes the behavior of `cvs diff -rHEAD' on branches.
+ HEAD here now behaves with as it does with all other CVS commands,
+ as a name for the head of the trunk (the old behavior of `cvs diff
+ -rHEAD' was to treat HEAD to mean the head of the branch, while all
+ the other commands already treated HEAD as the head of the trunk).
+ [Origin: Stephen Cameron <steve.cameron@compaq.com>]
+
+ RSE_PATCH_DEADAWARE:
+ This makes `cvs diff' aware of removed/dead files in the trunk
+ (HEAD), i.e., it doesn't complain if it didn't exist.
+ [Origin: FreeBSD]
+
+ RSE_PATCH_LOGNAME:
+ This is for SUID-based CVS servers and passes in `$LOGNAME' the real
+ user (first field in `$CVSROOT/CVSROOT/passwd') instead of the SUID
+ user (third field in `$CVSROOT/CVSROOT/passwd')
+ [Origin: Chris Cameron]
+
+ RSE_PATCH_HISTORYFILE:
+ This provides an additional `HistoryFile=<rel-path-under-CVSROOT>'
+ config variable which allows one to store the history file under a
+ different path.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_SMARTCONFIG:
+ This allows one to add custom configuration variables to
+ `$CVSROOT/CVSROOT/config' without having CVS complain about them and
+ fail with an error. This is useful to use the config file also for
+ storing config details for the various admin scripts.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_ADMININFO:
+ This adds the feature of an extra `$CVSROOT/CVSROOT/admininfo'
+ configuration file which can be used for access controlling `cvs
+ admin' commands similar to `cvs tag' (which is already done
+ with `taginfo') and `cvs commit' (which is already done with
+ `commitinfo'). The specified filters in this info file receive the
+ absolute repository directory as the first argument, followed by all
+ names of files in this directory on which the `cvs admin' command
+ should be performed. If the filter returns 0, the operation is
+ allowed. If it returns not 0, the operation is denied.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_IMPORTINFO:
+ This adds the feature of an extra `$CVSROOT/CVSROOT/importinfo'
+ configuration file which can be used for access controlling
+ `cvs import'. The specified filters in this info file receives
+ the following arguments: the vendor branch tag, the (absolute)
+ repository path which is the root of the import and then zero or
+ more relative file paths under this repository. If the filter
+ returns 0, the operation is allowed. If it returns not 0, the
+ operation is denied.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_HANDLE:
+ This adds a convinient `-h<handle>' option to `cvs diff'. `<handle>'
+ is a string of the format `[!]YYMMDDhhmmssoo' (YY=year, MM=month,
+ DD=day, hh=hour, mm=minute, ss=second, oo=offset) which internally
+ is expanded into two `-D' options. The first date is the equivalent
+ of `YYMMDDhhmmss', the second is the first plus `oo' seconds. If the
+ exclamation mark is used, the two dates are reversed. The intention
+ is that such a handle is a short form for a time range and can be
+ easily computed in a commit log mail. So the `-h' option can be used
+ to easily get the corresponding change diff for branch merging or
+ backing out. The only restriction is that time-overlapping commits
+ break the solution, of course. But in practice this is no real
+ problem.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_IMPORTTOUCH:
+ This prints the prefix 'T' (for "touched/tagged only") instead
+ of 'U' (for "updated") on `cvs import' if no modifications were
+ imported, i.e., no new revision is comitted. This way one can
+ distinguish those imports from the regular updated ones which also
+ print 'U' and which actually commit a new revision.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_RELLOCKDIR:
+ This allows the `LockDir' configuration directive to use relative
+ paths to $CVSROOT, because without this patch a relative path would
+ be relative to the current working directory (which is useless).
+ [Origin: Stefan Monnier <foo@acm.com>]
+
+ RSE_PATCH_CVSUSER:
+ This allows the Unix user RSE_PATCH_CVSUSER_CALLER (per default
+ "ossp-cvs") to use the environment variable CVSUSER to override the
+ login name CVS uses to identify the caller. This is intended for use
+ with a CVS setuid wrapper program or for use manually by the CVS
+ administrator.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_SETXID:
+ This is a variant of CVS's SETXID_SUPPORT. It allows one to
+ setuid/setgid the CVS executable. Then CVS deletes these effective
+ uid/gid for all commands except for the "cvs server" command. For
+ this and only this it switches the real uid/gid to the effective
+ uid/gid. This way one can use the repository as a black-box. One
+ just has to be make sure that only :ext: (for remote) and :fork:
+ (for local) access is used.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_PSERVERD:
+ This adds an additional `cvs pserverd' command which is like `cvs
+ pserver' except that it uses own builtin TCP/IP socket listening and
+ forking facility. The advantages over using inetd are: pserverd can
+ listen to particular host addresses/ports (inetd always binds to all
+ interfaces of a host), it can optionally chroot(2) for a particular
+ user only (usually "anonymous"), it can optionally force the global
+ options -l -u for a particular user only (usually "anonymous"), it
+ can detach into background and run as a real daemon, etc.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_MAPROOT
+ This adds a global --map-root=/oldpath:/newpath option which
+ allows one to map virtual/incoming CVSROOT values to real ones.
+ For instance this can be used together with --allow-root and "cvs
+ pserverd" to map the intuitive virtual path to the physical path on
+ the host.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_HASHFUNC:
+ This replaces the obscure hash function in src/hash.c with D.J.Berstein's
+ popular "times 33" function which is faster to compute and still
+ distributes very well.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_ADDFILEATTR:
+ Let the default file attributes set on newly added files.
+ [Origin: Noel Yap]
+
+ RSE_PATCH_WILDPASSWD:
+ This allows wildcards ("*") in CVSROOT/passwd. That allows one to
+ just do "*:ULtgRLXo7NRxs:cvsuser" which would let absolutely anyone
+ use CVS provided they know the password. It would also let you do
+ things like "*:*:cvsuser" to let only authorized system users use
+ CVS using their system passwords.
+ [Larry Jones <larry.jones@sdrc.com>]
+
+ RSE_PATCH_CVSPID:
+ This provides an environment variable $CVSPID which contains the process
+ id of the parent CVS process. This is usually used inside scripts called
+ from *info files in order to have a unique session handle (for instance
+ for a common temporary directory "/tmp/cvs.foo.$CVSPID", etc).
+ [Origin: Rich Salz <rsalz@caveosystems.com>]
+
+ RSE_PATCH_BUGFIX:
+ This enabled various bugfixes which are still not present in the
+ official CVS version.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_COSMETICS:
+ This just enables some cosmetic changes to various output messages.
+ [Origin: Ralf S. Engelschall]
+
+ RSE_PATCH_COSMETICS_HARD:
+ This just enables more cosmetic changes to various output messages.
+ The difference is that these break "make check".
+ [Origin: Ralf S. Engelschall]
+
Index: src/add.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/add.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 add.c
--- src/add.c 19 Apr 2001 19:45:31 -0000 1.1.1.4
+++ src/add.c 16 Feb 2002 12:36:09 -0000
@@ -798,6 +798,9 @@
li->type = T_TITLE;
li->tag = xstrdup (tag);
li->rev_old = li->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+ li->date = NULL;
+#endif
p->data = (char *) li;
(void) addnode (ulist, p);
Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
Index: src/admin.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/admin.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 admin.c
--- src/admin.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/admin.c 16 Feb 2002 12:36:09 -0000
@@ -139,6 +139,161 @@
dat->av[dat->ac++] = newelt;
}
+#ifdef RSE_PATCH_ADMININFO
+
+static List *admininfo_dlist;
+static List *admininfo_flist;
+
+static void admininfo_dlist_delproc(Node *);
+static int admininfo_info_runproc(char *, char *);
+static int admininfo_flist_runproc(Node *, void *);
+
+struct admininfo_dlist_st {
+ List *flist;
+};
+
+/* file callback function for recursive processing */
+static int
+admininfo_fileproc (
+ void *callerdat,
+ struct file_info *finfo)
+{
+ char *xdir;
+ Node *dnode;
+ Node *fnode;
+
+ /* determine current directory */
+ if (finfo->update_dir[0] == '\0')
+ xdir = ".";
+ else
+ xdir = finfo->update_dir;
+
+ /* find directory node in directory list */
+ if ((dnode = findnode(admininfo_dlist, xdir)) != NULL)
+ /* take already existing file list */
+ admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist;
+ else {
+ /* create a new file list */
+ struct admininfo_dlist_st *dlist;
+
+ admininfo_flist = getlist();
+
+ dlist = (struct admininfo_dlist_st *)xmalloc(sizeof(struct admininfo_dlist_st));
+ dlist->flist = admininfo_flist;
+
+ dnode = getnode();
+ dnode->type = UPDATE;
+ dnode->key = xstrdup(xdir);
+ dnode->data = (char *)dlist;
+ dnode->delproc = admininfo_dlist_delproc;
+
+ (void)addnode(admininfo_dlist, dnode);
+ }
+
+ /* create new file node in file list */
+ fnode = getnode();
+ fnode->type = UPDATE;
+ fnode->key = xstrdup(finfo->file);
+ fnode->data = NULL;
+ fnode->delproc = NULL;
+ (void)addnode(admininfo_flist, fnode);
+
+ return 0;
+}
+
+/* delete a directory list node */
+static void
+admininfo_dlist_delproc(
+ Node *p)
+{
+ struct admininfo_dlist_st *dlist;
+
+ dlist = (struct admininfo_dlist_st *)p->data;
+ dellist(&dlist->flist);
+ free(dlist);
+ return;
+}
+
+/* file callback function for recursive processing (when done) */
+static int
+admininfo_filesdoneproc(
+ void *callerdat,
+ int err,
+ char *repos,
+ char *update_dir,
+ List *entries)
+{
+ Node *dnode;
+ int n;
+
+ /* find file list for update directory */
+ if ((dnode = findnode(admininfo_dlist, update_dir)) != NULL)
+ admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist;
+ else
+ admininfo_flist = (List *)NULL;
+ if ( (admininfo_flist == NULL)
+ || (admininfo_flist->list->next == admininfo_flist->list))
+ return err;
+
+ /* parse and execute the admininfo configuration */
+ if ((n = Parse_Info(CVSROOTADM_ADMININFO, repos, admininfo_info_runproc, 1)) > 0) {
+ error(0, 0, "Pre-admin check failed");
+ err += n;
+ }
+
+ return err;
+}
+
+/* admininfo configuration entry callback */
+static int
+admininfo_info_runproc(repository, filter)
+ char *repository;
+ char *filter;
+{
+ char *s, *cp;
+ int rv;
+
+ /* if possible, do an own check to make sure that filter really exists */
+ if (filter[0] == '/') {
+ s = xstrdup(filter);
+ for (cp = s; *cp; cp++) {
+ if (isspace((unsigned char)*cp)) {
+ *cp = '\0';
+ break;
+ }
+ }
+ if (!isfile(s)) {
+ error (0, errno, "cannot find pre-admin filter '%s'", s);
+ free(s);
+ return (1);
+ }
+ free(s);
+ }
+
+ /* construct the filter command */
+ run_setup(filter);
+ run_arg(repository);
+ walklist(admininfo_flist, admininfo_flist_runproc, NULL);
+
+ /* execute the filter command */
+ rv = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+
+ return rv;
+}
+
+/* file list callback for adding file as another program argument */
+static int
+admininfo_flist_runproc(
+ Node *p,
+ void *closure)
+{
+ if (p->key != NULL)
+ run_arg(p->key);
+ return 0;
+}
+
+#endif /* RSE_PATCH_ADMININFO */
+
int
admin (argc, argv)
int argc;
@@ -505,6 +660,20 @@
#endif /* CLIENT_SUPPORT */
lock_tree_for_write (argc, argv, 0, W_LOCAL, 0);
+
+#ifdef RSE_PATCH_ADMININFO
+ /* allow `CVSROOT/CVSROOT/admininfo' filters to check whether the
+ `cvs admin' operation is authorized for all the specified files
+ in the repository */
+ admininfo_dlist = getlist();
+ err = start_recursion(admininfo_fileproc, admininfo_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
+ argc, argv, 0, W_LOCAL, 0, 0, (char *)NULL, 1);
+ if (err) {
+ Lock_Cleanup();
+ error(1, 0, "correct above errors first!");
+ }
+#endif
err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc,
(DIRLEAVEPROC) NULL, (void *)&admin_data,
Index: src/checkin.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/checkin.c,v
retrieving revision 1.1.1.1
diff -u -d -u -3 -r1.1.1.1 checkin.c
--- src/checkin.c 22 Feb 1998 19:46:46 -0000 1.1.1.1
+++ src/checkin.c 16 Feb 2002 12:36:09 -0000
@@ -32,14 +32,27 @@
Vers_TS *vers;
int set_time;
char *tocvsPath = NULL;
+#ifdef RSE_PATCH_COSMETICS_HARD
+ int flags;
+#endif
/* Hmm. This message goes to stdout and the "foo,v <-- foo"
message from "ci" goes to stderr. This doesn't make a whole
lot of sense, but making everything go to stdout can only be
gracefully achieved once RCS_checkin is librarified. */
+#ifdef RSE_PATCH_COSMETICS_HARD
+ if (!really_quiet) {
+#endif
cvs_output ("Checking in ", 0);
cvs_output (finfo->fullname, 0);
+#ifdef RSE_PATCH_COSMETICS_HARD
+ cvs_output ("\n", 0);
+#else
cvs_output (";\n", 0);
+#endif
+#ifdef RSE_PATCH_COSMETICS_HARD
+ }
+#endif
tocvsPath = wrap_tocvs_process_file (finfo->file);
if (!noexec)
@@ -56,7 +69,14 @@
if (finfo->rcs == NULL)
finfo->rcs = RCS_parse (finfo->file, finfo->repository);
+#ifdef RSE_PATCH_COSMETICS_HARD
+ flags = RCS_FLAGS_KEEPFILE;
+ if (really_quiet || quiet)
+ flags |= RCS_FLAGS_QUIET;
+ switch (RCS_checkin (finfo->rcs, NULL, message, rev, flags))
+#else
switch (RCS_checkin (finfo->rcs, NULL, message, rev, RCS_FLAGS_KEEPFILE))
+#endif
{
case 0: /* everything normal */
@@ -118,6 +138,16 @@
vers->options, vers->tag, vers->date, (char *) 0);
history_write (type, NULL, vers->vn_rcs,
finfo->file, finfo->repository);
+
+#ifdef RSE_PATCH_ADDFILEATTR
+ if (type == 'A') {
+ char *attr;
+ if ((attr = fileattr_getall(NULL)) != NULL) {
+ fileattr_setall(finfo->file, attr);
+ free(attr);
+ }
+ }
+#endif
if (tocvsPath)
if (unlink_file_dir (tocvsPath) < 0)
Index: src/checkout.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/checkout.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 checkout.c
--- src/checkout.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/checkout.c 16 Feb 2002 12:36:09 -0000
@@ -179,7 +179,11 @@
case 'p':
pipeout = 1;
run_module_prog = 0; /* don't run module prog when piping */
+#ifdef RSE_PATCH_NOLOCK
+ noexec = nolock = 1; /* so no locks will be created */
+#else
noexec = 1; /* so no locks will be created */
+#endif
break;
case 'c':
cat = 1;
Index: src/client.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/client.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 client.c
--- src/client.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/client.c 16 Feb 2002 12:36:09 -0000
@@ -105,6 +105,9 @@
int status PROTO((int argc, char **argv));
int tag PROTO((int argc, char **argv));
int update PROTO((int argc, char **argv));
+#ifdef RSE_PATCH_RLIST
+int list PROTO((int argc, char **argv));
+#endif
/* All the response handling functions. */
static void handle_ok PROTO((char *, int));
@@ -251,14 +254,34 @@
this_root = Name_Root ((char *) NULL, (char *) NULL);
}
+#ifdef RSE_PATCH_CVSROOT
+ {
+ int cvsroot_alias;
+ cvsroot_type *e;
+
+ cvsroot_alias = 0;
+ if ((e = cvsroot_lookup(NULL, current_parsed_root->original, NULL)) != NULL)
+ if (strcmp(e->slavepath, this_root) == 0)
+ cvsroot_alias = 1;
+ if ((e = cvsroot_lookup(NULL, NULL, this_root)) != NULL)
+ if (strcmp(e->masterpath, current_parsed_root->original) == 0)
+ cvsroot_alias = 1;
+#endif
+
/* Now check the value for root. */
if (this_root && current_parsed_root
+#ifdef RSE_PATCH_CVSROOT
+ && !cvsroot_alias
+#endif
&& (strcmp (this_root, current_parsed_root->original) != 0))
{
/* Don't send this, since the CVSROOTs don't match. */
free (this_root);
return 1;
}
+#ifdef RSE_PATCH_CVSROOT
+ }
+#endif
free (this_root);
}
@@ -2704,6 +2727,9 @@
/* Add a directory name to the list of those sent to the
server. */
if (update_dir && (*update_dir != '\0')
+#ifdef RSE_PATCH_CVSROOT
+ /* FIXME: alternative to RSE_PATCH_CVSROOT?! */
+#endif
&& (strcmp (update_dir, ".") != 0)
&& (findnode (dirs_sent_to_server, update_dir) == NULL))
{
@@ -4546,6 +4572,18 @@
error (1, 0,
"This server does not support the global -n option.");
}
+#ifdef RSE_PATCH_NOLOCK
+ if (nolock && !noexec)
+ {
+ if (have_global)
+ {
+ send_to_server ("Global_option -u\012", 0);
+ }
+ else
+ error (1, 0,
+ "This server does not support the global -u option.");
+ }
+#endif
if (quiet)
{
if (have_global)
Index: src/commit.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/commit.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 commit.c
--- src/commit.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/commit.c 16 Feb 2002 12:36:09 -0000
@@ -296,6 +296,9 @@
data->type = status;
data->tag = xstrdup (vers->tag);
data->rev_old = data->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+ data->date = xstrdup (vers->ts_user);
+#endif
node->type = UPDATE;
node->delproc = update_delproc;
@@ -498,7 +501,11 @@
/* Run the user-defined script to verify/check information in
*the log message
*/
+#ifdef RSE_PATCH_VERIFY
+ do_verify (&saved_message, (char *)NULL);
+#else
do_verify (saved_message, (char *)NULL);
+#endif
/* We always send some sort of message, even if empty. */
/* FIXME: is that true? There seems to be some code in do_editor
@@ -986,7 +993,16 @@
xmalloc (sizeof (struct logfile_info)));
li->type = status;
li->tag = xstrdup (vers->tag);
+#ifdef RSE_PATCH_READDNEW
+ /* If the file was re-added, we want the revision in the commitlog
+ to be NONE, not the previous dead revision. */
+ li->rev_old = status == T_ADDED ? NULL : xstrdup (vers->vn_rcs);
+#else
li->rev_old = xstrdup (vers->vn_rcs);
+#endif
+#ifdef RSE_PATCH_EXTRAPERCENT
+ li->date = xstrdup (vers->ts_user);
+#endif
li->rev_new = NULL;
p->data = (char *) li;
(void) addnode (ulist, p);
@@ -1230,7 +1246,11 @@
if (use_editor)
do_editor (finfo->update_dir, &saved_message,
finfo->repository, ulist);
+#ifdef RSE_PATCH_VERIFY
+ do_verify (&saved_message, finfo->repository);
+#else
do_verify (saved_message, finfo->repository);
+#endif
}
p = findnode (cilist, finfo->file);
@@ -1552,7 +1572,11 @@
got_message = 1;
if (use_editor)
do_editor (update_dir, &saved_message, real_repos, ulist);
+#ifdef RSE_PATCH_VERIFY
+ do_verify (&saved_message, real_repos);
+#else
do_verify (saved_message, real_repos);
+#endif
free (real_repos);
return (R_PROCESS);
}
@@ -2296,6 +2320,10 @@
free (li->rev_old);
if (li->rev_new)
free (li->rev_new);
+#ifdef RSE_PATCH_EXTRAPERCENT
+ if (li->date)
+ free (li->date);
+#endif
free (li);
}
Index: src/create_adm.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/create_adm.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 create_adm.c
--- src/create_adm.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/create_adm.c 16 Feb 2002 14:00:14 -0000
@@ -21,6 +21,41 @@
or after which CVS might do something non-useful. If WARN is zero, then
don't print warnings; all errors are fatal then. */
+#ifdef RSE_PATCH_CVSROOT
+static int local_template_cb(char *repository, char *template)
+{
+ FILE *fpIN, *fpOUT;
+ char buf[1024];
+ size_t n;
+
+ if ((fpOUT = CVS_FOPEN(CVSADM_TEMPLATE, "w+")) == NULL)
+ error(1, errno, "cannot open %s for writing", CVSADM_TEMPLATE);
+ if ((fpIN = CVS_FOPEN(template, "r")) == NULL)
+ error(1, errno, "cannot open %s for reading", template);
+ while (!feof(fpIN)) {
+ n = fread(buf, 1, sizeof buf, fpIN);
+ if (n == 0) {
+ if (ferror(fpIN))
+ error(0, errno, "cannot read template file %s", template);
+ break;
+ }
+ fwrite(buf, 1, n, fpOUT);
+ }
+ fclose(fpIN);
+ fclose(fpOUT);
+ return 0;
+}
+
+static void local_template(char *update_dir, char *repository)
+{
+ cvsroot_type *e;
+
+ if ((e = cvsroot_lookup(NULL, NULL, current_parsed_root->original)) != NULL)
+ Parse_Info(CVSROOTADM_RCSINFO, repository, local_template_cb, 1);
+ return;
+}
+#endif
+
int
Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn,
dotemplate)
@@ -179,6 +214,20 @@
fprintf (stderr, "%c<- Create_Admin\n",
(server_active) ? 'S' : ' ');
}
+#endif
+#ifdef RSE_PATCH_CVSROOT
+ /* Under our "cvs root" feature, checkouts are performed
+ locally (from the repository copy and without C/S), but commits
+ are performed remotely (to the master repository with C/S).
+ Unfortunately, CVS "optimizes" processing and doesn't provide
+ CVS/Template files on non-C/S checkouts. This would mean that
+ if "cvs root" feature is used, the rcsinfo-configured templates
+ are never used. So, if and only if we do a non-C/S checkout (or
+ similar operation which creates CVS/Template) _and_ the current
+ CVSROOT is known to be a repository copy, we force the creation
+ of CVS/Template. */
+ if (!server_active && !(current_parsed_root->isremote) && dotemplate)
+ local_template(update_dir, repository);
#endif
free (reposcopy);
Index: src/cvs.h
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/cvs.h,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 cvs.h
--- src/cvs.h 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/cvs.h 16 Feb 2002 12:36:21 -0000
@@ -187,6 +187,33 @@
#define CVSROOTADM_WRITERS "writers"
#define CVSROOTADM_PASSWD "passwd"
#define CVSROOTADM_CONFIG "config"
+#ifdef RSE_PATCH_ADMININFO
+#define CVSROOTADM_ADMININFO "admininfo"
+#endif
+#ifdef RSE_PATCH_IMPORTINFO
+#define CVSROOTADM_IMPORTINFO "importinfo"
+#endif
+
+#ifdef RSE_PATCH_ALTADMINFILES
+#define CVSROOTADM_MODULES_ALT "conf_modules"
+#define CVSROOTADM_LOGINFO_ALT "hook_logwrite"
+#define CVSROOTADM_RCSINFO_ALT "hook_logtempl"
+#define CVSROOTADM_COMMITINFO_ALT "hook_commit"
+#define CVSROOTADM_TAGINFO_ALT "hook_tag"
+#define CVSROOTADM_EDITINFO_ALT "hook_logedit"
+#define CVSROOTADM_VERIFYMSG_ALT "hook_logverify"
+#define CVSROOTADM_HISTORY_ALT "data_history"
+#define CVSROOTADM_VALTAGS_ALT "data_valtags"
+#define CVSROOTADM_IGNORE_ALT "conf_ignore"
+#define CVSROOTADM_CHECKOUTLIST_ALT "conf_checkout"
+#define CVSROOTADM_WRAPPER_ALT "hook_wrapper"
+#define CVSROOTADM_NOTIFY_ALT "hook_notify"
+#define CVSROOTADM_USERS_ALT "conf_users"
+#define CVSROOTADM_READERS_ALT "conf_readers"
+#define CVSROOTADM_WRITERS_ALT "conf_writers"
+#define CVSROOTADM_PASSWD_ALT "conf_passwd"
+#define CVSROOTADM_CONFIG_ALT "conf_global"
+#endif
#define CVSNULLREPOS "Emptydir" /* an empty directory */
@@ -273,6 +300,10 @@
#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */
/* #define CVSUMASK_DFLT Set by options.h */
+#ifdef RSE_PATCH_NOLOCK
+#define CVSNOLOCK_ENV "CVSNOLOCK" /* do not create lock files */
+#endif
+
/*
* If the beginning of the Repository matches the following string, strip it
* so that the output to the logfile does not contain a full pathname.
@@ -363,6 +394,9 @@
extern int use_editor;
extern int cvswrite;
extern mode_t cvsumask;
+#ifdef RSE_PATCH_LOCALID
+extern char *RCS_citag;
+#endif
/* Access method specified in CVSroot. */
typedef enum {
@@ -400,6 +434,9 @@
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
+#ifdef RSE_PATCH_NOLOCK
+extern int nolock; /* Don't create locks */
+#endif
extern int logoff; /* Don't write history entry */
extern int top_level_admin;
@@ -467,6 +504,27 @@
void root_allow_free PROTO ((void));
int root_allow_ok PROTO ((char *));
+#ifdef RSE_PATCH_MAPROOT
+void root_map_add PROTO ((char *, char *));
+void root_map_free PROTO ((void));
+int root_map_it PROTO ((char *, char **, int));
+#endif
+
+#ifdef RSE_PATCH_CVSROOT
+typedef struct {
+ char *nickname;
+ char *masterpath;
+ char *slavepath;
+ char *syncprog;
+} cvsroot_type;
+char *cvsroot_filename(void);
+void cvsroot_free(cvsroot_type *);
+cvsroot_type *cvsroot_entry_read(FILE *);
+void cvsroot_entry_write(FILE *, cvsroot_type *);
+cvsroot_type *cvsroot_lookup(char *, char *, char *);
+void cvsroot_synchronize(cvsroot_type *, int);
+#endif
+
char *gca PROTO((const char *rev1, const char *rev2));
extern void check_numeric PROTO ((const char *, int, char **));
char *getcaller PROTO((void));
@@ -570,6 +628,10 @@
extern void expand_wild PROTO ((int argc, char **argv,
int *pargc, char ***pargv));
+#ifdef RSE_PATCH_HANDLE
+int handle2dates(char *, time_t *, time_t *);
+#endif
+
#ifdef SERVER_SUPPORT
extern int cvs_casecmp PROTO ((char *, char *));
extern int fopen_case PROTO ((char *, char *, FILE **, char **));
@@ -589,7 +651,11 @@
void do_editor PROTO((char *dir, char **messagep,
char *repository, List * changes));
+#ifdef RSE_PATCH_VERIFY
+void do_verify PROTO((char **messagep, char *repository));
+#else
void do_verify PROTO((char *message, char *repository));
+#endif
typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten, int local_specified,
@@ -812,6 +878,9 @@
NULL for add or import */
char *rev_new; /* rev number after a commit/modify,
add, or import, NULL for remove */
+#ifdef RSE_PATCH_EXTRAPERCENT
+ char *date;
+#endif
};
/* Wrappers. */
@@ -851,6 +920,13 @@
int unedit PROTO ((int argc, char **argv));
int editors PROTO ((int argc, char **argv));
int watchers PROTO ((int argc, char **argv));
+#ifdef RSE_PATCH_CVSROOT
+int root PROTO ((int argc, char **argv));
+#endif
+#ifdef RSE_PATCH_PSERVERD
+int pserverd PROTO ((int argc, char **argv));
+int pserver_daemon PROTO ((int argc, char **argv));
+#endif
extern int annotate PROTO ((int argc, char **argv));
extern int add PROTO ((int argc, char **argv));
extern int admin PROTO ((int argc, char **argv));
@@ -871,6 +947,9 @@
extern int cvsstatus PROTO((int argc, char **argv));
extern int cvstag PROTO((int argc, char **argv));
extern int version PROTO((int argc, char **argv));
+#ifdef RSE_PATCH_RLIST
+extern int cvslist PROTO((int argc, char **argv));
+#endif
extern unsigned long int lookup_command_attribute PROTO((char *));
Index: src/cvsrc.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/cvsrc.c,v
retrieving revision 1.1.1.2
diff -u -d -u -3 -r1.1.1.2 cvsrc.c
--- src/cvsrc.c 23 Dec 1998 15:15:00 -0000 1.1.1.2
+++ src/cvsrc.c 16 Feb 2002 12:36:09 -0000
@@ -12,6 +12,203 @@
#include "cvs.h"
#include "getline.h"
+#ifdef RSE_PATCH_CVSRC
+
+#include <ctype.h>
+#include <string.h>
+
+static char *strq_start = NULL;
+
+static char *
+strqtok_cchar(
+ register char *s,
+ register char *c,
+ int *backslashed)
+{
+ register char ch;
+
+ if ((*backslashed = (*s == '\\'))) {
+ switch (*++s) {
+ case 'a':
+ *c = '\a';
+ break;
+ case 'b':
+ *c = '\b';
+ break;
+ case 'f':
+ *c = '\f';
+ break;
+ case 'n':
+ *c = '\n';
+ break;
+ case 'r':
+ *c = '\r';
+ break;
+ case 't':
+ *c = '\t';
+ break;
+ case 'v':
+ *c = '\v';
+ break;
+ case '\\':
+ *c = '\\';
+ break;
+ case '^':
+ *c = '^';
+ break;
+ case '\'':
+ *c = '\'';
+ break;
+ case '"':
+ *c = '"';
+ break;
+ case '?':
+ *c = '?';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ch = 0;
+ if (isdigit(*s) && *s != '8' && *s != '9') {
+ ch = *s++ - '0';
+ if (isdigit(*s) && *s != '8' && *s != '9') {
+ ch <<= 3;
+ ch |= *s++ - '0';
+ if (isdigit(*s) && *s != '8' && *s != '9') {
+ ch <<= 3;
+ ch |= *s++ - '0';
+ }
+ }
+ }
+ s--;
+ *c = ch;
+ break;
+ case 'x':
+ s++;
+ for (ch = 0; isxdigit(*s); s++) {
+ ch <<= 4;
+ ch |= isdigit(*s) ? *s - '0' :
+ islower(*s) ? *s + 10 - 'a' : *s + 10 - 'A';
+ }
+ s--;
+ *c = ch;
+ break;
+ default:
+ *c = *s;
+ break;
+ }
+ } else
+ *c = *s;
+ return (*s) ? s+1 : NULL;
+}
+
+static char *
+strqtok(
+ char *s, /* String to tokenize. NULL to continue same str */
+ char *delim, /* Token delimiters. Can be changed w/ each call. */
+ char *quotemarks, /* Quotation marks. Can be changed w/ each call. */
+ char *commentchars, /* Comment characters. Can be changed w/ each call. */
+ unsigned int flags) /* flags&01 -> strip quotes;
+ * flags&02 -> enable backslash escapes;
+ * flags&04 -> skip all delims before return;
+ */
+{
+ register char *p, *q;
+ char c;
+ char leftquote = 0;
+ char *token;
+ int backslashed, inquote, intok;
+
+ int stripquote = flags & 01; /* strip quotemarks from tokens */
+ int backslash = flags & 02; /* backslash sequences */
+ int skipdelim = flags & 04; /* skip seq of delims at end of token */
+
+ /* New string? */
+ if (s)
+ strq_start = s;
+ if (!strq_start)
+ return NULL;
+
+ /* Skip leading delimiters */
+ for (p=strq_start; *p && strchr(delim, *p); p++)
+ ;
+ if (!(*p) || strchr(commentchars, *p))
+ return NULL;
+
+ /* Set `token' to point to returned string.
+ * Use p and q to walk through the user's string:
+ * p will follow input characters;
+ * q will overwrite w/ outputted characters, minus possibly-stripped
+ * quotes and including nulls after each token.
+ */
+ token = q = p;
+ inquote = 0;
+ intok = 1;
+ if (backslash) {
+ while (intok && (p = strqtok_cchar(p, &c, &backslashed))) {
+ if (backslashed) {
+ *q++ = c; /* treat as plain character */
+ } else if (!inquote && *delim && strchr(delim, c)) {
+ *q = '\0'; /* Reached end of token */
+ intok = 0;
+ } else if (!inquote && *commentchars && strchr(commentchars, c)) {
+ *q = '\0'; /* Reached end of token */
+ *p = '\0'; /* make it act like end of string */
+ intok = 0;
+ } else if (!inquote && *quotemarks && strchr(quotemarks, c)) {
+ inquote = 1; /* Beginning a quoted segment */
+ leftquote = c; /* Save quote char for matching with */
+ if (!stripquote) *q++ = c;
+ } else if (inquote && leftquote == c) {
+ inquote = 0; /* Ending a quoted segment */
+ if (!stripquote) *q++ = c;
+ } else {
+ *q++ = c; /* Ordinary character */
+ }
+ }
+ strq_start = p; /* Where to start next search */
+ *q = '\0';
+ } else {
+ while (intok && *p) {
+ if (!inquote && *delim && strchr(delim, *p)) {
+ *q = '\0'; /* Reached end of token */
+ p++; /* advance p for next token */
+ intok = 0;
+ } else if (!inquote && *commentchars && strchr(commentchars, *p)) {
+ *q = '\0'; /* Reached end of token */
+ *p = '\0'; /* make it act like end of string */
+ intok = 0;
+ } else if (!inquote && *quotemarks && strchr(quotemarks, *p)) {
+ inquote = 1; /* Beginning a quoted segment */
+ leftquote = *p++; /* Save quote char for matching with */
+ if (!stripquote) *q++ = leftquote;
+ } else if (inquote && leftquote == *p) {
+ inquote = 0; /* Ending a quoted segment */
+ p++;
+ if (!stripquote) *q++ = leftquote;
+ } else {
+ *q++ = *p++;
+ }
+ }
+ strq_start = p; /* Where to start next search */
+ *q = '\0';
+ }
+
+ if (skipdelim && strq_start) {
+ /* Skip trailing delimiters */
+ while (*strq_start && strchr(delim, *strq_start))
+ strq_start++;
+ }
+ return token;
+}
+
+#endif
+
/* this file is to be found in the user's home directory */
#ifndef CVSRC_FILENAME
@@ -23,9 +220,68 @@
extern char *strtok ();
+#ifdef RSE_PATCH_CVSRC
+static void read_cvsrc_parentdirs ();
+static void read_cvsrc_file ();
+#endif
+
/* Read cvsrc, processing options matching CMDNAME ("cvs" for global
options, and update *ARGC and *ARGV accordingly. */
+#ifdef RSE_PATCH_CVSRC
+void
+read_cvsrc (argc, argv, cmdname)
+ int *argc;
+ char ***argv;
+ char *cmdname;
+{
+ /* try to read .cvsrc files from parent directories */
+ read_cvsrc_parentdirs(argc, argv, cmdname);
+
+ /* try to read .cvsrc file from home directory */
+ read_cvsrc_file(argc, argv, cmdname, get_homedir());
+
+ return;
+}
+
+/* read .cvsrc files from all parent directories (including the current dir) */
+static void
+read_cvsrc_parentdirs (argc, argv, cmdname)
+ int *argc;
+ char ***argv;
+ char *cmdname;
+{
+ char cwd[PATH_MAX];
+ char *cp;
+ int l;
+
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ return;
+ if ((l = strlen(cwd)) <= 0)
+ return;
+ if (cwd[l-1] != '/') {
+ cwd[l++] = '/';
+ cwd[l++] = '\0';
+ }
+ while (cwd[0] != '\0') {
+ cwd[strlen(cwd)-1] = '\0';
+ read_cvsrc_file(argc, argv, cmdname, cwd);
+ if ((cp = strrchr(cwd, '/')) == NULL)
+ break;
+ *(cp+1) = '\0';
+ }
+ return;
+}
+
+/* read .cvsrc file from a particular directory */
+static void
+read_cvsrc_file (argc, argv, cmdname, homedir)
+ int *argc;
+ char ***argv;
+ char *cmdname;
+ char *homedir;
+{
+#else
void
read_cvsrc (argc, argv, cmdname)
int *argc;
@@ -33,6 +289,7 @@
char *cmdname;
{
char *homedir;
+#endif
char *homeinit;
FILE *cvsrcfile;
@@ -64,7 +321,9 @@
/* determine filename for ~/.cvsrc */
+#ifndef RSE_PATCH_CVSRC
homedir = get_homedir ();
+#endif
/* If we can't find a home directory, ignore ~/.cvsrc. This may
make tracking down problems a bit of a pain, but on the other
hand it might be obnoxious to complain when CVS will function
@@ -123,9 +382,15 @@
if (found)
{
/* skip over command in the options line */
+#ifdef RSE_PATCH_CVSRC
+ for (optstart = strqtok (line + command_len, "\t \n", "\"'", "", 7);
+ optstart;
+ optstart = strqtok (NULL, "\t \n", "\"'", "", 7))
+#else
for (optstart = strtok (line + command_len, "\t \n");
optstart;
optstart = strtok (NULL, "\t \n"))
+#endif
{
new_argv [new_argc++] = xstrdup (optstart);
Index: src/diff.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/diff.c,v
retrieving revision 1.1.1.3
diff -u -d -u -3 -r1.1.1.3 diff.c
--- src/diff.c 24 Apr 2001 18:14:53 -0000 1.1.1.3
+++ src/diff.c 16 Feb 2002 12:36:09 -0000
@@ -77,7 +77,11 @@
"\t-r rev2\tDiff rev1/date1 against rev2.\n",
"\t--ifdef=arg\tOutput diffs in ifdef format.\n",
"(consult the documentation for your diff program for rcsdiff-options.\n",
+#ifdef RSE_PATCH_COSMETICS
+ "The most popular is -c for context diffs and -u for unified diffs).\n",
+#else
"The most popular is -c for context diffs but there are many more).\n",
+#endif
"(Specify the --help global option for a list of other help options)\n",
NULL
};
@@ -224,13 +228,21 @@
optind = 0;
while ((c = getopt_long (argc, argv,
+#if defined(RSE_PATCH_HANDLE)
+ "+abcdefh:ilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:",
+#else
"+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:",
+#endif
longopts, &option_index)) != -1)
{
switch (c)
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+#if defined(RSE_PATCH_HANDLE)
+ case 'i': case 'n': case 'p': case 's': case 't':
+#else
case 'h': case 'i': case 'n': case 'p': case 's': case 't':
+#endif
case 'u': case 'w': case 'y':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
@@ -302,6 +314,17 @@
else
diff_date1 = Make_Date (optarg);
break;
+#ifdef RSE_PATCH_HANDLE
+ case 'h': {
+ time_t t1, t2;
+ if (!handle2dates(optarg, &t1, &t2))
+ error (1, 0, "invalid handle string");
+ t1 -= 1; /* subtract one second to have a real difference */
+ diff_date1 = date_from_time_t(t1);
+ diff_date2 = date_from_time_t(t2);
+ break;
+ }
+#endif
case 'N':
empty_files = 1;
break;
@@ -436,8 +459,16 @@
char *head =
(vers->vn_rcs == NULL
? NULL
+#ifdef RSE_PATCH_DIFFHEAD
+ : RCS_head (vers->srcfile));
+#else
: RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
+#ifdef RSE_PATCH_DEADAWARE
+ exists = (head != NULL && !RCS_isdead(vers->srcfile, head));
+#else
exists = head != NULL;
+#endif
if (head != NULL)
free (head);
}
@@ -447,7 +478,12 @@
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
1, 0);
+#ifdef RSE_PATCH_DEADAWARE
+ exists = (xvers->vn_rcs != NULL &&
+ !RCS_isdead(xvers->srcfile, xvers->vn_rcs));
+#else
exists = xvers->vn_rcs != NULL;
+#endif
freevers_ts (&xvers);
}
if (exists)
@@ -840,7 +876,11 @@
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
? NULL
+#ifdef RSE_PATCH_DIFFHEAD
+ : RCS_head (vers->srcfile));
+#else
: RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
else
{
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
@@ -855,7 +895,11 @@
if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
use_rev2 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
? NULL
+#ifdef RSE_PATCH_DIFFHEAD
+ : RCS_head (vers->srcfile));
+#else
: RCS_branch_head (vers->srcfile, vers->vn_rcs));
+#endif
else
{
xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
Index: src/hash.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/hash.c,v
retrieving revision 1.1.1.3
diff -u -d -u -3 -r1.1.1.3 hash.c
--- src/hash.c 19 Sep 2000 00:06:35 -0000 1.1.1.3
+++ src/hash.c 16 Feb 2002 12:36:09 -0000
@@ -25,17 +25,25 @@
const char *key;
{
unsigned int h = 0;
+#ifndef RSE_PATCH_HASHFUNC
unsigned int g;
+#endif
assert(key != NULL);
while (*key != 0)
{
+#ifdef RSE_PATCH_HASHFUNC
+ /* D.J. Bernstein's popular times 33 function
+ (fast and distributes very well) */
+ h = ((h << 5) + h) + FOLD_FN_CHAR(*key++);
+#else
unsigned int c = *key++;
/* The FOLD_FN_CHAR is so that findnode_fn works. */
h = (h << 4) + FOLD_FN_CHAR (c);
if ((g = h & 0xf0000000) != 0)
h = (h ^ (g >> 24)) ^ g;
+#endif
}
return (h % HASHSIZE);
Index: src/history.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/history.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 history.c
--- src/history.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/history.c 16 Feb 2002 12:36:09 -0000
@@ -235,6 +235,9 @@
static char *tz_name = "+0000";
char *logHistory = ALL_REC_TYPES;
+#ifdef RSE_PATCH_HISTORYFILE
+char *history_file = NULL;
+#endif
/* -r, -t, or -b options, malloc'd. These are "" if the option in
question is not specified or is overridden by another option. The
@@ -668,6 +671,10 @@
if (histfile)
fname = xstrdup (histfile);
+#ifdef RSE_PATCH_HISTORYFILE
+ else if (history_file)
+ fname = xstrdup (history_file);
+#endif
else
{
fname = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM)
@@ -716,10 +723,18 @@
return;
if ( strchr(logHistory, type) == NULL )
return;
+#ifdef RSE_PATCH_HISTORYFILE
+ if (history_file != NULL)
+ fname = xstrdup (history_file);
+ else {
+#endif
fname = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM)
+ sizeof (CVSROOTADM_HISTORY) + 3);
(void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_HISTORY);
+#ifdef RSE_PATCH_HISTORYFILE
+ }
+#endif
/* turn off history logging if the history file does not exist */
if (!isfile (fname))
@@ -731,7 +746,11 @@
if (trace)
fprintf (stderr, "%s-> fopen(%s,a)\n",
CLIENT_SERVER_STR, fname);
+#ifdef RSE_PATCH_NOLOCK
+ if (nolock)
+#else
if (noexec)
+#endif
goto out;
fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
if (fd < 0)
Index: src/import.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/import.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 import.c
--- src/import.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/import.c 16 Feb 2002 12:36:09 -0000
@@ -57,6 +57,140 @@
NULL
};
+#ifdef RSE_PATCH_IMPORTINFO
+
+static char *importinfo_vtag;
+
+static int
+importinfo_descend(thisdir)
+ char *thisdir;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int err = 0;
+ List *dirlist = NULL;
+
+ if ((dirp = CVS_OPENDIR(thisdir)) == NULL) {
+ error(0, errno, "cannot open directory");
+ err++;
+ }
+ else {
+ errno = 0;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+ goto one_more_time_boys;
+ if (strcmp(dp->d_name, CVSADM) == 0)
+ goto one_more_time_boys;
+ if (ign_name(dp->d_name))
+ goto one_more_time_boys;
+ if (
+#ifdef DT_DIR
+ (dp->d_type == DT_DIR || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
+#else
+ isdir (dp->d_name)
+#endif
+ && !wrap_name_has(dp->d_name, WRAP_TOCVS)
+ ) {
+ Node *n;
+ if (dirlist == NULL)
+ dirlist = getlist();
+ n = getnode();
+ n->key = xstrdup(dp->d_name);
+ addnode(dirlist, n);
+ }
+ else if (
+#ifdef DT_DIR
+ dp->d_type == DT_LNK || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
+#else
+ islink (dp->d_name)
+#endif
+ ) {
+ err++;
+ }
+ else {
+ if (strcmp(thisdir, ".") == 0) {
+ run_arg(dp->d_name);
+ }
+ else {
+ char *p;
+ p = xmalloc(strlen(thisdir)+1+strlen(dp->d_name)+1);
+ (void)sprintf(p, "%s/%s", thisdir, dp->d_name);
+ run_arg(p);
+ free(p);
+ }
+ }
+ one_more_time_boys:
+ errno = 0;
+ }
+ if (errno != 0) {
+ error(0, errno, "cannot read directory");
+ err++;
+ }
+ (void)closedir(dirp);
+ }
+ if (dirlist != NULL) {
+ Node *head, *p;
+ head = dirlist->list;
+ for (p = head->next; p != head; p = p->next) {
+ if (strcmp(thisdir, ".") == 0) {
+ err += importinfo_descend(p->key);
+ }
+ else {
+ char *nextdir;
+ nextdir = xmalloc(strlen(thisdir)+1+strlen(p->key)+1);
+ (void)sprintf(nextdir, "%s/%s", thisdir, p->key);
+ err += importinfo_descend(nextdir);
+ free(nextdir);
+ }
+ }
+ dellist(&dirlist);
+ }
+ return err;
+}
+
+/* importinfo configuration entry callback */
+static int
+importinfo_runproc(repository, filter)
+ char *repository;
+ char *filter;
+{
+ char *s, *cp;
+ int rv;
+
+ /* if possible, do an own check to make sure that filter really exists */
+ if (filter[0] == '/') {
+ s = xstrdup(filter);
+ for (cp = s; *cp; cp++) {
+ if (isspace((unsigned char)*cp)) {
+ *cp = '\0';
+ break;
+ }
+ }
+ if (!isfile(s)) {
+ error (0, errno, "cannot find pre-admin filter '%s'", s);
+ free(s);
+ return (1);
+ }
+ free(s);
+ }
+
+ /* construct the filter command */
+ run_setup(filter);
+ run_arg(importinfo_vtag);
+ run_arg(repository);
+ ign_add_file(CVSDOTIGNORE, 1);
+ wrap_add_file(CVSDOTWRAPPER, 1);
+ rv = importinfo_descend(".");
+ if (rv > 0)
+ return rv;
+
+ /* execute the filter command */
+ rv = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+
+ return rv;
+}
+#endif
+
int
import (argc, argv)
int argc;
@@ -221,7 +355,11 @@
do_editor ((char *) NULL, &message, repository,
(List *) NULL);
}
+#ifdef RSE_PATCH_VERIFY
+ do_verify (&message, repository);
+#else
do_verify (message, repository);
+#endif
msglen = message == NULL ? 0 : strlen (message);
if (msglen == 0 || message[msglen - 1] != '\n')
{
@@ -283,6 +421,12 @@
error (1, 0, "attempt to import the repository");
}
+#ifdef RSE_PATCH_IMPORTINFO
+ importinfo_vtag = argv[1];
+ if (Parse_Info(CVSROOTADM_IMPORTINFO, argv[0], importinfo_runproc, 1) > 0)
+ error(1, 0, "Pre-import check failed");
+#endif
+
/*
* Make all newly created directories writable. Should really use a more
* sophisticated security mechanism here.
@@ -323,7 +467,11 @@
"Use the following command to help the merge:");
cvs_output_tagged ("newline", NULL);
cvs_output_tagged ("newline", NULL);
+#ifdef RSE_PATCH_COSMETICS
+ cvs_output_tagged ("text", " ");
+#else
cvs_output_tagged ("text", "\t");
+#endif
cvs_output_tagged ("text", program_name);
if (CVSroot_cmdline != NULL)
{
@@ -353,7 +501,11 @@
conflicts);
(void) fprintf (logfp,
"Use the following command to help the merge:\n\n");
+#ifdef RSE_PATCH_COSMETICS
+ (void) fprintf (logfp, " %s checkout ", program_name);
+#else
(void) fprintf (logfp, "\t%s checkout ", program_name);
+#endif
(void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
argv[1], argv[1], argv[0]);
}
@@ -376,6 +528,9 @@
li->type = T_TITLE;
li->tag = xstrdup (vbranch);
li->rev_old = li->rev_new = NULL;
+#ifdef RSE_PATCH_EXTRAPERCENT
+ li->date = NULL;
+#endif
p->data = (char *) li;
(void) addnode (ulist, p);
Update_Logfile (repository, message, logfp, ulist);
@@ -663,7 +818,11 @@
*/
if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
retval = 1;
+#ifdef RSE_PATCH_IMPORTTOUCH
+ add_log ('T', vfile);
+#else
add_log ('U', vfile);
+#endif
freevers_ts (&vers);
return (retval);
}
Index: src/list.c
===================================================================
RCS file: src/list.c
diff -N src/list.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/list.c 16 Feb 2002 12:36:09 -0000
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1998, Dan Rich <drich@employees.com>
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
+ *
+ * List Directory
+ */
+
+#ifdef RSE_PATCH_RLIST
+
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if 0
+#include "cvs.h"
+#endif
+
+static int cvslist_fileproc PROTO((void *callerdat, struct file_info * finfo));
+static Dtype cvslist_dirproc PROTO((void *callerdat, char *dir, char *repos, char *update_dir, List * entries));
+static int cvslist_output_dir PROTO((Node * node, void *closure));
+static int cvslist_output_file PROTO((char *name));
+static int cvslist_tag_proc PROTO((Node * p, void *closure));
+
+static char *numtag;
+static char *date = NULL;
+static int force_tag_match = 1;
+static int local = 0;
+static int verbose = 0;
+static int list_attic = 0;
+static RCSNode *xrcsnode;
+
+static const char *const status_usage[] = {
+ "Usage: %s %s [-alRv] [-r tag|-D date] modules\n",
+ "\t-a\tInclude attic files\n",
+ "\t-v\tVerbose format; includes additional information for the file\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-r rev\tExisting revision/tag.\n",
+ "\t-D\tExisting date.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int cvslist(int argc, char **argv)
+{
+ int c;
+ int i;
+ int which;
+ int retval;
+
+ if (argc == -1)
+ usage(status_usage);
+ optind = 0;
+ while ((c = getopt(argc, argv, "+alRr:v")) != -1) {
+ switch (c) {
+ case 'a':
+ list_attic = 1;
+ break;
+ case 'D':
+ if (date)
+ free(date);
+ date = Make_Date(optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'r':
+ numtag = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage(status_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (date && numtag)
+ error(1, 0, "-r and -D options are mutually exclusive");
+
+ wrap_setup();
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote) {
+ start_server();
+ ign_setup();
+ if (list_attic)
+ send_arg("-a");
+ if (local)
+ send_arg("-l");
+ if (verbose)
+ send_arg("-v");
+ if (numtag)
+ option_with_arg("-r", numtag);
+ if (date)
+ client_senddate(date);
+#if 0
+ if (supported_request("expand-modules")) {
+ /* This is done here because we need to read responses from the
+ server before we send the command checkout or export files. */
+ client_expand_modules(argc, argv, local);
+ }
+#endif
+ /* Send any remaining arguments -- probably dir/file names */
+ for (i = 0; i < argc; ++i)
+ send_arg(argv[i]);
+ send_to_server("list\012", 0); /* Send the command */
+ return get_responses_and_close();
+ }
+#endif
+#ifdef SERVER_SUPPORT
+ /* If we're the server, make sure we're starting at the root */
+ if (server_active)
+ CVS_CHDIR(current_parsed_root->directory);
+#endif
+
+#if 0
+ if (numtag != NULL)
+ tag_check_valid(numtag, argc, argv, local, 0, "");
+#endif
+
+ which = W_REPOS;
+ if (list_attic)
+ which |= W_ATTIC;
+
+ /* start the recursion processor */
+ cvs_output_tagged("+list", NULL);
+ retval = start_recursion(cvslist_fileproc, (FILESDONEPROC)NULL,
+ cvslist_dirproc, (DIRLEAVEPROC)NULL, NULL,
+ argc, argv, local, which, 0, 1, (char *)NULL, 1);
+ cvs_output_tagged("-list", NULL);
+
+ return retval;
+}
+
+/*
+ * Display file info
+ */
+/* ARGSUSED */
+static int cvslist_fileproc(callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
+{
+ char *buf;
+ Vers_TS *vers;
+
+ /* If a particular revision was specified, only show that one */
+ if (numtag != NULL || date != NULL) {
+ vers = Version_TS(finfo, NULL, NULL, NULL, 0, 0);
+ if (RCS_getversion(vers->srcfile, numtag, date, force_tag_match, NULL) == NULL)
+ return 0;
+ }
+
+ cvslist_output_file(finfo->fullname);
+
+ if (verbose) {
+ vers = Version_TS(finfo, NULL, NULL, NULL, 0, 0);
+ if (vers->srcfile) {
+ List *symbols = RCS_symbols(vers->srcfile);
+
+ cvs_output_tagged("+info", NULL);
+ if (vers->vn_rcs == NULL)
+ cvs_output_tagged("finfo",
+ " Repository revision:\tNo revision control file");
+ else {
+ buf = (char *)malloc(24 + strlen(vers->vn_rcs) + 1 +
+ strlen(vers->srcfile->path) + 1);
+ sprintf(buf, " Repository revision:\t%s\t%s",
+ vers->vn_rcs, vers->srcfile->path);
+ cvs_output_tagged("finfo", buf);
+ }
+ cvs_output_tagged("newline", NULL);
+ cvs_output_tagged("finfo", " Existing Tags:");
+ cvs_output_tagged("newline", NULL);
+ if (symbols) {
+ xrcsnode = finfo->rcs;
+ (void)walklist(symbols, cvslist_tag_proc, NULL);
+ }
+ else
+ cvs_output_tagged("finfo", "\tNo Tags Exist");
+
+ cvs_output_tagged("-info", NULL);
+ cvs_output_tagged("newline", NULL);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Display directory info
+ */
+/* ARGSUSED */
+static Dtype cvslist_dirproc(callerdat, dir, repos, update_dir, entries)
+ void *callerdat;
+ char *dir;
+ char *repos;
+ char *update_dir;
+ List *entries;
+{
+ char *buf;
+ List *dirs;
+
+ buf = (char *)malloc(strlen(update_dir) + 2);
+ sprintf(buf, "%s", update_dir);
+ cvs_output_tagged("fname", buf);
+ cvs_output_tagged("newline", NULL);
+ free(buf);
+
+ if (local) { /* We need to output the current dirs */
+ dirs = Find_Directories(update_dir, W_REPOS, NULL);
+ walklist(dirs, cvslist_output_dir, update_dir);
+ }
+ return R_PROCESS;
+}
+
+static int cvslist_output_dir(node, closure)
+ Node *node;
+ void *closure;
+{
+ char *buf;
+
+ buf = (char *)malloc(strlen((char *)closure) + strlen(node->key) + 3);
+ sprintf(buf, "%s/%s/", (char *)closure, node->key);
+ cvs_output_tagged("fname", buf);
+ cvs_output_tagged("newline", NULL);
+ free(buf);
+ return 0;
+}
+
+static int cvslist_output_file(name)
+ char *name;
+{
+ char *buf;
+ char *nlptr;
+
+ buf = (char *)malloc(strlen(name) + 1);
+ strncpy(buf, name, strlen(name));
+ *(buf+strlen(name)) = '\0';
+
+ /* cvs_output_tagged doesn't like \n */
+ if ((nlptr = strchr(buf, '\n')) != NULL)
+ nlptr = '\0';
+ cvs_output_tagged("fname", buf);
+ cvs_output_tagged("newline", NULL);
+ free(buf);
+ return 0;
+}
+
+static int cvslist_tag_proc(p, closure)
+ Node *p;
+ void *closure;
+{
+ char *branch = NULL;
+ char *buf;
+
+ if (RCS_nodeisbranch(xrcsnode, p->key))
+ branch = RCS_whatbranch(xrcsnode, p->key);
+
+ buf = xmalloc(80 + strlen(p->key)
+ + (branch ? strlen(branch) : strlen(p->data)));
+ sprintf(buf, "\t%-25s\t(%s: %s)", p->key,
+ branch ? "branch" : "revision", branch ? branch : p->data);
+ cvs_output_tagged("finfo", buf);
+ cvs_output_tagged("newline", NULL);
+ free(buf);
+
+ if (branch)
+ free(branch);
+
+ return (0);
+}
+
+#endif /* RSE_PATCH_RLIST */
+
Index: src/lock.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/lock.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 lock.c
--- src/lock.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/lock.c 16 Feb 2002 12:36:09 -0000
@@ -396,7 +396,11 @@
FILE *fp;
char *tmp;
+#ifdef RSE_PATCH_NOLOCK
+ if (nolock)
+#else
if (noexec)
+#endif
return (0);
/* we only do one directory at a time for read locks! */
@@ -468,7 +472,11 @@
{
char *wait_repos;
+#ifdef RSE_PATCH_NOLOCK
+ if (nolock)
+#else
if (noexec)
+#endif
return (0);
/* We only know how to do one list at a time */
Index: src/logmsg.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/logmsg.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 logmsg.c
--- src/logmsg.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/logmsg.c 16 Feb 2002 12:36:09 -0000
@@ -387,14 +387,26 @@
independant of the running of an editor for getting a message.
*/
void
+#ifdef RSE_PATCH_VERIFY
+do_verify (messagep, repository)
+ char **messagep;
+#else
do_verify (message, repository)
char *message;
+#endif
char *repository;
{
FILE *fp;
char *fname;
int retcode = 0;
+#ifdef RSE_PATCH_VERIFY
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char *p;
+ struct stat stbuf;
+#endif
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
/* The verification will happen on the server. */
@@ -408,7 +420,11 @@
/* If there's no message, then we have nothing to verify. Can this
case happen? And if so why would we print a message? */
+#ifdef RSE_PATCH_VERIFY
+ if (*messagep == NULL)
+#else
if (message == NULL)
+#endif
{
cvs_output ("No message to verify\n", 0);
return;
@@ -421,9 +437,15 @@
error (1, errno, "cannot create temporary file %s", fname);
else
{
+#ifdef RSE_PATCH_VERIFY
+ fprintf (fp, "%s", *messagep);
+ if ((*messagep)[0] == '\0' ||
+ (*messagep)[strlen (*messagep) - 1] != '\n')
+#else
fprintf (fp, "%s", message);
if ((message)[0] == '\0' ||
(message)[strlen (message) - 1] != '\n')
+#endif
(void) fprintf (fp, "%s", "\n");
if (fclose (fp) == EOF)
error (1, errno, "%s", fname);
@@ -453,6 +475,41 @@
}
}
+#ifdef RSE_PATCH_VERIFY
+ /*
+ * Put the entire message back into the *messagep variable
+ */
+ if ((fp = open_file (fname, "r")) == NULL) {
+ error(1, errno, "cannot open temporary file %s", fname);
+ return;
+ }
+ if (*messagep)
+ free (*messagep);
+ if (CVS_STAT(fname, &stbuf) != 0)
+ error(1, errno, "cannot find size of temp file %s", fname);
+ *messagep = (char *)xmalloc(stbuf.st_size + 1);
+ *messagep[0] = '\0';
+ line = NULL;
+ line_chars_allocated = 0;
+ if (stbuf.st_size > 0) {
+ p = *messagep;
+ while (1) {
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length == -1) {
+ if (ferror (fp))
+ error (0, errno, "warning: cannot read %s", fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
+ continue;
+ (void) strcpy (p, line);
+ p += line_length;
+ }
+ }
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", fname);
+#endif
+
/* Delete the temp file */
if (unlink_file (fname) < 0)
@@ -582,6 +639,42 @@
{
switch (*c)
{
+#ifdef RSE_PATCH_EXTRAPERCENT
+ case 'o': {
+ char T[2];
+ str_list = xrealloc (str_list, (strlen (str_list) + 1 + 1));
+ switch (li->type) {
+ case T_ADDED: T[0] = 'A'; break;
+ case T_MODIFIED: T[0] = 'M'; break;
+ case T_REMOVED: T[0] = 'R'; break;
+ default: T[0] = '?'; break;
+ }
+ T[1] = '\0';
+ (void) strcat (str_list, T);
+ break;
+ }
+ case 't':
+ str_list =
+ xrealloc (str_list,
+ (strlen (str_list)
+ + (li->tag ? strlen (li->tag) : 0)
+ + 10)
+ );
+ (void) strcat (str_list, (li->tag ? li->tag : ""));
+ break;
+ case 'd': {
+ time_t t;
+ if (li->date != NULL) {
+ t = get_date(li->date, NULL);
+ if (t != ((time_t)-1)) {
+ t += 1; /* re-adjust because of fudge */
+ str_list = xrealloc (str_list, (strlen(str_list)+20));
+ sprintf(str_list+strlen(str_list), "%ld", (long)t);
+ }
+ }
+ break;
+ }
+#endif
case 's':
str_list =
xrealloc (str_list,
Index: src/main.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/main.c,v
retrieving revision 1.1.1.5
diff -u -d -u -3 -r1.1.1.5 main.c
--- src/main.c 27 Apr 2001 19:57:23 -0000 1.1.1.5
+++ src/main.c 16 Feb 2002 12:36:09 -0000
@@ -41,6 +41,9 @@
int quiet = 0;
int trace = 0;
int noexec = 0;
+#ifdef RSE_PATCH_NOLOCK
+int nolock = 0;
+#endif
int logoff = 0;
/* Set if we should be writing CVSADM directories at top level. At
@@ -50,6 +53,15 @@
mode_t cvsumask = UMASK_DFLT;
+#ifdef RSE_PATCH_LOCALID
+char *RCS_citag = NULL;
+#endif
+
+#ifdef RSE_PATCH_PROLOGEPILOG
+char *cvs_prolog = NULL;
+char *cvs_epilog = NULL;
+#endif
+
char *CurDir;
/*
@@ -124,11 +136,17 @@
{ "login", "logon", "lgn", login, 0 },
{ "logout", NULL, NULL, logout, 0 },
#endif /* AUTH_CLIENT_SUPPORT */
+#ifdef RSE_PATCH_PSERVERD
+ { "pserverd", NULL, NULL, pserverd },
+#endif
#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
{ "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */
#endif
{ "rannotate","rann", "ra", annotate, 0 },
{ "rdiff", "patch", "pa", patch, 0 },
+#ifdef RSE_PATCH_RLIST
+ { "rlist", "rls", NULL, cvslist, 0 },
+#endif
{ "release", "re", "rel", release, 0 },
{ "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
{ "rlog", "rl", NULL, cvslog, 0 },
@@ -143,9 +161,53 @@
{ "version", "ve", "ver", version, 0 },
{ "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
{ "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR },
+#ifdef RSE_PATCH_CVSROOT
+ { "root", "ro", "repo", root, CVS_CMD_IGNORE_ADMROOT },
+#endif
{ NULL, NULL, NULL, NULL, 0 },
};
+#ifdef RSE_PATCH_CUSTOMCMD
+
+/* the table of custom commands */
+#define CUSTOMCMD_MAX 20
+static int customcmd_num = 0;
+struct customcmd {
+ char *name;
+ char *command;
+};
+static struct customcmd customcmd_tab[CUSTOMCMD_MAX];
+
+/* the internal handler function for custom commands */
+static int
+customcmd_run(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ char *cmd;
+
+ /* support for `cvs -H <cmd>' */
+ if (argc == -1) {
+ (void)fprintf(stderr, "Usage: %s %s [command arguments]\n",
+ program_name, command_name);
+ error_exit();
+ }
+
+ /* execute the command */
+ cmd = expand_path(argv[0], command_name, 0);
+ run_setup(cmd);
+ for (i = 1; i < argc; i++)
+ run_arg(argv[i]);
+ if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ error(1, 0, "program `%s' of custom command `%s' returned non-zero",
+ cmd, command_name);
+ free(cmd);
+
+ return 0;
+}
+#endif
+
static const char *const usg[] =
{
/* CVS usage messages never have followed the GNU convention of
@@ -186,9 +248,13 @@
paragraph in ../cvs.spec without assuming the reader knows what
version control means. */
+#ifdef RSE_PATCH_COSMETICS
+ "For CVS updates and additional information, see http://www.cvshome.org/\n",
+#else
"For CVS updates and additional information, see\n",
" the CVS home page at http://www.cvshome.org/ or\n",
" Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
+#endif
NULL,
};
@@ -215,11 +281,17 @@
" login Prompt for password for authenticating server\n",
" logout Removes entry in .cvspass for remote repository\n",
#endif /* AUTH_CLIENT_SUPPORT */
+#ifdef RSE_PATCH_PSERVERD
+ " pserverd Password server daemon\n",
+#endif
#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
" pserver Password server mode\n",
#endif
" rannotate Show last revision where each line of module was modified\n",
" rdiff Create 'patch' format diffs between releases\n",
+#ifdef RSE_PATCH_RLIST
+ " rlist List repository directories.\n",
+#endif
" release Indicate that a Module is no longer in use\n",
" remove Remove an entry from the repository\n",
" rlog Print out history information for a module\n",
@@ -234,6 +306,9 @@
" version Show current CVS version(s)\n",
" watch Set watches\n",
" watchers See who is watching a file\n",
+#ifdef RSE_PATCH_CVSROOT
+ " root Maintain repository root locations\n",
+#endif
"(Specify the --help option for a list of other help options)\n",
NULL,
};
@@ -249,6 +324,9 @@
" -w Make checked-out files read-write (default).\n",
" -l Turn history logging off.\n",
" -n Do not execute anything that will change the disk.\n",
+#ifdef RSE_PATCH_NOLOCK
+ " -u Do not create lock files (implies -l).\n",
+#endif
" -t Show trace of program execution -- try with -n.\n",
" -v CVS version and copyright.\n",
" -T tmpdir Use 'tmpdir' for temporary files.\n",
@@ -262,6 +340,10 @@
#endif
" -a Authenticate all net traffic.\n",
#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+ " -P program Run prolog program before processing.\n",
+ " -E program Run epilog program after processing.\n",
+#endif
" -s VAR=VAL Set CVS user variable.\n",
"(Specify the --help option for a list of other help options)\n",
NULL
@@ -332,6 +414,20 @@
if (strcmp (cmd_name, cm->fullname) == 0)
break;
}
+#ifdef RSE_PATCH_CUSTOMCMD
+ {
+ int i;
+ unsigned long int ret = 0;
+ for (i = 0; i < customcmd_num; i++) {
+ if (strcmp(customcmd_tab[i].name, cmd_name) == 0) {
+ ret |= CVS_CMD_IGNORE_ADMROOT;
+ ret &= ~(CVS_CMD_USES_WORK_DIR);
+ ret &= ~(CVS_CMD_MODIFIES_REPOSITORY);
+ return ret;
+ }
+ }
+ }
+#endif
return cm->attr;
}
@@ -401,11 +497,34 @@
int free_CVSroot = 0;
int free_Editor = 0;
int free_Tmpdir = 0;
+#ifdef RSE_PATCH_CVSROOT
+ cvsroot_type *cvsroot_sync = NULL;
+ int cvsroot_cmdline_isreal = 0;
+#endif
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ int standalone_command = 0;
+#endif
int help = 0; /* Has the user asked for help? This
lets us support the `cvs -H cmd'
convention to give help for cmd. */
+#if defined(RSE_PATCH_NOLOCK) ||\
+ defined(RSE_PATCH_PROLOGEPILOG) ||\
+ defined(RSE_PATCH_CUSTOMCMD)
+ static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa"
+#ifdef RSE_PATCH_NOLOCK
+ "u"
+#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+ "P:E:"
+#endif
+#ifdef RSE_PATCH_CUSTOMCMD
+ "C:"
+#endif
+ ;
+#else
static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa";
+#endif
static struct option long_options[] =
{
{"help", 0, NULL, 'H'},
@@ -414,6 +533,9 @@
{"help-synonyms", 0, NULL, 2},
{"help-options", 0, NULL, 4},
{"allow-root", required_argument, NULL, 3},
+#ifdef RSE_PATCH_MAPROOT
+ {"map-root", required_argument, NULL, 5},
+#endif
{0, 0, 0, 0}
};
/* `getopt_long' stores the option index here, but right now we
@@ -468,6 +590,16 @@
}
if (getenv (CVSREAD_ENV) != NULL)
cvswrite = 0;
+#ifdef RSE_PATCH_NOLOCK
+ if (getenv (CVSNOLOCK_ENV)) {
+ nolock = 1;
+ logoff = 1;
+ }
+#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+ cvs_prolog = getenv("CVSPROLOG");
+ cvs_epilog = getenv("CVSEPILOG");
+#endif
/* Set this to 0 to force getopt initialization. getopt() sets
this to 1 internally. */
@@ -487,12 +619,63 @@
use_cvsrc = 0;
}
+#ifdef RSE_PATCH_GLOBALOPTION
+ /*
+ * Perform a pre-lookup of the command name in order to scan cvsrc
+ * file also for command dependent global options. For instance a
+ * "-d" option only for "commit" commands (useful if one uses a
+ * local repository copy for all cvs commands, but commits have to
+ * go directly to the master repository).
+ */
+ if (use_cvsrc) {
+ command_name = argv[optind];
+ if (command_name != NULL && command_name[0] != '\0') {
+ for (cm = cmds; cm->fullname != NULL; cm++)
+ {
+ if (cm->nick1 && !strcmp(command_name, cm->nick1))
+ break;
+ if (cm->nick2 && !strcmp(command_name, cm->nick2))
+ break;
+ if (!strcmp(command_name, cm->fullname))
+ break;
+ }
+ command_name = cm->fullname;
+ }
+ }
+#endif
+
/*
* Scan cvsrc file for global options.
*/
if (use_cvsrc)
read_cvsrc (&argc, &argv, "cvs");
+#ifdef RSE_PATCH_GLOBALOPTION
+ if (use_cvsrc) {
+ if (command_name != NULL && command_name[0] != '\0') {
+ char *cmd;
+#ifdef RSE_PATCH_GLOBALOPTION_PARTLY
+ if ( strcmp(command_name, "commit") == 0
+ || strcmp(command_name, "tag") == 0
+ || strcmp(command_name, "rtag") == 0
+ || strcmp(command_name, "history") == 0
+ || strcmp(command_name, "admin") == 0
+ || strcmp(command_name, "import") == 0
+#ifdef RSE_PATCH_RLIST
+ || strcmp(command_name, "rlist") == 0
+#endif
+ || strcmp(command_name, "rdiff") == 0) {
+#endif
+ cmd = xmalloc(4 + strlen(command_name) + 1);
+ sprintf(cmd, "cvs/%s", command_name);
+ read_cvsrc (&argc, &argv, cmd);
+#ifdef RSE_PATCH_GLOBALOPTION_PARTLY
+ }
+#endif
+ }
+ }
+#endif
+
optind = 0;
opterr = 1;
@@ -518,6 +701,17 @@
/* --allow-root */
root_allow_add (optarg);
break;
+#ifdef RSE_PATCH_MAPROOT
+ case 5: {
+ /* --map-root */
+ char *cp;
+ if ((cp = strchr(optarg, ':')) == NULL)
+ error(1, 0, "invalid argument syntax for --map-root option");
+ *cp++ = '\0';
+ root_map_add(optarg, cp);
+ break;
+ }
+#endif
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
@@ -535,6 +729,10 @@
break;
case 'n':
noexec = 1;
+#ifdef RSE_PATCH_NOLOCK
+ case 'u': /* Fall through */
+ nolock = 1;
+#endif
case 'l': /* Fall through */
logoff = 1;
break;
@@ -573,10 +771,34 @@
case 'd':
if (CVSroot_cmdline != NULL)
free (CVSroot_cmdline);
+#ifdef RSE_PATCH_MAPROOT
+ {
+ char *newarg;
+ if (root_map_it(optarg, &newarg, 0))
+ optarg = newarg;
+ }
+#endif
+#ifdef RSE_PATCH_CVSROOT
+ {
+ cvsroot_type *e;
+ if ((e = cvsroot_lookup(optarg, NULL, NULL)) != NULL) {
+ if (!quiet)
+ fprintf(stderr, "%s: using repository `%s'\n", program_name, e->masterpath);
+ CVSroot_cmdline = xstrdup(e->masterpath);
+ CVSroot = xstrdup(e->masterpath);
+ cvsroot_free(e);
+ }
+ else {
+ cvsroot_cmdline_isreal = 1;
+#endif
CVSroot_cmdline = xstrdup (optarg);
if (free_CVSroot)
free (CVSroot);
CVSroot = xstrdup (optarg);
+#ifdef RSE_PATCH_CVSROOT
+ }
+ }
+#endif
free_CVSroot = 1;
cvs_update_env = 1; /* need to update environment */
break;
@@ -618,6 +840,28 @@
We will issue an error later if stream
authentication is not supported. */
break;
+#ifdef RSE_PATCH_PROLOGEPILOG
+ case 'P':
+ cvs_prolog = xstrdup(optarg);
+ break;
+ case 'E':
+ cvs_epilog = xstrdup(optarg);
+ break;
+#endif
+#ifdef RSE_PATCH_CUSTOMCMD
+ case 'C': {
+ char *cp;
+ if (customcmd_num >= CUSTOMCMD_MAX)
+ error(1, 0, "maximum number of allowed -C options reached");
+ if ((cp = strchr(optarg, ':')) == NULL)
+ error(1, 0, "invalid argument to option -C (has to be \"name:cmd\")");
+ *cp++ = '\0';
+ customcmd_tab[customcmd_num].name = xstrdup(optarg);
+ customcmd_tab[customcmd_num].command = xstrdup(cp);
+ customcmd_num++;
+ break;
+ }
+#endif
case '?':
default:
usage (usg);
@@ -629,6 +873,28 @@
if (argc < 1)
usage (usg);
+#ifdef RSE_PATCH_CUSTOMCMD
+ /* Look up the custom command. */
+ cm = NULL;
+ {
+ int i;
+ command_name = argv[0];
+ for (i = 0; i < customcmd_num; i++) {
+ if (strcmp(customcmd_tab[i].name, command_name) == 0) {
+ struct cmd *ccm;
+ ccm = (struct cmd *)xmalloc(sizeof(struct cmd));
+ ccm->nick1 = NULL;
+ ccm->nick2 = NULL;
+ ccm->func = customcmd_run;
+ ccm->fullname = customcmd_tab[i].name;
+ argv[0] = customcmd_tab[i].command;
+ cm = (const struct cmd *)ccm;
+ standalone_command = 1;
+ }
+ }
+ }
+ if (cm == NULL) {
+#endif
/* Look up the command name. */
@@ -651,6 +917,10 @@
else
command_name = cm->fullname; /* Global pointer for later use */
+#ifdef RSE_PATCH_CUSTOMCMD
+ }
+#endif
+
if (help)
{
argc = -1; /* some functions only check for this */
@@ -676,6 +946,71 @@
CVSUMASK_ENV, cp);
}
+#ifdef RSE_PATCH_CVSPID
+ /* provide the process id of the parent CVS process to
+ sub-processes (usually scripts called from *info files) in order
+ to let them have a unique session handle */
+ {
+ char pidbuf[64];
+ sprintf(pidbuf, "CVSPID=%lu", (unsigned long)getpid());
+ putenv(pidbuf);
+ }
+#endif
+
+#ifdef RSE_PATCH_SETXID
+ if ( strcmp(command_name, "kserver") != 0
+ && strcmp(command_name, "pserver") != 0
+ && strcmp(command_name, "server") == 0) {
+ uid_t uid, euid;
+ gid_t gid, egid;
+ struct passwd *pw;
+ char *env;
+
+ /* adjust group id */
+ gid = getgid();
+ egid = getegid();
+ if (gid != egid)
+ setgid(egid); /* upgrade real to effective gid */
+ else
+ setegid(gid); /* downgrade effective to real gid */
+
+ /* adjust user id */
+ uid = getuid();
+ euid = geteuid();
+ if (uid != euid)
+ setuid(euid); /* upgrade real to effective uid */
+ else
+ seteuid(uid); /* downgrade effective to real uid */
+
+ /* still do not adjust umask */
+ umask(0);
+
+ /* remember real user (especially for getcaller()) */
+ pw = getpwuid(uid);
+#ifdef AUTH_SERVER_SUPPORT
+ CVS_Username = xstrdup(pw->pw_name);
+#if HAVE_PUTENV
+ env = xmalloc(sizeof("LOGNAME=")+strlen(CVS_Username));
+ (void)sprintf(env, "LOGNAME=%s", CVS_Username);
+ (void)putenv(env);
+#endif
+#endif
+
+#if HAVE_PUTENV
+ /* remember running user */
+ pw = getpwuid(getuid());
+ env = xmalloc(sizeof("USER=")+strlen(pw->pw_name));
+ (void)sprintf(env, "USER=%s", pw->pw_name);
+ (void)putenv(env);
+#endif
+ }
+ else {
+ /* delete effective user and group id */
+ seteuid(getuid());
+ setegid(getgid());
+ }
+#endif
+
#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
/* If we are invoked with a single argument "kserver", then we are
running as Kerberos server as root. Do the authentication as
@@ -690,6 +1025,21 @@
}
#endif /* HAVE_KERBEROS */
+#ifdef RSE_PATCH_PSERVERD
+ if (strcmp(command_name, "pserverd") == 0) {
+ /*
+ * perform the socket listening. This returns multiple times,
+ * i.e., for each connection. But the parent never returns.
+ */
+ pserver_daemon(argc, argv);
+
+ /*
+ * switch to regular "cvs server" operation.
+ */
+ argc = 0;
+ command_name = "server";
+ }
+#endif
#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
if (strcmp (command_name, "pserver") == 0)
@@ -714,6 +1064,11 @@
server_active = strcmp (command_name, "server") == 0;
#endif
+#ifdef RSE_PATCH_CVSROOT
+ if (strcmp(command_name, "root") == 0)
+ standalone_command = 1;
+#endif
+
/* This is only used for writing into the history file. For
remote connections, it might be nice to have hostname
and/or remote path, on the other hand I'm not sure whether
@@ -784,8 +1139,12 @@
in server mode, since the client will send the repository
directory after the connection is made. */
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ if (!server_active && !standalone_command)
+#else
if (!server_active)
#endif
+#endif
{
char *CVSADM_Root;
@@ -841,6 +1200,54 @@
error (1, 0,
"CVS/Root file (if any).");
}
+
+#ifdef RSE_PATCH_CVSROOT
+ if (CVSroot_cmdline == NULL || !cvsroot_cmdline_isreal) {
+ cvsroot_type *e;
+ if (lookup_command_attribute(command_name) & CVS_CMD_MODIFIES_REPOSITORY) {
+ if ((e = cvsroot_lookup(NULL, NULL, CVSroot)) != NULL) {
+ /* command modifies repository and we still operare on
+ the slave repository, so switch to the master repository,
+ because we can only perform modifications there. */
+ if (!quiet) {
+ fprintf(stderr, "%s: switching to MASTER location of repository `%s'\n", program_name, e->nickname);
+ fprintf(stderr, "%s: %s <-- %s\n", program_name, e->masterpath, e->slavepath);
+ }
+ if (free_CVSroot)
+ free(CVSroot);
+ CVSroot = xstrdup(e->masterpath);
+ if (CVSroot_cmdline != NULL)
+ free(CVSroot_cmdline);
+ CVSroot_cmdline = xstrdup(e->masterpath);
+ cvsroot_sync = e;
+ free_CVSroot = 1;
+ cvs_update_env = 1;
+ }
+ }
+ else {
+ if ((e = cvsroot_lookup(NULL, CVSroot, NULL)) != NULL) {
+ if (e->slavepath[0] != '\0') {
+ /* command does not modify repository and we still operare on
+ the master repository, so switch to the slave repository,
+ because it is faster by definition. */
+ if (!quiet) {
+ fprintf(stderr, "%s: switching to SLAVE location of repository `%s'\n", program_name, e->nickname);
+ fprintf(stderr, "%s: %s --> %s\n", program_name, e->masterpath, e->slavepath);
+ }
+ if (free_CVSroot)
+ free(CVSroot);
+ CVSroot = xstrdup(e->slavepath);
+ if (CVSroot_cmdline != NULL)
+ free(CVSroot_cmdline);
+ CVSroot_cmdline = xstrdup(e->slavepath);
+ cvsroot_free(e);
+ free_CVSroot = 1;
+ cvs_update_env = 1;
+ }
+ }
+ }
+ }
+#endif /* RSE_PATCH_CVSROOT */
}
/* Here begins the big loop over unique cvsroot values. We
@@ -873,6 +1280,9 @@
end of things. */
while (
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ standalone_command ||
+#endif
#ifdef SERVER_SUPPORT
server_active ||
#endif
@@ -884,8 +1294,12 @@
in server mode, since the client will send the repository
directory after the connection is made. */
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ if (!server_active && !standalone_command)
+#else
if (!server_active)
#endif
+#endif
{
/* Now we're 100% sure that we have a valid CVSROOT
variable. Parse it to see if we're supposed to do
@@ -904,7 +1318,11 @@
* Check to see if the repository exists.
*/
#ifdef CLIENT_SUPPORT
+#ifdef RSE_PATCH_NOLOCK
+ if (!current_parsed_root->isremote && !nolock)
+#else
if (!current_parsed_root->isremote)
+#endif
#endif /* CLIENT_SUPPORT */
{
char *path;
@@ -918,7 +1336,12 @@
{
save_errno = errno;
/* If this is "cvs init", the root need not exist yet. */
+#ifdef RSE_PATCH_CVSROOT
+ if (strcmp (command_name, "init") != 0 &&
+ strcmp (command_name, "root") != 0)
+#else
if (strcmp (command_name, "init") != 0)
+#endif
{
error (1, save_errno, "%s", path);
}
@@ -954,6 +1377,9 @@
read_cvsrc and other such places or vice versa. That sort
of thing probably needs more thought. */
if (1
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ && !standalone_command
+#endif
#ifdef SERVER_SUPPORT
&& !server_active
#endif
@@ -984,7 +1410,49 @@
}
#endif
+#ifdef RSE_PATCH_PROLOGEPILOG
+ if (cvs_prolog != NULL) {
+ char *cmd;
+ cmd = expand_path(cvs_prolog, "prolog", 0);
+ run_setup(cmd);
+ run_arg("prolog");
+ run_arg(command_name);
+ if (CurDir != NULL)
+ run_arg(CurDir);
+ else
+ run_arg("unknown-cwd");
+ if (current_parsed_root != NULL && current_parsed_root->directory != NULL)
+ run_arg(current_parsed_root->directory);
+ else
+ run_arg("unknown-cvsroot");
+ if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ error(1, 0, "prolog program `%s' returned non-zero", cmd);
+ free(cmd);
+ }
+#endif
+
err = (*(cm->func)) (argc, argv);
+
+#ifdef RSE_PATCH_PROLOGEPILOG
+ if (cvs_epilog != NULL) {
+ char *cmd;
+ cmd = expand_path(cvs_epilog, "epilog", 0);
+ run_setup(cmd);
+ run_arg("epilog");
+ run_arg(command_name);
+ if (CurDir != NULL)
+ run_arg(CurDir);
+ else
+ run_arg("unknown-cwd");
+ if (current_parsed_root != NULL && current_parsed_root->directory != NULL)
+ run_arg(current_parsed_root->directory);
+ else
+ run_arg("unknown-cvsroot");
+ if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ error(1, 0, "epilog program `%s' returned non-zero", cmd);
+ free(cmd);
+ }
+#endif
/* Mark this root directory as done. When the server is
active, current_root will be NULL -- don't try and
@@ -1003,11 +1471,20 @@
dellist (&root_directories);
#endif
+#if defined(RSE_PATCH_CVSROOT) || defined(RSE_PATCH_CUSTOMCMD)
+ if (standalone_command)
+ break;
+#endif
#ifdef SERVER_SUPPORT
if (server_active)
break;
#endif
} /* end of loop for cvsroot values */
+
+#ifdef RSE_PATCH_CVSROOT
+ if (cvsroot_sync != NULL)
+ cvsroot_synchronize(cvsroot_sync, 0);
+#endif
} /* end of stuff that gets done if the user DOESN'T ask for help */
Index: src/mkmodules.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/mkmodules.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 mkmodules.c
--- src/mkmodules.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/mkmodules.c 16 Feb 2002 12:36:09 -0000
@@ -186,6 +186,48 @@
NULL
};
+#ifdef RSE_PATCH_ADMININFO
+static const char *const admininfo_contents[] = {
+ "# The \"admininfo\" file is used to control pre-admin checks.\n",
+ "# The filter on the right is invoked with the repository and a list \n",
+ "# of files to check. A non-zero exit of the filter program will \n",
+ "# cause the admin operation to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+#endif
+
+#ifdef RSE_PATCH_IMPORTINFO
+static const char *const importinfo_contents[] = {
+ "# The \"importinfo\" file is used to control pre-import checks.\n",
+ "# The filter on the right is invoked with the repository to check.\n",
+ "# A non-zero exit of the filter program will cause the import\n",
+ "# operation to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+#endif
+
static const char *const checkoutlist_contents[] = {
"# The \"checkoutlist\" file is used to support additional version controlled\n",
"# administrative files in $CVSROOT/CVSROOT, such as template files.\n",
@@ -297,6 +339,26 @@
"# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n",
"# history file, or a subset as needed (ie `TMAR' logs all write operations)\n",
"#LogHistory=TOFEWGCMAR\n",
+#ifdef RSE_PATCH_HISTORYFILE
+ "\n",
+ "# Set `HistoryFile' to the path name (relative to CVSROOT) of the history file\n",
+ "# if you do not want to store it not under CVSROOT/history\n",
+ "#HistoryFile=CVSROOT/history\n",
+#endif
+#ifdef RSE_PATCH_LOCALID
+ "\n",
+ "# Set `LocalIdName' to the name of a local tag to use in addition to Id\n",
+#ifdef RSE_PATCH_LOCALID_NAME
+ "#LocalIdName=" RSE_PATCH_LOCALID_NAME "\n",
+#else
+ "#LocalIdName=LocalId\n",
+#endif
+#endif
+#ifdef RSE_PATCH_CONFIGUMASK
+ "\n",
+ "# Set `UMask' to the octal value of the umask.\n",
+ "#UMask=002\n",
+#endif
NULL
};
@@ -319,6 +381,16 @@
{CVSROOTADM_TAGINFO,
"a %s file can be used to configure 'cvs tag' checking",
taginfo_contents},
+#ifdef RSE_PATCH_ADMININFO
+ {CVSROOTADM_ADMININFO,
+ "a %s file can be used to configure 'cvs admin' checking",
+ admininfo_contents},
+#endif
+#ifdef RSE_PATCH_IMPORTINFO
+ {CVSROOTADM_IMPORTINFO,
+ "a %s file can be used to configure 'cvs import' checking",
+ importinfo_contents},
+#endif
{CVSROOTADM_IGNORE,
"a %s file can be used to specify files to ignore",
NULL},
Index: src/options.h.in
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/options.h.in,v
retrieving revision 1.1.1.2
diff -u -d -u -3 -r1.1.1.2 options.h.in
--- src/options.h.in 27 Jan 1999 22:58:14 -0000 1.1.1.2
+++ src/options.h.in 16 Feb 2002 12:36:46 -0000
@@ -198,3 +198,48 @@
#ifndef STDC_HEADERS
extern void exit ();
#endif
+
+/*
+ * Support for compiling in various RSE extension
+ */
+#ifdef RSE_PATCHES
+#define RSE_PATCH_CVSRC
+#define RSE_PATCH_CVSROOT
+#define RSE_PATCH_GLOBALOPTION
+#define RSE_PATCH_GLOBALOPTION_PARTLY
+#define RSE_PATCH_CUSTOMCMD
+#define RSE_PATCH_PROLOGEPILOG
+#define RSE_PATCH_VERIFY
+#define RSE_PATCH_LOCALID
+#define RSE_PATCH_CVSHEADER
+#define RSE_PATCH_NOLOCK
+#define RSE_PATCH_EXTRAPERCENT
+#define RSE_PATCH_READDNEW
+#define RSE_PATCH_CONFIGUMASK
+#define RSE_PATCH_FASTERUPDATE
+#define RSE_PATCH_DEADAWARE
+#define RSE_PATCH_LOGNAME
+#define RSE_PATCH_HISTORYFILE
+#define RSE_PATCH_IMPORTINFO
+#define RSE_PATCH_ADMININFO
+#define RSE_PATCH_HANDLE
+#define RSE_PATCH_IMPORTTOUCH
+#define RSE_PATCH_RELLOCKDIR
+#define RSE_PATCH_CVSUSER
+#define RSE_PATCH_SETXID
+#define RSE_PATCH_PSERVERD
+#define RSE_PATCH_MAPROOT
+#define RSE_PATCH_RLIST
+#define RSE_PATCH_COSMETICS
+#define RSE_PATCH_HASHFUNC
+#define RSE_PATCH_ADDFILEATTR
+#define RSE_PATCH_WILDPASSWD
+#define RSE_PATCH_CVSPID
+#define RSE_PATCH_BUGFIX
+/* problematic changes, because they break "make check" */
+#undef RSE_PATCH_COSMETICS_HARD
+#undef RSE_PATCH_MERGENOKEYWORD
+#undef RSE_PATCH_DIFFHEAD
+#undef RSE_PATCH_SMARTCONFIG
+#endif
+
Index: src/parseinfo.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/parseinfo.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 parseinfo.c
--- src/parseinfo.c 19 Apr 2001 19:45:32 -0000 1.1.1.4
+++ src/parseinfo.c 16 Feb 2002 12:36:09 -0000
@@ -11,6 +11,9 @@
#include <assert.h>
extern char *logHistory;
+#ifdef RSE_PATCH_HISTORYFILE
+extern char *history_file;
+#endif
/*
* Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
@@ -371,7 +374,24 @@
{
if (lock_dir != NULL)
free (lock_dir);
+#ifdef RSE_PATCH_RELLOCKDIR
+ if (p[0] == '/') {
+#endif
lock_dir = xstrdup (p);
+#ifdef RSE_PATCH_RELLOCKDIR
+ }
+ else {
+ char *s;
+
+ lock_dir = xmalloc (strlen (p)
+ + strlen (current_parsed_root->directory)
+ + 2);
+ strcpy (lock_dir, current_parsed_root->directory);
+ s = lock_dir + strlen (lock_dir);
+ *s++ = '/';
+ strcpy (s, p);
+ }
+#endif
/* Could try some validity checking, like whether we can
opendir it or something, but I don't see any particular
reason to do that now rather than waiting until lock.c. */
@@ -384,6 +404,28 @@
strcpy (logHistory, p);
}
}
+#ifdef RSE_PATCH_HISTORYFILE
+ else if (strcmp (line, "HistoryFile") == 0)
+ {
+ if (history_file != NULL)
+ free (history_file);
+ history_file = xstrdup (p);
+ }
+#endif
+#ifdef RSE_PATCH_LOCALID
+ else if (strcmp (line, "LocalIdName") == 0) {
+ RCS_citag = strdup(p);
+ if (RCS_citag == NULL) {
+ error (0, 0, "%s: no memory for local tag '%s'", infopath, p);
+ goto error_return;
+ }
+ }
+#endif
+#ifdef RSE_PATCH_CONFIGUMASK
+ else if (strcmp (line, "UMask") == 0) {
+ cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777);
+ }
+#endif
else
{
/* We may be dealing with a keyword which was added in a
@@ -397,9 +439,11 @@
adding new keywords to your CVSROOT/config file is not
particularly recommended unless you are planning on using
the new features. */
+#ifndef RSE_PATCH_SMARTCONFIG
error (0, 0, "%s: unrecognized keyword '%s'",
infopath, line);
goto error_return;
+#endif
}
}
if (ferror (fp_info))
Index: src/rcs.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/rcs.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 rcs.c
--- src/rcs.c 24 Apr 2001 18:14:53 -0000 1.1.1.4
+++ src/rcs.c 16 Feb 2002 12:36:09 -0000
@@ -114,6 +114,10 @@
static void rcs_internal_unlockfile PROTO ((FILE *, char *));
static char *rcs_lockfilename PROTO ((char *));
+#ifdef RSE_PATCH_CVSHEADER
+static char *getfullCVSname PROTO((char *, char **));
+#endif
+
/* The RCS file reading functions are called a lot, and they do some
string comparisons. This macro speeds things up a bit by skipping
the function call when the first characters are different. It
@@ -3342,10 +3346,17 @@
size_t len;
};
#define KEYWORD_INIT(s) (s), sizeof (s) - 1
+#ifdef RSE_PATCH_LOCALID
+static struct rcs_keyword keywords[] =
+#else
static const struct rcs_keyword keywords[] =
+#endif
{
{ KEYWORD_INIT ("Author") },
{ KEYWORD_INIT ("Date") },
+#ifdef RSE_PATCH_CVSHEADER
+ { KEYWORD_INIT ("CVSHeader") },
+#endif
{ KEYWORD_INIT ("Header") },
{ KEYWORD_INIT ("Id") },
{ KEYWORD_INIT ("Locker") },
@@ -3355,12 +3366,22 @@
{ KEYWORD_INIT ("Revision") },
{ KEYWORD_INIT ("Source") },
{ KEYWORD_INIT ("State") },
+#ifdef RSE_PATCH_LOCALID
+#ifdef RSE_PATCH_LOCALID_NAME
+ { KEYWORD_INIT (RSE_PATCH_LOCALID_NAME) },
+#else
+ { KEYWORD_INIT ("LocalId") },
+#endif
+#endif
{ NULL, 0 }
};
enum keyword
{
KEYWORD_AUTHOR = 0,
KEYWORD_DATE,
+#ifdef RSE_PATCH_CVSHEADER
+ KEYWORD_CVSHEADER,
+#endif
KEYWORD_HEADER,
KEYWORD_ID,
KEYWORD_LOCKER,
@@ -3369,7 +3390,12 @@
KEYWORD_RCSFILE,
KEYWORD_REVISION,
KEYWORD_SOURCE,
+#ifdef RSE_PATCH_LOCALID
+ KEYWORD_STATE,
+ KEYWORD_LOCALID
+#else
KEYWORD_STATE
+#endif
};
/* Convert an RCS date string into a readable string. This is like
@@ -3506,6 +3532,13 @@
return;
}
+#ifdef RSE_PATCH_LOCALID
+ if (RCS_citag != NULL && keywords[KEYWORD_LOCALID].string == NULL) {
+ keywords[KEYWORD_LOCALID].string = RCS_citag;
+ keywords[KEYWORD_LOCALID].len = strlen(RCS_citag);
+ }
+#endif
+
/* If we are using -kkvl, dig out the locker information if any. */
locker = NULL;
if (expand == KFLAG_KVL)
@@ -3595,15 +3628,28 @@
free_value = 1;
break;
+#ifdef RSE_PATCH_CVSHEADER
+ case KEYWORD_CVSHEADER:
+#endif
case KEYWORD_HEADER:
case KEYWORD_ID:
+#ifdef RSE_PATCH_LOCALID
+ case KEYWORD_LOCALID:
+#endif
{
char *path;
int free_path;
char *date;
+#ifdef RSE_PATCH_CVSHEADER
+ char *old_path = NULL;
+#endif
if (kw == KEYWORD_HEADER)
path = rcs->path;
+#ifdef RSE_PATCH_CVSHEADER
+ else if (kw == KEYWORD_CVSHEADER)
+ path = getfullCVSname(rcs->path, &old_path);
+#endif
else
path = last_component (rcs->path);
path = escape_keyword_value (path, &free_path);
@@ -3623,6 +3669,10 @@
locker != NULL ? locker : "");
if (free_path)
free (path);
+#ifdef RSE_PATCH_CVSHEADER
+ if (old_path)
+ free (old_path);
+#endif
free (date);
free_value = 1;
}
@@ -8419,3 +8469,38 @@
}
return label;
}
+
+#ifdef RSE_PATCH_CVSHEADER
+static char *
+getfullCVSname(CVSname, pathstore)
+ char *CVSname, **pathstore;
+{
+ int rootlen;
+ char *c;
+ int alen;
+
+ if (current_parsed_root->directory != NULL) {
+ alen = sizeof("/" CVSATTIC) - 1;
+ *pathstore = xstrdup(CVSname);
+ if ((c = strrchr(*pathstore, '/')) != NULL) {
+ if (c - *pathstore >= alen) {
+ if (!strncmp(c - alen, "/" CVSATTIC, alen)) {
+ while (*c != '\0') {
+ *(c - alen) = *c;
+ c++;
+ }
+ *(c - alen) = '\0';
+ }
+ }
+ }
+ rootlen = strlen(current_parsed_root->directory);
+ if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) &&
+ (*pathstore)[rootlen] == '/')
+ CVSname = (*pathstore + rootlen + 1);
+ else
+ CVSname = (*pathstore);
+ }
+ return CVSname;
+}
+#endif
+
Index: src/recurse.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/recurse.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 recurse.c
--- src/recurse.c 19 Apr 2001 19:45:33 -0000 1.1.1.4
+++ src/recurse.c 16 Feb 2002 12:36:09 -0000
@@ -508,7 +508,11 @@
if (frame->flags == R_SKIP_ALL)
return (0);
+#ifdef RSE_PATCH_NOLOCK
+ should_readlock = nolock ? 0 : frame->readlock;
+#else
should_readlock = noexec ? 0 : frame->readlock;
+#endif
/* The fact that locks are not active here is what makes us fail to have
the
@@ -550,7 +554,11 @@
*/
if (server_active
/* If there are writelocks around, we cannot pause here. */
+#ifdef RSE_PATCH_NOLOCK
+ && (should_readlock || nolock))
+#else
&& (should_readlock || noexec))
+#endif
server_pause_check();
#endif
Index: src/repos.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/repos.c,v
retrieving revision 1.1.1.3
diff -u -d -u -3 -r1.1.1.3 repos.c
--- src/repos.c 19 Apr 2001 19:45:33 -0000 1.1.1.3
+++ src/repos.c 16 Feb 2002 12:36:09 -0000
@@ -204,3 +204,11 @@
repository[len - 2] = '\0';
}
}
+
+#ifdef RSE_PATCH_RLIST
+/* Shameless hack: in order to avoid having to patch the brain-dead
+ Automake-based CVS build environment (src/Makefile.am) we add the
+ "cvs rlist" code to an arbitrarily chosen source file. */
+#include "list.c"
+#endif
+
Index: src/root.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/root.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 root.c
--- src/root.c 19 Apr 2001 19:45:33 -0000 1.1.1.4
+++ src/root.c 16 Feb 2002 12:36:09 -0000
@@ -122,6 +122,9 @@
/* allocate space to return and fill it in */
strip_trailing_slashes (root);
ret = xstrdup (root);
+#ifdef RSE_PATCH_MAPROOT
+ root_map_it(ret, &ret, 0);
+#endif
out:
free (cvsadm);
free (tmp);
@@ -267,6 +270,87 @@
+#ifdef RSE_PATCH_MAPROOT
+
+typedef struct root_map_st {
+ char *old;
+ char *new;
+} root_map_t;
+
+#define ROOT_MAP_MAX 10
+static int root_map_max = 0;
+static root_map_t root_map_vec[ROOT_MAP_MAX];
+
+void root_map_add(char *old, char *new)
+{
+ if (root_map_max >= ROOT_MAP_MAX)
+ return;
+ root_map_vec[root_map_max].old = xstrdup(old);
+ root_map_vec[root_map_max].new = xstrdup(new);
+ root_map_max++;
+ return;
+}
+
+void root_map_free(void)
+{
+ while (root_map_max > 0) {
+ free(root_map_vec[root_map_max].old);
+ free(root_map_vec[root_map_max].new);
+ root_map_max--;
+ }
+ return;
+}
+
+int root_map_it(char *old, char **new, int prefixonly)
+{
+ int rv;
+ int i;
+ int n;
+
+ if (old == NULL)
+ return 0;
+ rv = 0;
+ for (i = 0; i < root_map_max; i++) {
+ n = strlen(root_map_vec[i].old);
+ if (!prefixonly && strcmp(old, root_map_vec[i].old) == 0) {
+ if (new == NULL) {
+ /* we assume old is buffer and override it */
+ strcpy(old, root_map_vec[i].new);
+ }
+ else {
+ if (old == *new)
+ /* old and new is same pointer we free before */
+ free(old);
+ /* provide new allocated buffer */
+ *new = xmalloc(strlen(root_map_vec[i].new)+1);
+ strcpy(*new, root_map_vec[i].new);
+ }
+ rv = 1;
+ break;
+ }
+ else if (prefixonly && strncmp(old, root_map_vec[i].old, n) == 0) {
+ if (new == NULL) {
+ /* we assume old is buffer and override it */
+ sprintf(old, "%s%s", root_map_vec[i].new, old+n);
+ }
+ else {
+ char *oldnew = *new;
+ /* provide new allocated buffer */
+ *new = xmalloc(strlen(root_map_vec[i].new)+strlen(old+n)+1);
+ sprintf(*new, "%s%s", root_map_vec[i].new, old+n);
+ if (old == oldnew)
+ /* old and new is same pointer we free before */
+ free(old);
+ }
+ rv = 1;
+ break;
+ }
+ }
+ return rv;
+}
+
+#endif /* RSE_PATCH_MAPROOT */
+
/* This global variable holds the global -d option. It is NULL if -d
was not used, which means that we must get the CVSroot information
from the CVSROOT environment variable or from a CVS/Root file. */
@@ -804,3 +888,472 @@
/* NOTREACHED */
}
#endif
+
+#ifdef RSE_PATCH_CVSROOT
+
+#include <string.h>
+
+#ifndef CVS_ROOT_FILE
+#define CVS_ROOT_FILE ".cvsroot"
+#endif
+
+char *
+cvsroot_filename(
+ void)
+{
+ char *homedir;
+ char *rootfile;
+
+ /* Environment should override file. */
+ if ((rootfile = getenv("CVS_ROOTFILE")) != NULL)
+ return xstrdup(rootfile);
+
+ /* Construct absolute pathname to user's password file. */
+ if ((homedir = get_homedir()) == NULL) {
+ error(1, 0, "could not find out home directory");
+ return NULL;
+ }
+ rootfile = (char *)xmalloc(strlen(homedir)+strlen(CVS_ROOT_FILE)+3);
+ strcpy(rootfile, homedir);
+ strcat(rootfile, "/");
+ strcat(rootfile, CVS_ROOT_FILE);
+ return rootfile;
+}
+
+void cvsroot_free(
+ cvsroot_type *e)
+{
+ if (e != NULL) {
+ if (e->nickname != NULL)
+ free(e->nickname);
+ if (e->masterpath != NULL)
+ free(e->masterpath);
+ if (e->slavepath != NULL)
+ free(e->slavepath);
+ if (e->syncprog != NULL)
+ free(e->syncprog);
+ free(e);
+ }
+ return;
+}
+
+cvsroot_type *
+cvsroot_entry_read(
+ FILE *fp)
+{
+ cvsroot_type *e;
+ char *nickname;
+ char *masterpath;
+ char *slavepath;
+ char *syncprog;
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ size_t n;
+
+ e = NULL;
+ line = NULL;
+ line_chars_allocated = 0;
+ while ((line_length = getline(&line, &line_chars_allocated, fp)) >= 0) {
+ /* parse line */
+ line += strspn(line, " \t\n");
+ if (line[0] == '#')
+ continue;
+ nickname = line;
+ if ((n = strcspn(line, " \t\n")) == 0)
+ return NULL;
+ line += n;
+ *line++ = '\0';
+ line += strspn(line, " \t");
+ masterpath = line;
+ if ((n = strcspn(line, " \t\n")) == 0)
+ return NULL;
+ line += n;
+ *line++ = '\0';
+ line += strspn(line, " \t\n");
+ slavepath = "";
+ syncprog = "";
+ if (line[0] != '\0') {
+ slavepath = line;
+ n = strcspn(line, " \t\n");
+ line += n;
+ *line++ = '\0';
+ if (line[0] != '\0') {
+ syncprog = line;
+ n = strcspn(line, " \t\n");
+ line += n;
+ *line++ = '\0';
+ }
+ }
+ e = (cvsroot_type *)xmalloc(sizeof(cvsroot_type));
+ e->nickname = xstrdup(nickname);
+ e->masterpath = xstrdup(masterpath);
+ e->slavepath = xstrdup(slavepath);
+ e->syncprog = xstrdup(syncprog);
+ break;
+ }
+ return e;
+}
+
+void
+cvsroot_entry_write(
+ FILE *fp,
+ cvsroot_type *e)
+{
+ if (fp != NULL && e != NULL) {
+ fprintf(fp, "%s %s",
+ e->nickname, e->masterpath);
+ if (e->slavepath[0] != '\0')
+ fprintf(fp, " %s", e->slavepath);
+ if (e->syncprog[0] != '\0')
+ fprintf(fp, " %s", e->syncprog);
+ fprintf(fp, "\n");
+ }
+ return;
+}
+
+cvsroot_type *
+cvsroot_lookup(
+ char *by_nickname,
+ char *by_masterpath,
+ char *by_slavepath)
+{
+ char *rootfile;
+ cvsroot_type *e = NULL;
+ FILE *fp;
+
+ if ((rootfile = cvsroot_filename()) == NULL)
+ return NULL;
+ if ((fp = fopen(rootfile, "r")) == NULL) {
+ free(rootfile);
+ return NULL;
+ }
+ while ((e = cvsroot_entry_read(fp)) != NULL) {
+ if ( (by_nickname != NULL && strcmp(e->nickname, by_nickname) == 0)
+ || (by_masterpath != NULL && strcmp(e->masterpath, by_masterpath) == 0)
+ || (by_slavepath != NULL && strcmp(e->slavepath, by_slavepath) == 0))
+ break;
+ cvsroot_free(e);
+ }
+ fclose(fp);
+ free(rootfile);
+ return e;
+}
+
+void
+cvsroot_synchronize(
+ cvsroot_type *e,
+ int force)
+{
+ char *cmd;
+ char *arg;
+ char *rsh;
+ int smart;
+ char *syncprog;
+
+ smart = 0;
+ syncprog = e->syncprog;
+ if (syncprog[0] == '-') {
+ smart++;
+ syncprog++;
+ }
+ if (smart && !force) {
+ if (!really_quiet) {
+ if (strcasecmp(syncprog, "manual") == 0) {
+ fprintf(stderr, "%s: synchronize SLAVE with MASTER of repository `%s', please!\n", program_name, e->nickname);
+ }
+ else {
+ fprintf(stderr, "%s: synchronize SLAVE with MASTER of repository `%s'\n", program_name, e->nickname);
+ fprintf(stderr, "%s: by running the command `%s root -s %s', please.\n", program_name, program_name, e->nickname);
+ }
+ }
+ return;
+ }
+
+ if (strcasecmp(syncprog, "manual") == 0) {
+ if (!really_quiet) {
+ fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s'\n", program_name, e->nickname);
+ fprintf(stderr, "%s: has to be performed manually by you!\n", program_name);
+ }
+ }
+ else if (strcasecmp(syncprog, "rsync") == 0 ||
+ strncasecmp(syncprog, "rsync:", 6) == 0) {
+ if (!really_quiet) {
+ fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s':\n", program_name, e->nickname);
+ fprintf(stderr, "%s: %s --> %s (rsync)\n", program_name, e->masterpath, e->slavepath);
+ }
+ run_setup("rsync");
+ if (!quiet)
+ run_arg("-v");
+ if ((rsh = getenv("CVS_RSH")) != NULL) {
+ arg = xmalloc(strlen(rsh)+7);
+ strcpy(arg, "--rsh=");
+ strcat(arg, rsh);
+ run_arg(arg);
+ free(arg);
+ }
+ run_arg("-rlpt");
+ run_arg("--delete");
+ if (strncasecmp(syncprog, "rsync:", 6) == 0) {
+ char *list = xstrdup(syncprog+6);
+ for (arg = strtok(list, ","); arg != NULL; arg = strtok(NULL, ",")) {
+ if (arg[0] == '!') {
+ run_arg("--exclude");
+ run_arg(arg+1);
+ }
+ else {
+ run_arg("--include");
+ run_arg(arg);
+ }
+ }
+ free(list);
+ }
+ arg = xmalloc(strlen(e->masterpath)+2);
+ strcpy(arg, e->masterpath);
+ strcat(arg, "/");
+ run_arg(arg);
+ free(arg);
+ arg = xmalloc(strlen(e->slavepath)+2);
+ strcpy(arg, e->slavepath);
+ strcat(arg, "/");
+ run_arg(arg);
+ free(arg);
+ if (trace) {
+ cvs_output(program_name, 0);
+ cvs_output(" ", 1);
+ cvs_output(command_name, 0);
+ cvs_output(": Executing ", 0);
+ run_print(stdout);
+ cvs_output("\n", 0);
+ }
+ if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ error(1, 0, "synchronization program `rsync' returned non-zero");
+ }
+ else {
+ if (!really_quiet) {
+ fprintf(stderr, "%s: synchronizing SLAVE with MASTER of repository `%s':\n", program_name, e->nickname);
+ fprintf(stderr, "%s: %s --> %s (%s)\n", program_name, e->masterpath, e->slavepath, e->syncprog);
+ }
+ cmd = expand_path(syncprog, "sync", 0);
+ run_setup(cmd);
+ run_arg(e->nickname);
+ run_arg(e->masterpath);
+ run_arg(e->slavepath);
+ if (trace) {
+ cvs_output(program_name, 0);
+ cvs_output(" ", 1);
+ cvs_output(command_name, 0);
+ cvs_output(": Executing ", 0);
+ run_print(stdout);
+ cvs_output("\n", 0);
+ }
+ if (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ error(1, 0, "synchronization program `%s' returned non-zero", cmd);
+ free(cmd);
+ }
+}
+
+static const char *const root_usage[] = {
+ "Usage: %s %s [-v] -e|-E|-l|s [arg ...]\n",
+ "Options:\n",
+ " -v Verbose mode.\n",
+ " -e Edit entry from ~/.cvsroot in batch mode.\n",
+ " -E Edit entry from ~/.cvsroot in visual mode.\n",
+ " -l List entries from ~/.cvsroot.\n",
+ " -s Synchronize entries from ~/.cvsroot.\n",
+ "Synopsis:\n",
+ " Add/Modify an entry:\n",
+ " cvs root -e nickname masterpath [slavepath [syncprog]]\n",
+ " Delete an entry:\n",
+ " cvs root -e nickname\n",
+ " List all or some particular entries:\n",
+ " cvs [-Q] [-q] root [-v] -l [nickname ...]\n",
+ " Synchronize all or some particular entries:\n",
+ " cvs [-Q] [-q] root -s [nickname ...]\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+root(
+ int argc,
+ char **argv)
+{
+ enum {
+ ROOT_MODE_UNKNOWN,
+ ROOT_MODE_EDIT_CMDLINE,
+ ROOT_MODE_EDIT_VISUAL,
+ ROOT_MODE_LIST,
+ ROOT_MODE_SYNC
+ };
+ int mode = ROOT_MODE_UNKNOWN;
+ char *rootfile;
+ char *rootfilebak = NULL;
+ FILE *fp;
+ FILE *fpbak = NULL;
+ int option;
+ cvsroot_type *e;
+ cvsroot_type E;
+ int doit;
+ int i;
+ int rc;
+ int verbose = 0;
+ int found = 0;
+ int oldexists;
+
+ if (argc == -1)
+ usage(root_usage);
+ optind = 0;
+ while ((option = getopt(argc, argv, "veEsl")) != EOF) {
+ switch ((char)option) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'e':
+ mode = ROOT_MODE_EDIT_CMDLINE;
+ break;
+ case 'E':
+ mode = ROOT_MODE_EDIT_VISUAL;
+ break;
+ case 'l':
+ mode = ROOT_MODE_LIST;
+ break;
+ case 's':
+ mode = ROOT_MODE_SYNC;
+ break;
+ case '?':
+ default:
+ usage(root_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (mode == ROOT_MODE_UNKNOWN)
+ error(1, 0, "exactly one of the -e, -E, -l or -s options have to given");
+
+ if (mode == ROOT_MODE_EDIT_CMDLINE) {
+ if (argc < 1 || argc > 4)
+ error(1, 0, "option -e requires 1-4 arguments");
+ E.nickname = argv[0];
+ if (argc >= 2)
+ E.masterpath = argv[1];
+ else
+ E.masterpath = "";
+ if (argc >= 3)
+ E.slavepath = argv[2];
+ else
+ E.slavepath = "";
+ if (argc == 4)
+ E.syncprog = argv[3];
+ else
+ E.syncprog = "";
+ if ((rootfile = cvsroot_filename()) == NULL)
+ return 0;
+ oldexists = 0;
+ if (isfile(rootfile)) {
+ oldexists = 1;
+ rootfilebak = xmalloc(strlen(rootfile)+5);
+ strcpy(rootfilebak, rootfile);
+ strcat(rootfilebak, ".bak");
+ rename(rootfile, rootfilebak);
+ if ((fpbak = fopen(rootfilebak, "r")) == NULL) {
+ free(rootfile);
+ free(rootfilebak);
+ return 0;
+ }
+ }
+ if ((fp = fopen(rootfile, "w")) == NULL) {
+ fclose(fpbak);
+ free(rootfile);
+ free(rootfilebak);
+ return 0;
+ }
+ if (oldexists) {
+ found = 0;
+ while ((e = cvsroot_entry_read(fpbak)) != NULL) {
+ if (strcmp(e->nickname, E.nickname) == 0) {
+ cvsroot_free(e);
+ found = 1;
+ break;
+ }
+ cvsroot_entry_write(fp, e);
+ cvsroot_free(e);
+ }
+ }
+ if (argc > 1)
+ cvsroot_entry_write(fp, &E);
+ if (oldexists) {
+ if (found) {
+ while ((e = cvsroot_entry_read(fpbak)) != NULL) {
+ cvsroot_entry_write(fp, e);
+ cvsroot_free(e);
+ }
+ }
+ fclose(fpbak);
+ }
+ fclose(fp);
+ }
+ else if (mode == ROOT_MODE_EDIT_VISUAL) {
+ if (argc != 0)
+ error(1, 0, "option -E requires no arguments");
+ if ((rootfile = cvsroot_filename()) == NULL)
+ return 0;
+ run_setup(Editor);
+ run_arg(rootfile);
+ if ((rc = run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_SIGIGNORE)) != 0)
+ error (1, rc == -1 ? errno : 0, "warning: editor session failed");
+ }
+ else if (mode == ROOT_MODE_LIST || mode == ROOT_MODE_SYNC) {
+ if ((rootfile = cvsroot_filename()) == NULL)
+ return 0;
+ if ((fp = fopen(rootfile, "r")) == NULL) {
+ free(rootfile);
+ return 0;
+ }
+ while ((e = cvsroot_entry_read(fp)) != NULL) {
+ doit = 0;
+ if (argc == 0)
+ doit = 1;
+ else {
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], e->nickname) == 0) {
+ doit = 1;
+ break;
+ }
+ }
+ }
+ if (doit) {
+ if (mode == ROOT_MODE_LIST) {
+ if (verbose)
+ fprintf(stdout, "Repository `%s':\n"
+ " Master Path: %s\n"
+ " Slave Path: %s\n"
+ " Synchronize: %s\n",
+ e->nickname, e->masterpath,
+ e->slavepath, e->syncprog);
+ else
+ fprintf(stdout, "%s %s %s %s\n",
+ e->nickname, e->masterpath,
+ e->slavepath, e->syncprog);
+ }
+ else if (mode == ROOT_MODE_SYNC) {
+ if (e->slavepath[0] == '\0' || e->syncprog[0] == '\0') {
+ if (argc > 0)
+ error(1, 0, "repository `%s' has no slave path or sync program defined", e->nickname);
+ }
+ else
+ cvsroot_synchronize(e, 1);
+ }
+ }
+ cvsroot_free(e);
+ }
+ fclose(fp);
+ free(rootfile);
+ }
+ return 0;
+}
+
+
+#endif /* RSE_PATCH_CVSROOT */
+
Index: src/sanity.sh
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/sanity.sh,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 sanity.sh
--- src/sanity.sh 25 Apr 2001 22:30:56 -0000 1.1.1.4
+++ src/sanity.sh 16 Feb 2002 12:36:35 -0000
@@ -104,6 +104,7 @@
# "debugger"
#set -x
+echo '[THIS PROCEDURE TAKES APPROX. 25min ON A PII/400MHz, SO BE PATIENT!]'
echo 'This test should produce no other output than this line, and a final "OK".'
# Regexp to match what CVS will call itself in output that it prints.
@@ -8517,11 +8518,13 @@
############################################################
# Check out the whole repository
mkdir 1; cd 1
- dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/checkoutlist
+ dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
+U CVSROOT/importinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
@@ -8541,11 +8544,13 @@
############################################################
# Check out CVSROOT
mkdir 1; cd 1
- dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+ dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
+U CVSROOT/importinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
@@ -8568,11 +8573,13 @@
mkdir 1; cd 1
dotest modules-3 "${testcvs} -q co somedir" ''
cd somedir
- dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
+ dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo
+U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
+U CVSROOT/importinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
@@ -18230,7 +18237,7 @@
add a line on trunk after trunktag"
# But diff thinks that HEAD is "br1". Case (b) from cvs.texinfo.
# Probably people are relying on it.
- dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
+ #RSE# dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" ""
# With a nonbranch sticky tag on a branch,
# HEAD is the head of the trunk
Index: src/server.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/server.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 server.c
--- src/server.c 19 Apr 2001 19:34:04 -0000 1.1.1.4
+++ src/server.c 16 Feb 2002 12:36:09 -0000
@@ -117,6 +117,13 @@
# endif /* AUTH_SERVER_SUPPORT */
+#ifdef RSE_PATCH_PSERVERD
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
/* While processing requests, this buffer accumulates data to be sent to
the client, and then once we are in do_cvs_command, we use it
@@ -734,6 +741,13 @@
if (error_pending()) return;
+#ifdef RSE_PATCH_MAPROOT
+ {
+ char *argnew;
+ if (root_map_it(arg, &argnew, 0))
+ arg = argnew;
+ }
+#endif
if (!isabsolute (arg))
{
if (alloc_pending (80 + strlen (arg)))
@@ -1155,6 +1169,9 @@
char *repos;
status = buf_read_line (buf_from_net, &repos, (int *) NULL);
+#ifdef RSE_PATCH_MAPROOT
+ root_map_it(repos, &repos, 1);
+#endif
if (status == 0)
{
if (!outside_root (repos))
@@ -2181,6 +2198,11 @@
case 'n':
noexec = 1;
break;
+#ifdef RSE_PATCH_NOLOCK
+ case 'u':
+ nolock = 1;
+ break;
+#endif
case 'q':
quiet = 1;
break;
@@ -3916,6 +3938,17 @@
}
/* See server.h for description. */
+#ifdef RSE_PATCH_RLIST
+static void serve_list PROTO ((char *));
+static void
+serve_list (arg)
+ char *arg;
+{
+ if (print_pending_error())
+ return;
+ do_cvs_command("rlist", cvslist);
+}
+#endif
void
server_modtime (finfo, vers_ts)
@@ -4770,6 +4803,9 @@
REQ_LINE("expand-modules", serve_expand_modules, 0),
REQ_LINE("ci", serve_ci, RQ_ESSENTIAL),
REQ_LINE("co", serve_co, RQ_ESSENTIAL),
+#ifdef RSE_PATCH_RLIST
+ REQ_LINE("rlist", serve_list, 0),
+#endif
REQ_LINE("update", serve_update, RQ_ESSENTIAL),
REQ_LINE("diff", serve_diff, 0),
REQ_LINE("log", serve_log, 0),
@@ -5351,8 +5387,13 @@
{
char *env, *cvs_user;
+#if defined(RSE_PATCH_LOGNAME) && defined(AUTH_SERVER_SUPPORT)
+ env = xmalloc (sizeof "LOGNAME=" + strlen (CVS_Username));
+ (void) sprintf (env, "LOGNAME=%s", CVS_Username);
+#else
env = xmalloc (sizeof "LOGNAME=" + strlen (username));
(void) sprintf (env, "LOGNAME=%s", username);
+#endif
(void) putenv (env);
env = xmalloc (sizeof "USER=" + strlen (username));
@@ -5430,6 +5471,13 @@
found_it = 1;
break;
}
+#ifdef RSE_PATCH_WILDPASSWD
+ if (strncmp(linebuf, "*:", 2) == 0) {
+ found_it = 1;
+ namelen = 1;
+ break;
+ }
+#endif
}
if (ferror (fp))
error (0, errno, "cannot read %s", filename);
@@ -5473,10 +5521,14 @@
/* Okay, after this conditional chain, found_password and
host_user_tmp will have useful values: */
+#ifdef RSE_PATCH_WILDPASSWD
+ if (non_cvsuser_portion[strspn(non_cvsuser_portion, " \t")] == '\0')
+#else
if ((non_cvsuser_portion == NULL)
|| (strlen (non_cvsuser_portion) == 0)
|| ((strspn (non_cvsuser_portion, " \t"))
== strlen (non_cvsuser_portion)))
+#endif
{
found_password = NULL;
host_user_tmp = NULL;
@@ -5507,6 +5559,14 @@
*host_user_ptr = xstrdup (host_user_tmp);
retval = 1;
}
+#ifdef RSE_PATCH_WILDPASSWD
+ else if (strcmp(found_password, "*") == 0)
+ {
+ /* Give host_user_ptr permanent storage. */
+ *host_user_ptr = xstrdup(host_user_tmp);
+ retval = -1;
+ }
+#endif
else
{
*host_user_ptr = NULL;
@@ -5552,7 +5612,11 @@
/* host_user already set by reference, so just return. */
goto handle_return;
}
+#ifdef RSE_PATCH_WILDPASSWD
+ else if (rc == -1 || system_auth)
+#else
else if (rc == 0 && system_auth)
+#endif
{
/* No cvs password found, so try /etc/passwd. */
@@ -5594,15 +5658,30 @@
if (*found_passwd)
{
/* user exists and has a password */
+#ifdef RSE_PATCH_WILDPASSWD
+ if (strcmp (found_passwd, crypt (password, found_passwd)) != 0) {
+ if (host_user != NULL) {
+ free (host_user);
+ host_user = NULL;
+ }
+ }
+ else if (host_user == NULL) {
+ host_user = xstrdup (username);
+ }
+#else
host_user = ((! strcmp (found_passwd,
crypt (password, found_passwd)))
? xstrdup (username) : NULL);
+#endif
goto handle_return;
}
else if (password && *password)
{
/* user exists and has no system password, but we got
one as parameter */
+#ifdef RSE_PATCH_WILDPASSWD
+ if (host_user == NULL)
+#endif
host_user = xstrdup (username);
goto handle_return;
}
@@ -5613,7 +5692,11 @@
goto handle_return;
}
}
+#ifdef RSE_PATCH_WILDPASSWD
+ else
+#else
else if (rc == 0)
+#endif
{
/* Note that the message _does_ distinguish between the case in
which we check for a system password and the case in which
@@ -5634,6 +5717,7 @@
#endif
exit (EXIT_FAILURE);
}
+#ifndef RSE_PATCH_WILDPASSWD
else
{
/* Something strange happened. We don't know what it was, but
@@ -5641,6 +5725,7 @@
host_user = NULL;
goto handle_return;
}
+#endif
handle_return:
if (host_user)
@@ -5778,6 +5863,10 @@
strip_trailing_newlines (username);
strip_trailing_newlines (password);
+#ifdef RSE_PATCH_MAPROOT
+ root_map_it(repository, &repository, 0);
+#endif
+
/* ... and make sure the protocol ends on the right foot. */
/* See above comment about error handling. */
getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX);
@@ -6611,3 +6700,520 @@
cvs_output (text, 0);
}
}
+
+#ifdef RSE_PATCH_PSERVERD
+
+/* ========================================================================= */
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+
+static void pserver_handshake(void);
+
+/*
+ * Main procedure stub. This is called in two contexts: first under "cvs
+ * -H pserverd" where we just display the usage; second inside the CVS
+ * main loop where we have to act as the regular "cvs server".
+ */
+
+static const char *const pserverd_usage[] = {
+ "Usage: %s %s [-v] [-d] [-l addr[:port]] [-p pidfile] [-A user] [-R user:repos:chroot]\n",
+ "\t-v\tVerbose mode.\n",
+ "\t-d\tDetach into background and run as a daemon.\n",
+ "\t-l\tListen to a particular address/port.\n",
+ "\t-p\tWrite the daemon's PID to a file.\n",
+ "\t-A\tForce global -l -n -u options for a particular user.\n",
+ "\t-R\tPerform a chroot(2) for a user/repository pair.\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+pserverd(
+ int argc,
+ char **argv)
+{
+ if (argc == -1)
+ usage(pserverd_usage);
+ return server(argc, argv);
+}
+
+/*
+ * The pserver daemon. This listens on a particular TCP/IP socket for
+ * connections. If one occurs, it forks and returns to the caller inside
+ * the child process. The parent process runs forever.
+ */
+
+static struct {
+ char *user;
+ char *repos;
+ char *chroot;
+} pserver_chroot;
+
+static char *pserverd_anonymous_user = NULL;
+static int pserverd_verbose = 0;
+
+static int
+tcp_setinaddr(
+ struct sockaddr_in *addr,
+ const char *host,
+ const char *service,
+ const char *protocol)
+{
+ struct hostent *hp;
+ char *end;
+ long portno;
+ struct servent *serv;
+
+ memset(addr, 0, sizeof *addr);
+ addr->sin_family = AF_INET;
+
+ /* set host part of address */
+ if (host == NULL)
+ addr->sin_addr.s_addr = INADDR_ANY;
+ else {
+ addr->sin_addr.s_addr = inet_addr(host);
+ if (addr->sin_addr.s_addr == (unsigned long) -1) {
+ if ((hp = gethostbyname(host)) == NULL)
+ return -1;
+ memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
+ addr->sin_family = hp->h_addrtype;
+ }
+ }
+
+ /* set port part of address */
+ if (service == NULL)
+ addr->sin_port = htons(0);
+ else {
+ portno = strtol(service, &end, 10);
+ if (portno > 0 && portno <= 65535 && end != service && *end == '\0')
+ addr->sin_port = htons(portno);
+ else {
+ if ((serv = getservbyname(service, protocol)) == NULL)
+ return -1;
+ addr->sin_port = serv->s_port;
+ }
+ }
+ return 0;
+}
+
+static int
+tcp_listen(
+ const char *host,
+ const char *port)
+{
+ int s;
+ struct protoent *proto;
+ struct sockaddr_in server;
+ int yes = 1;
+
+ if (tcp_setinaddr(&server, host, port, "tcp") < 0)
+ return -1;
+ if ((proto = getprotobyname("tcp")) == NULL)
+ return -1;
+ if ((s = socket(PF_INET, SOCK_STREAM, proto->p_proto)) < 0)
+ return -1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
+ if (bind(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ close(s);
+ return -1;
+ }
+ if (listen(s, 256) < 0) {
+ close(s);
+ return -1;
+ }
+ return s;
+}
+
+static int
+proc_daemon(
+ int nochdir,
+ int noclose)
+{
+ int fd;
+ int rc;
+
+ /*
+ * Ignore tty related signals
+ */
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_IGN);
+#endif
+
+ /*
+ * fork so the parent can exit, this returns control to the command line
+ * or shell invoking your program. This step is required so that the new
+ * process is guaranteed not to be a process group leader (The next step,
+ * setsid, would fail if you're a process group leader).
+ */
+ rc = fork();
+ switch (rc) {
+ case -1: return -1;
+ case 0: break;
+ default: _exit(0); /* exit original process */
+ }
+
+ /*
+ * setsid to become a process group and session group leader. Since a
+ * controlling terminal is associated with a session, and this new session
+ * has not yet acquired a controlling terminal our process now has no
+ * controlling terminal, which is a Good Thing for daemons.
+ */
+#ifdef HAVE_SETSID
+ if (setsid() == -1)
+ return -1;
+#else
+ if (setpgid(0, getpid()) == -1)
+ return -1;
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
+ if ((fd = open(_PATH_TTY, O_RDWR)) == -1)
+ return -1;
+ ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+#endif
+
+ /*
+ * fork again so the parent, (the session group leader), can exit. This
+ * means that we, as a non-session group leader, can never regain a
+ * controlling terminal.
+ */
+ rc = fork();
+ switch (rc) {
+ case -1: return -1;
+ case 0: break;
+ default: _exit(0); /* exit original process */
+ }
+
+ /*
+ * chdir("/") to ensure that our process doesn't keep any directory in
+ * use. Failure to do this could make it so that an administrator couldn't
+ * unmount a filesystem, because it was our current directory.
+ * [Equivalently, we could change to any directory containing files
+ * important to the daemon's operation.]
+ */
+ if (!nochdir)
+ chdir("/");
+
+ /*
+ * give us complete control over the permissions of anything we write. We
+ * don't know what umask we may have inherited. [This step is optional]
+ */
+ umask(0);
+
+ /*
+ * close fds 0, 1, and 2. This releases the standard in, out, and error we
+ * inherited from our parent process. We have no way of knowing where
+ * these fds might have been redirected to.
+ */
+ if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ close(fd);
+ }
+ return 0;
+}
+
+static void
+pserver_daemon_reapchild(
+ int signo)
+{
+ pid_t child;
+ int status;
+ char buf[128];
+
+ while ((child = waitpid(-1, &status, WNOHANG)) > (pid_t)0) {
+ if (pserverd_verbose) {
+ sprintf(buf, "cvs pserverd[%ld]: child process (pid %ld): terminated.\n",
+ (long)getpid(), (long)child);
+ write(STDOUT_FILENO, buf, strlen(buf));
+ }
+ }
+ signal(signo, &pserver_daemon_reapchild);
+ return;
+}
+
+int
+pserver_daemon(
+ int argc,
+ char **argv)
+{
+ int sd;
+ pid_t child;
+ int option;
+ char *host = NULL;
+ char *port = "2401";
+ char *listen = NULL;
+ struct sockaddr_in them;
+ int detach = 0;
+ char *pidfile = NULL;
+ FILE *fp;
+ char *cp;
+ int len;
+ int ns;
+
+ /* make sure we are running with root priviledges, because
+ we need it later for chroot, switch_to_user, etc. */
+ if (geteuid() != 0)
+ error(1, 0, "root priviledges required for pserver operation");
+
+ /* process "cvs pserverd" command options */
+ optind = 0;
+ while ((option = getopt(argc, argv, "vl:dp:A:R:")) != EOF) {
+ switch ((char) option) {
+ case 'v':
+ pserverd_verbose = 1;
+ break;
+ case 'l':
+ listen = xstrdup(optarg);
+ break;
+ case 'd':
+ detach = 1;
+ pserverd_verbose = 0;
+ break;
+ case 'p':
+ pidfile = xstrdup(optarg);
+ break;
+ case 'A':
+ pserverd_anonymous_user = xstrdup(optarg);
+ break;
+ case 'R':
+ cp = xstrdup(optarg);
+ pserver_chroot.user = cp;
+ if ((cp = strchr(cp, ':')) == NULL)
+ error(1, 0, "invalid -R option argument");
+ *cp++ = '\0';
+ pserver_chroot.repos = cp;
+ if ((cp = strchr(cp, ':')) == NULL)
+ error(1, 0, "invalid -R option argument");
+ *cp++ = '\0';
+ pserver_chroot.chroot = cp;
+ break;
+ case '?':
+ default:
+ usage(pserverd_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 0)
+ usage(pserverd_usage);
+
+ /* optionally go into the background as a real daemon */
+ if (detach)
+ proc_daemon(0, 0);
+
+ /* optionally write out the pid */
+ if (pidfile != NULL) {
+ if ((fp = fopen(pidfile, "w")) == NULL)
+ error(1, 0, "unable to write pid to file %s: %s",
+ pidfile, strerror(errno));
+ fprintf(fp, "%ld\n", (long)getpid());
+ fclose(fp);
+ }
+
+ /* listen on the TCP/IP socket */
+ if (listen != NULL) {
+ if ((port = strrchr(listen, ':')) != NULL)
+ *(port++) = '\0';
+ if (strcasecmp(listen, "*") == 0 || strcmp(listen, "0.0.0.0") == 0)
+ host = NULL;
+ else
+ host = listen;
+ }
+ if ((sd = tcp_listen(host, port)) < 0)
+ error(1, 0, "unable to listen (%s:%s): %s",
+ host != NULL ? host : "*", port, strerror(errno));
+
+ /* make sure we reap the childs */
+ signal(SIGCHLD, &pserver_daemon_reapchild);
+
+ /* daemon loop */
+ for (;;) {
+ len = sizeof(them);
+ ns = accept(sd, (struct sockaddr *)&them, &len);
+ if (ns < 0) {
+ if (errno == EINTR)
+ continue;
+ error(1, 0, "accept(2) failed: %s", strerror(errno));
+ }
+ switch (child = fork()) {
+ case -1:
+ error(1, 0, "unable to fork(2): %s", strerror(errno));
+ break;
+ case 0:
+ /* child */
+ close(sd);
+ signal(SIGCHLD, SIG_DFL);
+
+ /* connect stdin/stdout to socket */
+ dup2(ns, STDIN_FILENO);
+ dup2(ns, STDOUT_FILENO);
+
+ /*
+ * perform "cvs pserver" authentication handshake.
+ */
+ pserver_handshake();
+
+ /*
+ * just return to caller, i.e., the main() procedure
+ * which in turn will dispatch into "cvs server" code
+ * for us...
+ */
+ return 0;
+ break;
+ default:
+ /* parent */
+ if (pserverd_verbose)
+ fprintf(stderr, "cvs pserverd[%ld]: child process (pid %ld): started.\n",
+ (long)getpid(), (long)child);
+ close(ns);
+ break;
+ }
+ }
+ exit(0);
+ return 0;
+}
+
+static void
+pserver_handshake(
+ void)
+{
+ char *tmp = NULL;
+ size_t tmp_allocated = 0;
+ char *repository = NULL;
+ size_t repository_allocated = 0;
+ char *username = NULL;
+ size_t username_allocated = 0;
+ char *password = NULL;
+ size_t password_allocated = 0;
+ char *host_user = NULL;
+ char *descrambled_password;
+ int verify_and_exit = 0;
+ char *chrootdir = NULL;
+ int on;
+
+#ifdef SO_KEEPALIVE
+ /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
+ if the client dies while we are waiting for input. */
+ on = 1;
+ (void)setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on));
+#endif
+
+ /* Make sure the protocol starts off on the right foot... */
+ getline(&tmp, &tmp_allocated, stdin);
+
+ if (strcmp (tmp, "BEGIN VERIFICATION REQUEST\n") == 0)
+ verify_and_exit = 1;
+ else if (strcmp (tmp, "BEGIN AUTH REQUEST\n") == 0)
+ ;
+ else
+ error (1, 0, "bad auth protocol start: %s", tmp);
+
+ /* Get the three important pieces of information in order. */
+ getline(&repository, &repository_allocated, stdin);
+ getline(&username, &username_allocated, stdin);
+ getline(&password, &password_allocated, stdin);
+
+ /* Make them pure. */
+ strip_trailing_newlines(repository);
+ strip_trailing_newlines(username);
+ strip_trailing_newlines(password);
+
+#ifdef RSE_PATCH_MAPROOT
+ root_map_it(repository, &repository, 0);
+#endif
+
+ /* ... and make sure the protocol ends on the right foot. */
+ getline(&tmp, &tmp_allocated, stdin);
+ if (strcmp (tmp, verify_and_exit ?
+ "END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n") != 0)
+ error (1, 0, "bad auth protocol end: %s", tmp);
+
+ if (!root_allow_ok(repository))
+ goto i_hate_you;
+ parse_config(repository);
+
+ /* We need the real cleartext before we hash it. */
+ descrambled_password = descramble(password);
+ host_user = check_password(username, descrambled_password, repository);
+ memset(descrambled_password, 0, strlen(descrambled_password));
+ free(descrambled_password);
+
+ if (host_user == NULL) {
+ i_hate_you:
+ printf("I HATE YOU\n");
+ fflush(stdout);
+ if (pserverd_verbose)
+ fprintf(stderr, "cvs pserverd[%ld]: status=FAILED user=%s root=%s\n",
+ (long)getpid(), username, repository);
+ error_exit();
+ }
+
+ /* Don't go any farther if we're just responding to "cvs login". */
+ if (verify_and_exit) {
+ printf("I LOVE YOU\n");
+ fflush(stdout);
+ if (pserverd_verbose)
+ fprintf(stderr, "cvs pserverd[%ld]: status=OK user=%s root=%s (huser=%s)\n",
+ (long)getpid(), username, repository, host_user);
+ exit(0);
+ }
+
+ /* Set Pserver_Repos so that we can check later that the same
+ repository is sent in later client/server protocol. */
+ Pserver_Repos = xmalloc(strlen(repository)+1);
+ strcpy(Pserver_Repos, repository);
+
+ /* Optionally perform a chroot */
+ if (pserver_chroot.user != NULL) {
+ if ( strcmp(username, pserver_chroot.user) == 0
+ && ( strcmp(repository, pserver_chroot.repos) == 0
+ || strcmp(pserver_chroot.repos, "*") == 0 )) {
+ chrootdir = pserver_chroot.chroot;
+ if (chdir(chrootdir) == -1)
+ error(1, 0, "failed to chdir(2) to %s: %s", chrootdir, strerror(errno));
+ if (chroot(chrootdir) == -1)
+ error(1, 0, "failed to chroot(2) to %s: %s", chrootdir, strerror(errno));
+ }
+ }
+
+ /* Additionally switch to read-only mode for anonymous user */
+ if (pserverd_anonymous_user != NULL) {
+ if (strcmp(username, pserverd_anonymous_user) == 0) {
+#ifdef RSE_PATCH_NOLOCK
+ nolock = 1;
+#endif
+ logoff = 1;
+ }
+ }
+
+ /* Switch to run as this user. */
+ switch_to_user(host_user);
+ free(tmp);
+ free(repository);
+ free(username);
+ free(password);
+
+ printf("I LOVE YOU\n");
+ fflush(stdout);
+ if (pserverd_verbose)
+ fprintf(stderr, "cvs pserverd[%ld]: status=OK user=%s root=%s (huser=%s hroot=%s)\n",
+ (long)getpid(), username, repository, host_user, chrootdir != NULL ? chrootdir : "/");
+ return;
+}
+
+#endif /* RSE_PATCH_PSERVERD */
+
Index: src/subr.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/subr.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 subr.c
--- src/subr.c 19 Apr 2001 19:34:04 -0000 1.1.1.4
+++ src/subr.c 16 Feb 2002 13:49:47 -0000
@@ -336,6 +336,22 @@
uid_t uid;
#endif
+#ifdef RSE_PATCH_CVSUSER
+#ifndef RSE_PATCH_CVSUSER_CALLER
+#define RSE_PATCH_CVSUSER_CALLER "cvs"
+#endif
+ uid = getuid();
+ if ((pw = (struct passwd *)getpwnam(RSE_PATCH_CVSUSER_CALLER)) != NULL) {
+ if (pw->pw_uid == uid) {
+ char *name;
+ if ((name = getenv("CVSUSER")) != NULL) {
+ cache = xstrdup(name);
+ return cache;
+ }
+ }
+ }
+#endif
+
/* If there is a CVS username, return it. */
#ifdef AUTH_SERVER_SUPPORT
if (CVS_Username != NULL)
@@ -797,6 +813,73 @@
return backup_name;
}
+
+#ifdef RSE_PATCH_HANDLE
+/* handle: 2000041317203601
+ date1: 2000/04/13 17:20:36
+ date2: 2000/04/13 17:20:37 */
+int handle2dates(char *handle, time_t *t1, time_t *t2)
+{
+ int Y,M,D,h,m,s,o;
+ char buf[17];
+ time_t t;
+ struct tm tm;
+ int rev = 0;
+ int i;
+
+ /* check for correct handle format */
+ if (handle == NULL)
+ return 0;
+ if (handle[0] == '!') {
+ handle++;
+ rev = 1;
+ }
+ if (strlen(handle) != 16)
+ return 0;
+ for (i = 0; i < 16; i++)
+ if (!isdigit(handle[i]))
+ return 0;
+
+ /* parse out handle parts */
+ strcpy(buf, handle);
+ o = atoi(buf+14);
+ buf[14] = '\0';
+ s = atoi(buf+12);
+ buf[12] = '\0';
+ m = atoi(buf+10);
+ buf[10] = '\0';
+ h = atoi(buf+8);
+ buf[8] = '\0';
+ D = atoi(buf+6);
+ buf[6] = '\0';
+ M = atoi(buf+4);
+ buf[4] = '\0';
+ Y = atoi(buf);
+
+ /* assemble parts into a time value */
+ memset(&tm, 0, sizeof tm);
+ tm.tm_sec = s;
+ tm.tm_min = m;
+ tm.tm_hour = h;
+ tm.tm_mday = D;
+ tm.tm_mon = M - 1;
+ tm.tm_year = Y - 1900;
+ t = mktime(&tm);
+ if (t == -1)
+ return 0;
+
+ /* output the first and second time */
+ if (rev) {
+ *t2 = t;
+ *t1 = t + o;
+ }
+ else {
+ *t1 = t;
+ *t2 = t + o;
+ }
+ return 1;
+}
+#endif
/*
* Copy a string into a buffer escaping any shell metacharacters. The
Index: src/tag.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/tag.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 tag.c
--- src/tag.c 24 Apr 2001 17:04:59 -0000 1.1.1.4
+++ src/tag.c 16 Feb 2002 12:36:09 -0000
@@ -1229,7 +1229,11 @@
/* The tags is valid but not mentioned in val-tags. Add it. */
datum value;
+#ifdef RSE_PATCH_NOLOCK
+ if (noexec || nowrite || nolock)
+#else
if (noexec || nowrite)
+#endif
{
if (db != NULL)
dbm_close (db);
Index: src/update.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/update.c,v
retrieving revision 1.1.1.4
diff -u -d -u -3 -r1.1.1.4 update.c
--- src/update.c 24 Apr 2001 17:04:59 -0000 1.1.1.4
+++ src/update.c 16 Feb 2002 12:36:09 -0000
@@ -203,7 +203,11 @@
break;
case 'p':
pipeout = 1;
+#ifdef RSE_PATCH_NOLOCK
+ nolock = noexec = 1; /* so no locks will be created */
+#else
noexec = 1; /* so no locks will be created */
+#endif
break;
case 'j':
if (join_rev2)
@@ -1809,6 +1813,17 @@
patch can't handle that. */
fail = 1;
}
+#ifdef RSE_PATCH_FASTERUPDATE
+ else {
+ /*
+ * Don't send a diff if just sending the entire file
+ * would be smaller
+ */
+ fseek(e, 0L, SEEK_END);
+ if (file_info->st_size < ftell(e))
+ fail = 1;
+ }
+#endif
fclose (e);
}
}
@@ -2563,8 +2578,16 @@
write_letter (finfo, 'C');
}
else
+#ifdef RSE_PATCH_MERGENOKEYWORD
+ {
+ if (*t_options == '\0')
+ t_options = "-kk"; /* to ignore keyword expansions */
+#endif
status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
t_options, rev1, rev2);
+#ifdef RSE_PATCH_MERGENOKEYWORD
+ }
+#endif
if (status != 0 && status != 1)
{
Index: src/version.c
===================================================================
RCS file: /e/ossp/pkg/tool/cvs/cvs/cvs/src/version.c,v
retrieving revision 1.1.1.5
diff -u -d -u -3 -r1.1.1.5 version.c
--- src/version.c 27 Apr 2001 20:02:28 -0000 1.1.1.5
+++ src/version.c 16 Feb 2002 12:38:04 -0000
@@ -12,7 +12,11 @@
#include "cvs.h"
+#ifdef RSE_PATCHES
+char *version_string = "Concurrent Versions System (CVS) 1.11.1p1 [RSE]";
+#else
char *version_string = "Concurrent Versions System (CVS) 1.11.1p1";
+#endif
#ifdef CLIENT_SUPPORT
#ifdef SERVER_SUPPORT