diff options
Diffstat (limited to 'contrib/cvs/src/mkmodules.c')
-rw-r--r-- | contrib/cvs/src/mkmodules.c | 1054 |
1 files changed, 0 insertions, 1054 deletions
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c deleted file mode 100644 index 751d4c7..0000000 --- a/contrib/cvs/src/mkmodules.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions 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 kit. */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" -#include "history.h" -#include "savecwd.h" - -#ifndef DBLKSIZ -#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */ -#endif - -static int checkout_file PROTO((char *file, char *temp)); -static char *make_tempfile PROTO((void)); -static void rename_rcsfile PROTO((char *temp, char *real)); - -#ifndef MY_NDBM -static void rename_dbmfile PROTO((char *temp)); -static void write_dbmfile PROTO((char *temp)); -#endif /* !MY_NDBM */ - -/* 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", -#if 0 /* see comments in wrap_add in wrapper.c */ - "# 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", -#endif - "# 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 \"CVS notification\" %s\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", - "# -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=yes\n", - "\n", - "# Set `IgnoreUnknownConfigKeys' to `yes' to ignore unknown config\n", - "# keys which are supported in a future version of CVS.\n", - "# This option is intended to be useful as a transition for read-only\n", - "# mirror sites when sites may need to be updated later than the\n", - "# primary CVS repository.\n", - "#IgnoreUnknownConfigKeys=no\n", - "\n", - "# Put CVS lock files in this directory rather than directly in the repository.\n", - "#LockDir=/var/lock/cvs\n", - "\n", -#ifdef PRESERVE_PERMISSIONS_SUPPORT - "# Set `PreservePermissions' to `yes' to save file status information\n", - "# in the repository.\n", - "#PreservePermissions=no\n", - "\n", -#endif - "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n", - "# level of the new working directory when using the `cvs checkout'\n", - "# command.\n", - "#TopLevelAdmin=no\n", - "\n", - "# Set `LogHistory' to `all' or `" ALL_HISTORY_REC_TYPES "' to log all transactions to the\n", - "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n", - "#LogHistory=" ALL_HISTORY_REC_TYPES "\n", - "\n", - "# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n", - "# script to change the log message. Set it to `stat' to force CVS to verify\n", - "# that the file has changed before reading it (this can take up to an extra\n", - "# second per directory being committed, so it is not recommended for large\n", - "# repositories. Set it to `never' (the previous CVS behavior) to prevent\n", - "# verifymsg scripts from changing the log message.\n", - "#RereadLogAfterVerify=always\n", - NULL -}; - -static const struct admin_file filelist[] = { - {CVSROOTADM_LOGINFO, - "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", - rcsinfo_contents}, - {CVSROOTADM_EDITINFO, - "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", - commitinfo_contents}, - {CVSROOTADM_TAGINFO, - "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", - NULL}, - {CVSROOTADM_CHECKOUTLIST, - "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", - 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, 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 (noexec) - return 0; - - if (save_cwd (&cwd)) - error_exit (); - - if ( CVS_CHDIR (dir) < 0) - error (1, errno, "cannot chdir to %s", dir); - - /* - * First, do the work necessary to update the "modules" database. - */ - temp = make_tempfile (); - switch (checkout_file (CVSROOTADM_MODULES, temp)) - { - - case 0: /* everything ok */ -#ifdef MY_NDBM - /* open it, to generate any duplicate errors */ - if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL) - dbm_close (db); -#else - write_dbmfile (temp); - rename_dbmfile (temp); -#endif - rename_rcsfile (temp, CVSROOTADM_MODULES); - break; - - default: - error (0, 0, - "'cvs checkout' is less functional without a %s file", - CVSROOTADM_MODULES); - break; - } /* switch on checkout_file() */ - - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - - /* Checkout the files that need it in CVSROOT dir */ - for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) { - if (fileptr->errormsg == NULL) - continue; - temp = make_tempfile (); - if (checkout_file (fileptr->filename, temp) == 0) - rename_rcsfile (temp, fileptr->filename); -#if 0 - /* - * If there was some problem other than the file not existing, - * checkout_file already printed a real error message. If the - * file does not exist, it is harmless--it probably just means - * that the repository was created with an old version of CVS - * which didn't have so many files in CVSROOT. - */ - else if (fileptr->errormsg) - error (0, 0, fileptr->errormsg, fileptr->filename); -#endif - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - } - - fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r"); - if (fp) - { - /* - * File format: - * [<whitespace>]<filename>[<whitespace><error message>]<end-of-line> - * - * comment lines begin with '#' - */ - while (getline (&line, &line_allocated, fp) >= 0) - { - /* skip lines starting with # */ - if (line[0] == '#') - continue; - - if ((last = strrchr (line, '\n')) != NULL) - *last = '\0'; /* strip the newline */ - - /* Skip leading white space. */ - for (fname = line; - *fname && isspace ((unsigned char) *fname); - fname++) - ; - - /* Find end of filename. */ - for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++) - ; - *cp = '\0'; - - temp = make_tempfile (); - if (checkout_file (fname, temp) == 0) - { - rename_rcsfile (temp, fname); - } - else - { - /* Skip leading white space before the error message. */ - for (cp++; - cp < last && *cp && isspace ((unsigned char) *cp); - cp++) - ; - if (cp < last && *cp) - error (0, 0, "%s", cp); - } - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - } - 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); -} - -/* - * Yeah, I know, there are NFS race conditions here. - */ -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 = 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; -} - -/* Get a file. If the file does not exist, return 1 silently. If - there is an error, print a message and return 1 (FIXME: probably - not a very clean convention). On success, return 0. */ - -static int -checkout_file (file, temp) - char *file; - char *temp; -{ - char *rcs; - RCSNode *rcsnode; - int retcode = 0; - - if (noexec) - return 0; - - rcs = xmalloc (strlen (file) + 5); - strcpy (rcs, file); - strcat (rcs, RCSEXT); - if (!isfile (rcs)) - { - free (rcs); - return (1); - } - - rcsnode = RCS_parsercsfile (rcs); - if (!rcsnode) - { - /* Probably not necessary (?); RCS_parsercsfile already printed a - message. */ - error (0, 0, "Failed to parse `%s'.", rcs); - free (rcs); - return 1; - } - - retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp, - (RCSCHECKOUTPROC) NULL, (void *) NULL); - if (retcode != 0) - { - /* Probably not necessary (?); RCS_checkout already printed a - message. */ - error (0, 0, "failed to check out %s file", - file); - } - freercsnode (&rcsnode); - free (rcs); - return (retcode); -} - -#ifndef MY_NDBM - -static void -write_dbmfile (temp) - char *temp; -{ - char line[DBLKSIZ], value[DBLKSIZ]; - FILE *fp; - DBM *db; - char *cp, *vp; - datum key, val; - int len, cont, err = 0; - - fp = open_file (temp, "r"); - if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL) - error (1, errno, "cannot open dbm file %s for creation", temp); - for (cont = 0; fgets (line, sizeof (line), fp) != NULL;) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * Add the line to the value, at the end if this is a continuation - * line; otherwise at the beginning, but only after any trailing - * backslash is removed. - */ - vp = value; - if (cont) - vp += strlen (value); - - /* - * See if the line we read is a continuation line, and strip the - * backslash if so. - */ - len = strlen (line); - if (len > 0) - cp = &line[len - 1]; - else - cp = line; - if (*cp == '\\') - { - cont = 1; - *cp = '\0'; - } - else - { - cont = 0; - } - (void) strcpy (vp, line); - if (value[0] == '#') - continue; /* comment line */ - vp = value; - while (*vp && isspace ((unsigned char) *vp)) - vp++; - if (*vp == '\0') - continue; /* empty line */ - - /* - * If this was not a continuation line, add the entry to the database - */ - if (!cont) - { - key.dptr = vp; - while (*vp && !isspace ((unsigned char) *vp)) - vp++; - key.dsize = vp - key.dptr; - *vp++ = '\0'; /* NULL terminate the key */ - while (*vp && isspace ((unsigned char) *vp)) - vp++; /* skip whitespace to value */ - if (*vp == '\0') - { - error (0, 0, "warning: NULL value for key `%s'", key.dptr); - continue; - } - val.dptr = vp; - val.dsize = strlen (vp); - if (dbm_store (db, key, val, DBM_INSERT) == 1) - { - error (0, 0, "duplicate key found for `%s'", key.dptr); - err++; - } - } - } - dbm_close (db); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", temp); - if (err) - { - /* I think that the size of the buffer needed here is - just determined by sizeof (CVSROOTADM_MODULES), the - filenames created by make_tempfile, and other things that won't - overflow. */ - char dotdir[50], dotpag[50], dotdb[50]; - - (void) sprintf (dotdir, "%s.dir", temp); - (void) sprintf (dotpag, "%s.pag", temp); - (void) sprintf (dotdb, "%s.db", temp); - if (unlink_file (dotdir) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotdir); - if (unlink_file (dotpag) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotpag); - if (unlink_file (dotdb) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotdb); - error (1, 0, "DBM creation failed; correct above errors"); - } -} - -static void -rename_dbmfile (temp) - char *temp; -{ - /* I think that the size of the buffer needed here is - just determined by sizeof (CVSROOTADM_MODULES), the - filenames created by make_tempfile, and other things that won't - overflow. */ - char newdir[50], newpag[50], newdb[50]; - char dotdir[50], dotpag[50], dotdb[50]; - char bakdir[50], bakpag[50], bakdb[50]; - - int dir1_errno = 0, pag1_errno = 0, db1_errno = 0; - int dir2_errno = 0, pag2_errno = 0, db2_errno = 0; - int dir3_errno = 0, pag3_errno = 0, db3_errno = 0; - - (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES); - (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES); - (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES); - (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (newdir, "%s.dir", temp); - (void) sprintf (newpag, "%s.pag", temp); - (void) sprintf (newdb, "%s.db", temp); - - (void) chmod (newdir, 0666); - (void) chmod (newpag, 0666); - (void) chmod (newdb, 0666); - - /* don't mess with me */ - SIG_beginCrSect (); - - /* rm .#modules.dir .#modules.pag */ - if (unlink_file (bakdir) < 0) - dir1_errno = errno; - if (unlink_file (bakpag) < 0) - pag1_errno = errno; - if (unlink_file (bakdb) < 0) - db1_errno = errno; - - /* mv modules.dir .#modules.dir */ - if (CVS_RENAME (dotdir, bakdir) < 0) - dir2_errno = errno; - /* mv modules.pag .#modules.pag */ - if (CVS_RENAME (dotpag, bakpag) < 0) - pag2_errno = errno; - /* mv modules.db .#modules.db */ - if (CVS_RENAME (dotdb, bakdb) < 0) - db2_errno = errno; - - /* mv "temp".dir modules.dir */ - if (CVS_RENAME (newdir, dotdir) < 0) - dir3_errno = errno; - /* mv "temp".pag modules.pag */ - if (CVS_RENAME (newpag, dotpag) < 0) - pag3_errno = errno; - /* mv "temp".db modules.db */ - if (CVS_RENAME (newdb, dotdb) < 0) - db3_errno = errno; - - /* OK -- make my day */ - SIG_endCrSect (); - - /* I didn't want to call error() when we had signals blocked - (unnecessary?), but do it now. */ - if (dir1_errno && !existence_error (dir1_errno)) - error (0, dir1_errno, "cannot remove %s", bakdir); - if (pag1_errno && !existence_error (pag1_errno)) - error (0, pag1_errno, "cannot remove %s", bakpag); - if (db1_errno && !existence_error (db1_errno)) - error (0, db1_errno, "cannot remove %s", bakdb); - - if (dir2_errno && !existence_error (dir2_errno)) - error (0, dir2_errno, "cannot remove %s", bakdir); - if (pag2_errno && !existence_error (pag2_errno)) - error (0, pag2_errno, "cannot remove %s", bakpag); - if (db2_errno && !existence_error (db2_errno)) - error (0, db2_errno, "cannot remove %s", bakdb); - - if (dir3_errno && !existence_error (dir3_errno)) - error (0, dir3_errno, "cannot remove %s", bakdir); - if (pag3_errno && !existence_error (pag3_errno)) - error (0, pag3_errno, "cannot remove %s", bakpag); - if (db3_errno && !existence_error (db3_errno)) - error (0, db3_errno, "cannot remove %s", bakdb); -} - -#endif /* !MY_NDBM */ - -static void -rename_rcsfile (temp, real) - char *temp; - char *real; -{ - char *bak; - struct stat statbuf; - 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... */ - if (CVS_STAT (rcs, &statbuf) < 0 - && !existence_error (errno)) - error (0, errno, "cannot stat %s", rcs); - 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); - - /* rm .#loginfo */ - if (unlink_file (bak) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", bak); - - /* mv loginfo .#loginfo */ - if (CVS_RENAME (real, bak) < 0 - && !existence_error (errno)) - error (0, errno, "cannot rename %s to %s", real, bak); - - /* mv "temp" loginfo */ - if (CVS_RENAME (temp, real) < 0 - && !existence_error (errno)) - error (0, errno, "cannot rename %s to %s", temp, real); - - free (bak); -} - -/* - * Walk PATH backwards to the root directory looking for the root of a - * repository. - */ -static char * -in_repository (const char *path) -{ - char *cp = xstrdup (path); - - for (;;) - { - if (isdir (cp)) - { - int foundit; - char *adm = xmalloc (strlen(cp) + strlen(CVSROOTADM) + 2); - sprintf (adm, "%s/%s", cp, CVSROOTADM); - foundit = isdir (adm); - free (adm); - if (foundit) return cp; - } - - /* If last_component() returns the empty string, then cp either - * points at the system root or is the empty string itself. - */ - if (!*last_component (cp) || !strcmp (cp, ".") - || last_component(cp) == cp) - break; - - cp[strlen(cp) - strlen(last_component(cp)) - 1] = '\0'; - } - - return NULL; -} - - -const char *const init_usage[] = { - "Usage: %s %s\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -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 = 0; - - char *root_dir; - const struct admin_file *fileptr; - - assert (!server_active); - - umask (cvsumask); - - if (argc == -1 || argc > 1) - usage (init_usage); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - - ign_setup (); - send_init_command (); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - root_dir = in_repository (current_parsed_root->directory); - - if (root_dir && strcmp (root_dir, current_parsed_root->directory)) - error (1, 0, - "Cannot initialize repository under existing CVSROOT: `%s'", - root_dir); - free (root_dir); - - /* 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 (current_parsed_root->directory); - - adm = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2); - sprintf (adm, "%s/%s", current_parsed_root->directory, 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); - - /* Make Emptydir so it's there if we need it */ - mkdir_if_needed (CVSNULLREPOS); - - /* 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); - - /* Make the new history file world-writeable, since every CVS - user will need to be able to write to it. We use chmod() - because xchmod() is too shy. */ - chmod (info, 0666); - } - - /* Make an empty val-tags file to prevent problems creating it later. */ - strcpy (info, adm); - strcat (info, "/"); - strcat (info, CVSROOTADM_VALTAGS); - if (!isfile (info)) - { - FILE *fp; - - fp = open_file (info, "w"); - if (fclose (fp) < 0) - error (1, errno, "cannot close %s", info); - - /* Make the new val-tags file world-writeable, since every CVS - user will need to be able to write to it. We use chmod() - because xchmod() is too shy. */ - chmod (info, 0666); - } - - free (info); - free (info_v); - - mkmodules (adm); - - free (adm); - return err; -} |