|
|
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
|
|
|
|