summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Lockert <tholo@cvs.openbsd.org>1998-02-22 09:27:26 +0000
committerThorsten Lockert <tholo@cvs.openbsd.org>1998-02-22 09:27:26 +0000
commitb1d3171142efef3d21f576f0ba25905ac9504238 (patch)
tree6443e78e720e9406ad354c33f6c1c03efe04b65a
parente8befda30be9497912a351c5f2bb0b3d0a8257f9 (diff)
Merge local changes to support a configuration file with Cyclic's scheme
-rw-r--r--gnu/usr.bin/cvs/src/cvs.h1
-rw-r--r--gnu/usr.bin/cvs/src/main.c76
-rw-r--r--gnu/usr.bin/cvs/src/mkmodules.c662
-rw-r--r--gnu/usr.bin/cvs/src/parseinfo.c304
-rw-r--r--gnu/usr.bin/cvs/src/server.c1
5 files changed, 790 insertions, 254 deletions
diff --git a/gnu/usr.bin/cvs/src/cvs.h b/gnu/usr.bin/cvs/src/cvs.h
index 342fed2d4ae..a9e83599590 100644
--- a/gnu/usr.bin/cvs/src/cvs.h
+++ b/gnu/usr.bin/cvs/src/cvs.h
@@ -472,7 +472,6 @@ int isabsolute PROTO((const char *filename));
char *last_component PROTO((char *path));
char *get_homedir PROTO ((void));
char *cvs_temp_name PROTO ((void));
-void parseopts PROTO ((const char *root));
int numdots PROTO((const char *s));
char *increment_revnum PROTO ((const char *));
diff --git a/gnu/usr.bin/cvs/src/main.c b/gnu/usr.bin/cvs/src/main.c
index ba4d5c89b8d..7e111bed2b6 100644
--- a/gnu/usr.bin/cvs/src/main.c
+++ b/gnu/usr.bin/cvs/src/main.c
@@ -447,8 +447,8 @@ main (argc, argv)
if (getenv (CVSREAD_ENV) != NULL)
cvswrite = 0;
if (getenv (CVSREADONLYFS_ENV)) {
- readonlyfs = TRUE;
- logoff = TRUE;
+ readonlyfs = 1;
+ logoff = 1;
}
/* Set this to 0 to force getopt initialization. getopt() sets
@@ -823,7 +823,6 @@ Copyright (c) 1989-1997 Brian Berliner, david d `zoo' zuhn, \n\
error (0, 0, "Sorry, you don't have read/write access to the history file");
error (1, save_errno, "%s", path);
}
- parseopts(CVSroot_directory);
free (path);
}
@@ -1007,74 +1006,3 @@ usage (cpp)
(void) fprintf (stderr, *cpp);
error_exit();
}
-
-void
-parseopts(root)
- const char *root;
-{
- char path[PATH_MAX];
- int save_errno;
- char buf[1024];
- const char *p;
- char *q;
- FILE *fp;
-
- if (root == NULL) {
- printf("no CVSROOT in parseopts\n");
- return;
- }
- p = strchr (root, ':');
- if (p)
- p++;
- else
- p = root;
- if (p == NULL) {
- printf("mangled CVSROOT in parseopts\n");
- return;
- }
- (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
- if ((fp = fopen(path, "r")) != NULL) {
- while (fgets(buf, sizeof buf, fp) != NULL) {
- if (buf[0] == '#')
- continue;
- q = strrchr(buf, '\n');
- if (q)
- *q = '\0';
-
- if (!strncmp(buf, "tag=", 4)) {
- char *what;
-
- RCS_citag = strdup(buf+4);
- if (RCS_citag == NULL) {
- printf("no memory for local tag\n");
- return;
- }
- what = malloc(sizeof("RCSLOCALID")+1+strlen(RCS_citag)+1);
- if (what == NULL) {
- printf("no memory for local tag\n");
- return;
- }
- sprintf(what, "RCSLOCALID=%s", RCS_citag);
- putenv(what);
- } else if (!strncmp(buf, "umask=", 6)) {
- mode_t mode;
-
- cvsumask = (mode_t)(strtol(buf+6, NULL, 8) & 0777);
- }
- else if (!strncmp(buf, "dlimit=", 7)) {
-#ifdef BSD
-#include <sys/resource.h>
- struct rlimit rl;
-
- if (getrlimit(RLIMIT_DATA, &rl) != -1) {
- rl.rlim_cur = atoi(buf+7);
- rl.rlim_cur *= 1024;
-
- (void) setrlimit(RLIMIT_DATA, &rl);
- }
-#endif /* BSD */
- }
- }
- fclose(fp);
- }
-}
diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c
index c4453588921..bb95d592532 100644
--- a/gnu/usr.bin/cvs/src/mkmodules.c
+++ b/gnu/usr.bin/cvs/src/mkmodules.c
@@ -3,35 +3,18 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
- *
- * mkmodules
- *
- * Re-build the modules database for the CVS system. Accepts one argument,
- * which is the directory that the modules,v file lives in.
- */
+ * specified in the README file that comes with the CVS kit. */
#include "cvs.h"
-
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)mkmodules.c 1.45 94/09/30 $";
-USE(rcsid);
-#endif
+#include "savecwd.h"
+#include "getline.h"
#ifndef DBLKSIZ
#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
#endif
-char *program_name, *command_name;
-
-char *Rcsbin = RCSBIN_DFLT;
-char *CVSroot = CVSROOT_DFLT;
-int noexec = 0; /* Here only to satisfy use in subr.c */
-int trace = 0; /* Here only to satisfy use in subr.c */
-
static int checkout_file PROTO((char *file, char *temp));
-static void make_tempfile PROTO((char *temp));
-static void mkmodules_usage PROTO((void));
+static char *make_tempfile PROTO((void));
static void rename_rcsfile PROTO((char *temp, char *real));
#ifndef MY_NDBM
@@ -39,77 +22,363 @@ static void rename_dbmfile PROTO((char *temp));
static void write_dbmfile PROTO((char *temp));
#endif /* !MY_NDBM */
-
-int
-main (argc, argv)
- int argc;
- char **argv;
-{
- char temp[PATH_MAX];
- char *cp, *last, *fname;
-#ifdef MY_NDBM
- DBM *db;
-#endif
- FILE *fp;
- char line[512];
- static struct _checkout_file {
- char *filename;
- char *errormsg;
- } *fileptr, filelist[] = {
+/* Structure which describes an administrative file. */
+struct admin_file {
+ /* Name of the file, within the CVSROOT directory. */
+ char *filename;
+
+ /* This is a one line description of what the file is for. It is not
+ currently used, although one wonders whether it should be, somehow.
+ If NULL, then don't process this file in mkmodules (FIXME?: a bit of
+ a kludge; probably should replace this with a flags field). */
+ char *errormsg;
+
+ /* Contents which the file should have in a new repository. To avoid
+ problems with brain-dead compilers which choke on long string constants,
+ this is a pointer to an array of char * terminated by NULL--each of
+ the strings is concatenated.
+
+ If this field is NULL, the file is not created in a new
+ repository, but it can be added with "cvs add" (just as if one
+ had created the repository with a version of CVS which didn't
+ know about the file) and the checked-out copy will be updated
+ without having to add it to checkoutlist. */
+ const char * const *contents;
+};
+
+static const char *const loginfo_contents[] = {
+ "# The \"loginfo\" file controls where \"cvs commit\" log information\n",
+ "# is sent. The first entry on a line is a regular expression which must match\n",
+ "# the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. If a match is found, then the remainder of the line is a filter\n",
+ "# program that should expect log information on its standard input.\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",
+ "#\n",
+ "# You may specify a format string as part of the\n",
+ "# filter. The string is composed of a `%' followed\n",
+ "# by a single format character, or followed by a set of format\n",
+ "# characters surrounded by `{' and `}' as separators. The format\n",
+ "# characters are:\n",
+ "#\n",
+ "# s = file name\n",
+ "# V = old version number (pre-checkin)\n",
+ "# v = new version number (post-checkin)\n",
+ "#\n",
+ "# For example:\n",
+ "#DEFAULT (echo \"\"; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
+ "# or\n",
+ "#DEFAULT (echo \"\"; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
+ NULL
+};
+
+static const char *const rcsinfo_contents[] = {
+ "# The \"rcsinfo\" file is used to control templates with which the editor\n",
+ "# is invoked on commit and import.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. For the first match that is found, then the remainder of the\n",
+ "# line is the name of the file that contains the template.\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
+};
+
+static const char *const editinfo_contents[] = {
+ "# The \"editinfo\" file is used to allow verification of logging\n",
+ "# information. It works best when a template (as specified in the\n",
+ "# rcsinfo file) is provided for the logging procedure. Given a\n",
+ "# template with locations for, a bug-id number, a list of people who\n",
+ "# reviewed the code before it can be checked in, and an external\n",
+ "# process to catalog the differences that were code reviewed, the\n",
+ "# following test can be applied to the code:\n",
+ "#\n",
+ "# Making sure that the entered bug-id number is correct.\n",
+ "# Validating that the code that was reviewed is indeed the code being\n",
+ "# checked in (using the bug-id number or a seperate review\n",
+ "# number to identify this particular code set.).\n",
+ "#\n",
+ "# If any of the above test failed, then the commit would be aborted.\n",
+ "#\n",
+ "# Actions such as mailing a copy of the report to each reviewer are\n",
+ "# better handled by an entry in the loginfo file.\n",
+ "#\n",
+ "# One thing that should be noted is the the ALL keyword is not\n",
+ "# supported. There can be only one entry that matches a given\n",
+ "# repository.\n",
+ NULL
+};
+
+static const char *const verifymsg_contents[] = {
+ "# The \"verifymsg\" file is used to allow verification of logging\n",
+ "# information. It works best when a template (as specified in the\n",
+ "# rcsinfo file) is provided for the logging procedure. Given a\n",
+ "# template with locations for, a bug-id number, a list of people who\n",
+ "# reviewed the code before it can be checked in, and an external\n",
+ "# process to catalog the differences that were code reviewed, the\n",
+ "# following test can be applied to the code:\n",
+ "#\n",
+ "# Making sure that the entered bug-id number is correct.\n",
+ "# Validating that the code that was reviewed is indeed the code being\n",
+ "# checked in (using the bug-id number or a seperate review\n",
+ "# number to identify this particular code set.).\n",
+ "#\n",
+ "# If any of the above test failed, then the commit would be aborted.\n",
+ "#\n",
+ "# Actions such as mailing a copy of the report to each reviewer are\n",
+ "# better handled by an entry in the loginfo file.\n",
+ "#\n",
+ "# One thing that should be noted is the the ALL keyword is not\n",
+ "# supported. There can be only one entry that matches a given\n",
+ "# repository.\n",
+ NULL
+};
+
+static const char *const commitinfo_contents[] = {
+ "# The \"commitinfo\" file is used to control pre-commit 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 commit 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
+};
+
+static const char *const taginfo_contents[] = {
+ "# The \"taginfo\" file is used to control pre-tag checks.\n",
+ "# The filter on the right is invoked with the following arguments:\n",
+ "#\n",
+ "# $1 -- tagname\n",
+ "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n",
+ "# $3 -- repository\n",
+ "# $4-> file revision [file revision ...]\n",
+ "#\n",
+ "# A non-zero exit of the filter program will cause the tag 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
+};
+
+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",
+ "#\n",
+ "# The first entry on a line is a filename which will be checked out from\n",
+ "# the corresponding RCS file in the $CVSROOT/CVSROOT directory.\n",
+ "# The remainder of the line is an error message to use if the file cannot\n",
+ "# be checked out.\n",
+ "#\n",
+ "# File format:\n",
+ "#\n",
+ "# [<whitespace>]<filename><whitespace><error message><end-of-line>\n",
+ "#\n",
+ "# comment lines begin with '#'\n",
+ NULL
+};
+
+static const char *const cvswrappers_contents[] = {
+ "# This file affects handling of files based on their names.\n",
+ "#\n",
+ "# The -t/-f options allow one to treat directories of files\n",
+ "# as a single file, or to transform a file in other ways on\n",
+ "# its way in and out of CVS.\n",
+ "#\n",
+ "# The -m option specifies whether CVS attempts to merge files.\n",
+ "#\n",
+ "# The -k option specifies keyword expansion (e.g. -kb for binary).\n",
+ "#\n",
+ "# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)\n",
+ "#\n",
+ "# wildcard [option value][option value]...\n",
+ "#\n",
+ "# where option is one of\n",
+ "# -f from cvs filter value: path to filter\n",
+ "# -t to cvs filter value: path to filter\n",
+ "# -m update methodology value: MERGE or COPY\n",
+ "# -k expansion mode value: b, o, kkv, &c\n",
+ "#\n",
+ "# and value is a single-quote delimited value.\n",
+ "# For example:\n",
+ "#*.gif -k 'b'\n",
+ NULL
+};
+
+static const char *const notify_contents[] = {
+ "# The \"notify\" file controls where notifications from watches set by\n",
+ "# \"cvs watch add\" or \"cvs edit\" are sent. The first entry on a line is\n",
+ "# a regular expression which is tested against the directory that the\n",
+ "# change is being made to, relative to the $CVSROOT. If it matches,\n",
+ "# then the remainder of the line is a filter program that should contain\n",
+ "# one occurrence of %s for the user to notify, and information on its\n",
+ "# standard input.\n",
+ "#\n",
+ "# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n",
+ "#\n",
+ "# For example:\n",
+ "#ALL mail %s -s \"CVS notification\"\n",
+ NULL
+};
+
+static const char *const modules_contents[] = {
+ "# Three different line formats are valid:\n",
+ "# key -a aliases...\n",
+ "# key [options] directory\n",
+ "# key [options] directory files...\n",
+ "#\n",
+ "# Where \"options\" are composed of:\n",
+ "# -i prog Run \"prog\" on \"cvs commit\" from top-level of module.\n",
+ "# -o prog Run \"prog\" on \"cvs checkout\" of module.\n",
+ "# -e prog Run \"prog\" on \"cvs export\" of module.\n",
+ "# -t prog Run \"prog\" on \"cvs rtag\" of module.\n",
+ "# -u prog Run \"prog\" on \"cvs update\" of module.\n",
+ "# -d dir Place module in directory \"dir\" instead of module name.\n",
+ "# -l Top-level directory only -- do not recurse.\n",
+ "#\n",
+ "# NOTE: If you change any of the \"Run\" options above, you'll have to\n",
+ "# release and re-checkout any working directories of these modules.\n",
+ "#\n",
+ "# And \"directory\" is a path to a directory relative to $CVSROOT.\n",
+ "#\n",
+ "# The \"-a\" option specifies an alias. An alias is interpreted as if\n",
+ "# everything on the right of the \"-a\" had been typed on the command line.\n",
+ "#\n",
+ "# You can encode a module within a module by using the special '&'\n",
+ "# character to interpose another module into the current module. This\n",
+ "# can be useful for creating a module that consists of many directories\n",
+ "# spread out over the entire source repository.\n",
+ NULL
+};
+
+static const char *const config_contents[] = {
+ "# Set this to \"no\" if pserver shouldn't check system users/passwords\n",
+ "#SystemAuth=no\n",
+ "# Set this to the name of a local tag to use in addition to Id\n",
+ "#tag=OurTag\n",
+ "# Set this to the default umask to use when creating files and directories\n",
+ "#umask=002\n",
+ "# Set this to the default data resource limit to use\n",
+ "#dlimit=65536\n",
+ NULL
+};
+
+static const struct admin_file filelist[] = {
{CVSROOTADM_LOGINFO,
- "no logging of 'cvs commit' messages is done without a %s file"},
+ "no logging of 'cvs commit' messages is done without a %s file",
+ &loginfo_contents[0]},
{CVSROOTADM_RCSINFO,
- "a %s file can be used to configure 'cvs commit' templates"},
+ "a %s file can be used to configure 'cvs commit' templates",
+ rcsinfo_contents},
{CVSROOTADM_EDITINFO,
- "a %s file can be used to validate log messages"},
+ "a %s file can be used to validate log messages",
+ editinfo_contents},
+ {CVSROOTADM_VERIFYMSG,
+ "a %s file can be used to validate log messages",
+ verifymsg_contents},
{CVSROOTADM_COMMITINFO,
- "a %s file can be used to configure 'cvs commit' checking"},
+ "a %s file can be used to configure 'cvs commit' checking",
+ commitinfo_contents},
{CVSROOTADM_TAGINFO,
- "a %s file can be used to configure 'cvs tag' checking"},
+ "a %s file can be used to configure 'cvs tag' checking",
+ taginfo_contents},
{CVSROOTADM_IGNORE,
- "a %s file can be used to specify files to ignore"},
+ "a %s file can be used to specify files to ignore",
+ NULL},
{CVSROOTADM_CHECKOUTLIST,
- "a %s file can specify extra CVSROOT files to auto-checkout"},
+ "a %s file can specify extra CVSROOT files to auto-checkout",
+ checkoutlist_contents},
{CVSROOTADM_WRAPPER,
- "a %s file can be used to specify files to treat as wrappers"},
- {NULL, NULL}};
-
- /*
- * Just save the last component of the path for error messages
- */
- program_name = last_component (argv[0]);
-
- if (argc != 2)
- mkmodules_usage ();
-
- if ((cp = getenv (RCSBIN_ENV)) != NULL)
- Rcsbin = cp;
-
- /*
- * If Rcsbin is set to something, make sure it is terminated with a slash
- * character. If not, add one.
- */
- if (Rcsbin[0] != '\0')
- {
- int len = strlen (Rcsbin);
- char *rcsbin;
+ "a %s file can be used to specify files to treat as wrappers",
+ cvswrappers_contents},
+ {CVSROOTADM_NOTIFY,
+ "a %s file can be used to specify where notifications go",
+ notify_contents},
+ {CVSROOTADM_MODULES,
+ /* modules is special-cased in mkmodules. */
+ NULL,
+ modules_contents},
+ {CVSROOTADM_READERS,
+ "a %s file specifies read-only users",
+ NULL},
+ {CVSROOTADM_WRITERS,
+ "a %s file specifies read/write users",
+ NULL},
+
+ /* Some have suggested listing CVSROOTADM_PASSWD here too. This
+ would mean that CVS commands which operate on the
+ CVSROOTADM_PASSWD file would transmit hashed passwords over the
+ net. This might seem to be no big deal, as pserver normally
+ transmits cleartext passwords, but the difference is that
+ CVSROOTADM_PASSWD contains *all* passwords, not just the ones
+ currently being used. For example, it could be too easy to
+ accidentally give someone readonly access to CVSROOTADM_PASSWD
+ (e.g. via anonymous CVS or cvsweb), and then if there are any
+ guessable passwords for read/write access (usually there will be)
+ they get read/write access.
+
+ Another worry is the implications of storing old passwords--if
+ someone used a password in the past they might be using it
+ elsewhere, using a similar password, etc, and so saving old
+ passwords, even hashed, is probably not a good idea. */
+
+ {CVSROOTADM_CONFIG,
+ "a %s file configures various behaviors",
+ config_contents},
+ {NULL, NULL}
+};
+
+/* Rebuild the checked out administrative files in directory DIR. */
+int
+mkmodules (dir)
+ char *dir;
+{
+ struct saved_cwd cwd;
+ char *temp;
+ char *cp, *last, *fname;
+#ifdef MY_NDBM
+ DBM *db;
+#endif
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ const struct admin_file *fileptr;
- if (Rcsbin[len - 1] != '/')
- {
- rcsbin = Rcsbin;
- Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */
- (void) strcpy (Rcsbin, rcsbin);
- (void) strcat (Rcsbin, "/");
- }
- }
+ if (save_cwd (&cwd))
+ error_exit ();
- if (chdir (argv[1]) < 0)
- error (1, errno, "cannot chdir to %s", argv[1]);
+ if ( CVS_CHDIR (dir) < 0)
+ error (1, errno, "cannot chdir to %s", dir);
/*
* First, do the work necessary to update the "modules" database.
*/
- make_tempfile (temp);
+ temp = make_tempfile ();
switch (checkout_file (CVSROOTADM_MODULES, temp))
{
@@ -127,7 +396,7 @@ main (argc, argv)
case -1: /* fork failed */
(void) unlink_file (temp);
- exit (1);
+ error (1, errno, "cannot check out %s", CVSROOTADM_MODULES);
/* NOTREACHED */
default:
@@ -138,10 +407,13 @@ main (argc, argv)
} /* switch on checkout_file() */
(void) unlink_file (temp);
+ free (temp);
/* Checkout the files that need it in CVSROOT dir */
for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
- make_tempfile (temp);
+ if (fileptr->errormsg == NULL)
+ continue;
+ temp = make_tempfile ();
if (checkout_file (fileptr->filename, temp) == 0)
rename_rcsfile (temp, fileptr->filename);
#if 0
@@ -156,10 +428,10 @@ main (argc, argv)
error (0, 0, fileptr->errormsg, fileptr->filename);
#endif
(void) unlink_file (temp);
+ free (temp);
}
- /* Use 'fopen' instead of 'open_file' because we want to ignore error */
- fp = fopen (CVSROOTADM_CHECKOUTLIST, "r");
+ fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r");
if (fp)
{
/*
@@ -168,7 +440,7 @@ main (argc, argv)
*
* comment lines begin with '#'
*/
- while (fgets (line, sizeof (line), fp) != NULL)
+ while (getline (&line, &line_allocated, fp) >= 0)
{
/* skip lines starting with # */
if (line[0] == '#')
@@ -186,7 +458,7 @@ main (argc, argv)
;
*cp = '\0';
- make_tempfile (temp);
+ temp = make_tempfile ();
if (checkout_file (fname, temp) == 0)
{
rename_rcsfile (temp, fname);
@@ -198,9 +470,25 @@ main (argc, argv)
if (cp < last && *cp)
error (0, 0, cp, fname);
}
+ free (temp);
}
- (void) fclose (fp);
+ if (line)
+ free (line);
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST);
}
+ else
+ {
+ /* Error from CVS_FOPEN. */
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST);
+ }
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
return (0);
}
@@ -208,25 +496,27 @@ main (argc, argv)
/*
* Yeah, I know, there are NFS race conditions here.
*/
-static void
-make_tempfile (temp)
- char *temp;
+static char *
+make_tempfile ()
{
static int seed = 0;
int fd;
+ char *temp;
if (seed == 0)
seed = getpid ();
+ temp = xmalloc (sizeof (BAKPREFIX) + 40);
while (1)
{
(void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
- if ((fd = open (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
+ if ((fd = CVS_OPEN (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
break;
if (errno != EEXIST)
error (1, errno, "cannot create temporary file %s", temp);
}
if (close(fd) < 0)
error(1, errno, "cannot close temporary file %s", temp);
+ return temp;
}
static int
@@ -234,18 +524,31 @@ checkout_file (file, temp)
char *file;
char *temp;
{
- char rcs[PATH_MAX];
+ char *rcs;
+ RCSNode *rcsnode;
int retcode = 0;
- (void) sprintf (rcs, "%s%s", file, RCSEXT);
+ if (noexec)
+ return 0;
+
+ rcs = xmalloc (strlen (file) + 5);
+ strcpy (rcs, file);
+ strcat (rcs, RCSEXT);
if (!isfile (rcs))
+ {
+ free (rcs);
return (1);
- run_setup ("%s%s -q -p", Rcsbin, RCS_CO);
- run_arg (rcs);
- if ((retcode = run_exec (RUN_TTY, temp, RUN_TTY, RUN_NORMAL)) != 0)
+ }
+ rcsnode = RCS_parsercsfile (rcs);
+ retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp,
+ (RCSCHECKOUTPROC) NULL, (void *) NULL);
+ if (retcode != 0)
{
- error (0, retcode == -1 ? errno : 0, "failed to check out %s file", file);
+ error (0, retcode == -1 ? errno : 0, "failed to check out %s file",
+ file);
}
+ freercsnode (&rcsnode);
+ free (rcs);
return (retcode);
}
@@ -376,12 +679,12 @@ rename_dbmfile (temp)
(void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
(void) unlink_file (bakpag);
(void) unlink_file (bakdb);
- (void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */
- (void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */
- (void) rename (dotdb, bakdb); /* mv modules.db .#modules.db */
- (void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */
- (void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */
- (void) rename (newdb, dotdb); /* mv "temp".db modules.db */
+ (void) CVS_RENAME (dotdir, bakdir); /* mv modules.dir .#modules.dir */
+ (void) CVS_RENAME (dotpag, bakpag); /* mv modules.pag .#modules.pag */
+ (void) CVS_RENAME (dotdb, bakdb); /* mv modules.db .#modules.db */
+ (void) CVS_RENAME (newdir, dotdir); /* mv "temp".dir modules.dir */
+ (void) CVS_RENAME (newpag, dotpag); /* mv "temp".pag modules.pag */
+ (void) CVS_RENAME (newdb, dotdb); /* mv "temp".db modules.db */
/* OK -- make my day */
SIG_endCrSect ();
@@ -394,41 +697,152 @@ rename_rcsfile (temp, real)
char *temp;
char *real;
{
- char bak[50];
+ char *bak;
struct stat statbuf;
- char rcs[PATH_MAX];
-
+ char *rcs;
+
/* Set "x" bits if set in original. */
+ rcs = xmalloc (strlen (real) + sizeof (RCSEXT) + 10);
(void) sprintf (rcs, "%s%s", real, RCSEXT);
statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
- (void) stat (rcs, &statbuf);
+ (void) CVS_STAT (rcs, &statbuf);
+ free (rcs);
if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
error (0, errno, "warning: cannot chmod %s", temp);
+ bak = xmalloc (strlen (real) + sizeof (BAKPREFIX) + 10);
(void) sprintf (bak, "%s%s", BAKPREFIX, real);
(void) unlink_file (bak); /* rm .#loginfo */
- (void) rename (real, bak); /* mv loginfo .#loginfo */
- (void) rename (temp, real); /* mv "temp" loginfo */
+ (void) CVS_RENAME (real, bak); /* mv loginfo .#loginfo */
+ (void) CVS_RENAME (temp, real); /* mv "temp" loginfo */
+ free (bak);
}
+
+const char *const init_usage[] = {
+ "Usage: %s %s\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
-/*
- * For error() only
- */
-void
-Lock_Cleanup ()
+int
+init (argc, argv)
+ int argc;
+ char **argv;
{
-}
+ /* Name of CVSROOT directory. */
+ char *adm;
+ /* Name of this administrative file. */
+ char *info;
+ /* Name of ,v file for this administrative file. */
+ char *info_v;
+ /* Exit status. */
+ int err;
-int server_active = 0;
+ const struct admin_file *fileptr;
-void
-server_cleanup ()
-{
-}
-
-static void
-mkmodules_usage ()
-{
- (void) fprintf (stderr, "Usage: %s modules-directory\n", program_name);
- exit (1);
+ umask (cvsumask);
+
+ if (argc == -1 || argc > 1)
+ usage (init_usage);
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ start_server ();
+
+ ign_setup ();
+ send_init_command ();
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ /* Note: we do *not* create parent directories as needed like the
+ old cvsinit.sh script did. Few utilities do that, and a
+ non-existent parent directory is as likely to be a typo as something
+ which needs to be created. */
+ mkdir_if_needed (CVSroot_directory);
+
+ adm = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + 10);
+ strcpy (adm, CVSroot_directory);
+ strcat (adm, "/");
+ strcat (adm, CVSROOTADM);
+ mkdir_if_needed (adm);
+
+ /* This is needed because we pass "fileptr->filename" not "info"
+ to add_rcs_file below. I think this would be easy to change,
+ thus nuking the need for CVS_CHDIR here, but I haven't looked
+ closely (e.g. see wrappers calls within add_rcs_file). */
+ if ( CVS_CHDIR (adm) < 0)
+ error (1, errno, "cannot change to directory %s", adm);
+
+ /* 80 is long enough for all the administrative file names, plus
+ "/" and so on. */
+ info = xmalloc (strlen (adm) + 80);
+ info_v = xmalloc (strlen (adm) + 80);
+ for (fileptr = filelist; fileptr && fileptr->filename; ++fileptr)
+ {
+ if (fileptr->contents == NULL)
+ continue;
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, fileptr->filename);
+ strcpy (info_v, info);
+ strcat (info_v, RCSEXT);
+ if (isfile (info_v))
+ /* We will check out this file in the mkmodules step.
+ Nothing else is required. */
+ ;
+ else
+ {
+ int retcode;
+
+ if (!isfile (info))
+ {
+ FILE *fp;
+ const char * const *p;
+
+ fp = open_file (info, "w");
+ for (p = fileptr->contents; *p != NULL; ++p)
+ if (fputs (*p, fp) < 0)
+ error (1, errno, "cannot write %s", info);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+ }
+ /* The message used to say " of " and fileptr->filename after
+ "initial checkin" but I fail to see the point as we know what
+ file it is from the name. */
+ retcode = add_rcs_file ("initial checkin", info_v,
+ fileptr->filename, "1.1", NULL,
+
+ /* No vendor branch. */
+ NULL, NULL, 0, NULL,
+
+ NULL, 0, NULL);
+ if (retcode != 0)
+ /* add_rcs_file already printed an error message. */
+ err = 1;
+ }
+ }
+
+ /* Turn on history logging by default. The user can remove the file
+ to disable it. */
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, CVSROOTADM_HISTORY);
+ if (!isfile (info))
+ {
+ FILE *fp;
+
+ fp = open_file (info, "w");
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+ }
+
+ free (info);
+ free (info_v);
+
+ mkmodules (adm);
+
+ free (adm);
+ return 0;
}
diff --git a/gnu/usr.bin/cvs/src/parseinfo.c b/gnu/usr.bin/cvs/src/parseinfo.c
index d19e774f294..cb3c0ee3b02 100644
--- a/gnu/usr.bin/cvs/src/parseinfo.c
+++ b/gnu/usr.bin/cvs/src/parseinfo.c
@@ -3,15 +3,12 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*/
#include "cvs.h"
-
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)parseinfo.c 1.18 94/09/23 $";
-USE(rcsid);
-#endif
+#include "getline.h"
+#include <assert.h>
/*
* Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
@@ -24,19 +21,21 @@ int
Parse_Info (infofile, repository, callproc, all)
char *infofile;
char *repository;
- int (*callproc) ();
+ CALLPROC callproc;
int all;
{
int err = 0;
FILE *fp_info;
- char infopath[PATH_MAX];
- char line[MAXLINELEN];
+ char *infopath;
+ char *line = NULL;
+ size_t line_allocated = 0;
char *default_value = NULL;
+ char *expanded_value= NULL;
int callback_done, line_number;
char *cp, *exp, *value, *srepos;
const char *regex_err;
- if (CVSroot == NULL)
+ if (CVSroot_original == NULL)
{
/* XXX - should be error maybe? */
error (0, 0, "CVSROOT variable not set");
@@ -44,21 +43,32 @@ Parse_Info (infofile, repository, callproc, all)
}
/* find the info file and open it */
- (void) sprintf (infopath, "%s/%s/%s", CVSroot,
+ infopath = xmalloc (strlen (CVSroot_directory)
+ + strlen (infofile)
+ + sizeof (CVSROOTADM)
+ + 10);
+ (void) sprintf (infopath, "%s/%s/%s", CVSroot_directory,
CVSROOTADM, infofile);
- if ((fp_info = fopen (infopath, "r")) == NULL)
- return (0); /* no file -> nothing special done */
+ fp_info = CVS_FOPEN (infopath, "r");
+ if (fp_info == NULL)
+ {
+ /* If no file, don't do anything special. */
+ if (!existence_error (errno))
+ error (0, errno, "cannot open %s", infopath);
+ free (infopath);
+ return 0;
+ }
/* strip off the CVSROOT if repository was absolute */
srepos = Short_Repository (repository);
if (trace)
- (void) fprintf (stderr, "-> ParseInfo(%s, %s, %s)\n",
+ (void) fprintf (stderr, " -> ParseInfo(%s, %s, %s)\n",
infopath, srepos, all ? "ALL" : "not ALL");
/* search the info file for lines that match */
callback_done = line_number = 0;
- while (fgets (line, sizeof (line), fp_info) != NULL)
+ while (getline (&line, &line_allocated, fp_info) >= 0)
{
line_number++;
@@ -97,42 +107,12 @@ Parse_Info (infofile, repository, callproc, all)
if ((cp = strrchr (value, '\n')) != NULL)
*cp = '\0';
- /* FIXME: probably should allow multiple occurrences of CVSROOT. */
- /* FIXME-maybe: perhaps should allow CVSREAD and other cvs
- settings (if there is a need for them, which isn't clear). */
- /* FIXME-maybe: Should there be a way to substitute arbitrary
- environment variables? Probably not, because then what gets
- substituted would depend on who runs cvs. A better feature might
- be to allow a file in CVSROOT to specify variables to be
- substituted. */
+ if (expanded_value != NULL)
+ free (expanded_value);
+ expanded_value = expand_path (value, infofile, line_number);
+ if (!expanded_value)
{
- char *p, envname[128];
-
- strcpy(envname, "$");
- /* FIXME: I'm not at all sure this should be CVSROOT_ENV as opposed
- to literal CVSROOT. The value we subsitute is the cvs root
- in use which is not the same thing as the environment variable
- CVSROOT_ENV. */
- strcat(envname, CVSROOT_ENV);
-
- cp = xstrdup(value);
- if ((p = strstr(cp, envname))) {
- if (strlen(line) + strlen(CVSroot) + 1 > MAXLINELEN) {
- /* FIXME: there is no reason for this arbitrary limit. */
- error(0, 0,
- "line %d in %s too long to expand $CVSROOT, ignored",
- line_number, infofile);
- continue;
- }
- if (p > cp) {
- strncpy(value, cp, p - cp);
- value[p - cp] = '\0';
- strcat(value, CVSroot);
- } else
- strcpy(value, CVSroot);
- strcat(value, p + strlen(envname));
- }
- free(cp);
+ continue;
}
/*
@@ -145,7 +125,11 @@ Parse_Info (infofile, repository, callproc, all)
/* save the default value so we have it later if we need it */
if (strcmp (exp, "DEFAULT") == 0)
{
- default_value = xstrdup (value);
+ /* Is it OK to silently ignore all but the last DEFAULT
+ expression? */
+ if (default_value != NULL)
+ free (default_value);
+ default_value = xstrdup (expanded_value);
continue;
}
@@ -157,7 +141,7 @@ Parse_Info (infofile, repository, callproc, all)
if (strcmp (exp, "ALL") == 0)
{
if (all)
- err += callproc (repository, value);
+ err += callproc (repository, expanded_value);
else
error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
line_number, infofile);
@@ -179,10 +163,13 @@ Parse_Info (infofile, repository, callproc, all)
continue; /* no match */
/* it did, so do the callback and note that we did one */
- err += callproc (repository, value);
+ err += callproc (repository, expanded_value);
callback_done = 1;
}
- (void) fclose (fp_info);
+ if (ferror (fp_info))
+ error (0, errno, "cannot read %s", infopath);
+ if (fclose (fp_info) < 0)
+ error (0, errno, "cannot close %s", infopath);
/* if we fell through and didn't callback at all, do the default */
if (callback_done == 0 && default_value != NULL)
@@ -191,6 +178,215 @@ Parse_Info (infofile, repository, callproc, all)
/* free up space if necessary */
if (default_value != NULL)
free (default_value);
+ if (expanded_value != NULL)
+ free (expanded_value);
+ free (infopath);
+ if (line != NULL)
+ free (line);
return (err);
}
+
+
+/* Parse the CVS config file. The syntax right now is a bit ad hoc
+ but tries to draw on the best or more common features of the other
+ *info files and various unix (or non-unix) config file syntaxes.
+ Lines starting with # are comments. Settings are lines of the form
+ KEYWORD=VALUE. There is currently no way to have a multi-line
+ VALUE (would be nice if there was, probably).
+
+ CVSROOT is the $CVSROOT directory (CVSroot_directory might not be
+ set yet).
+
+ Returns 0 for success, negative value for failure. Call
+ error(0, ...) on errors in addition to the return value. */
+int
+parse_config (cvsroot)
+ char *cvsroot;
+{
+ char *infopath;
+ FILE *fp_info;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ size_t len;
+ char *p;
+ /* FIXME-reentrancy: If we do a multi-threaded server, this would need
+ to go to the per-connection data structures. */
+ static int parsed = 0;
+
+ /* Authentication code and serve_root might both want to call us.
+ Let this happen smoothly. */
+ if (parsed)
+ return 0;
+ parsed = 1;
+
+ infopath = malloc (strlen (cvsroot)
+ + sizeof (CVSROOTADM_CONFIG)
+ + sizeof (CVSROOTADM)
+ + 10);
+ if (infopath == NULL)
+ {
+ error (0, 0, "out of memory; cannot allocate infopath");
+ goto error_return;
+ }
+
+ strcpy (infopath, cvsroot);
+ strcat (infopath, "/");
+ strcat (infopath, CVSROOTADM);
+ strcat (infopath, "/");
+ strcat (infopath, CVSROOTADM_CONFIG);
+
+ fp_info = CVS_FOPEN (infopath, "r");
+ if (fp_info == NULL)
+ {
+ /* If no file, don't do anything special. */
+ if (!existence_error (errno))
+ {
+ /* Just a warning message; doesn't affect return
+ value, currently at least. */
+ error (0, errno, "cannot open %s", infopath);
+ }
+ free (infopath);
+ return 0;
+ }
+
+ while (getline (&line, &line_allocated, fp_info) >= 0)
+ {
+ /* Skip comments. */
+ if (line[0] == '#')
+ continue;
+
+ /* At least for the moment we don't skip whitespace at the start
+ of the line. Too picky? Maybe. But being insufficiently
+ picky leads to all sorts of confusion, and it is a lot easier
+ to start out picky and relax it than the other way around.
+
+ Is there any kind of written standard for the syntax of this
+ sort of config file? Anywhere in POSIX for example (I guess
+ makefiles are sort of close)? Red Hat Linux has a bunch of
+ these too (with some GUI tools which edit them)...
+
+ Along the same lines, we might want a table of keywords,
+ with various types (boolean, string, &c), as a mechanism
+ for making sure the syntax is consistent. Any good examples
+ to follow there (Apache?)? */
+
+ /* Strip the training newline. There will be one unless we
+ read a partial line without a newline, and then got end of
+ file (or error?). */
+
+ len = strlen (line) - 1;
+ if (line[len] == '\n')
+ line[len] = '\0';
+
+ /* Skip blank lines. */
+ if (line[0] == '\0')
+ continue;
+
+ /* The first '=' separates keyword from value. */
+ p = strchr (line, '=');
+ if (p == NULL)
+ {
+ /* Probably should be printing line number. */
+ error (0, 0, "syntax error in %s: line '%s' is missing '='",
+ infopath, line);
+ goto error_return;
+ }
+
+ *p++ = '\0';
+
+ if (strcmp (line, "RCSBIN") == 0)
+ {
+ /* This option used to specify the directory for RCS
+ executables. But since we don't run them any more,
+ this is a noop. Silently ignore it so that a
+ repository can work with either new or old CVS. */
+ ;
+ }
+ else if (strcmp (line, "SystemAuth") == 0)
+ {
+ if (strcmp (p, "no") == 0)
+#ifdef AUTH_SERVER_SUPPORT
+ system_auth = 0;
+#else
+ /* Still parse the syntax but ignore the
+ option. That way the same config file can
+ be used for local and server. */
+ ;
+#endif
+ else if (strcmp (p, "yes") == 0)
+#ifdef AUTH_SERVER_SUPPORT
+ system_auth = 1;
+#else
+ ;
+#endif
+ else
+ {
+ error (0, 0, "unrecognized value '%s' for SystemAuth", p);
+ goto error_return;
+ }
+ }
+ else if (strcmp (line, "tag") == 0) {
+ RCS_citag = strdup(p);
+ if (RCS_citag == NULL) {
+ error (0, 0, "%s: no memory for local tag '%s'",
+ infopath, p);
+ goto error_return;
+ }
+ }
+ else if (strcmp (line, "umask") == 0) {
+ cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777);
+ }
+ else if (strcmp (line, "dlimit") == 0) {
+#ifdef BSD
+#include <sys/resource.h>
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_DATA, &rl) != -1) {
+ rl.rlim_cur = atoi(p);
+ rl.rlim_cur *= 1024;
+
+ (void) setrlimit(RLIMIT_DATA, &rl);
+ }
+#endif /* BSD */
+ }
+ else
+ {
+ /* We may be dealing with a keyword which was added in a
+ subsequent version of CVS. In that case it is a good idea
+ to complain, as (1) the keyword might enable a behavior like
+ alternate locking behavior, in which it is dangerous and hard
+ to detect if some CVS's have it one way and others have it
+ the other way, (2) in general, having us not do what the user
+ had in mind when they put in the keyword violates the
+ principle of least surprise. Note that one corollary is
+ adding new keywords to your CVSROOT/config file is not
+ particularly recommended unless you are planning on using
+ the new features. */
+ error (0, 0, "%s: unrecognized keyword '%s'",
+ infopath, line);
+ goto error_return;
+ }
+ }
+ if (ferror (fp_info))
+ {
+ error (0, errno, "cannot read %s", infopath);
+ goto error_return;
+ }
+ if (fclose (fp_info) < 0)
+ {
+ error (0, errno, "cannot close %s", infopath);
+ goto error_return;
+ }
+ free (infopath);
+ if (line != NULL)
+ free (line);
+ return 0;
+
+ error_return:
+ if (infopath != NULL)
+ free (infopath);
+ if (line != NULL)
+ free (line);
+ return -1;
+}
diff --git a/gnu/usr.bin/cvs/src/server.c b/gnu/usr.bin/cvs/src/server.c
index 5cecbdfc066..b512845192f 100644
--- a/gnu/usr.bin/cvs/src/server.c
+++ b/gnu/usr.bin/cvs/src/server.c
@@ -621,7 +621,6 @@ Sorry, you don't have read/write access to the history file %s", path);
(void) putenv (env);
/* do not free env, as putenv has control of it */
#endif
- parseopts(CVSroot_directory);
}
static int max_dotdot_limit = 0;