summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/cvs/src
diff options
context:
space:
mode:
authortholo <tholo@openbsd.org>1997-02-21 06:54:35 +0000
committertholo <tholo@openbsd.org>1997-02-21 06:54:35 +0000
commitae5e8a9bc5efbe41ac6d96a58870257739c0284d (patch)
treed302b99e913addb809123539374b2a8da76eb01c /gnu/usr.bin/cvs/src
parentMissed files from new release from Cyclic Software (diff)
downloadwireguard-openbsd-ae5e8a9bc5efbe41ac6d96a58870257739c0284d.tar.xz
wireguard-openbsd-ae5e8a9bc5efbe41ac6d96a58870257739c0284d.zip
Integrate local changes
Diffstat (limited to 'gnu/usr.bin/cvs/src')
-rw-r--r--gnu/usr.bin/cvs/src/checkout.c171
-rw-r--r--gnu/usr.bin/cvs/src/commit.c332
-rw-r--r--gnu/usr.bin/cvs/src/cvs.h66
-rw-r--r--gnu/usr.bin/cvs/src/ignore.c14
-rw-r--r--gnu/usr.bin/cvs/src/lock.c273
-rw-r--r--gnu/usr.bin/cvs/src/main.c144
-rw-r--r--gnu/usr.bin/cvs/src/patch.c14
-rw-r--r--gnu/usr.bin/cvs/src/rcscmds.c10
-rw-r--r--gnu/usr.bin/cvs/src/server.c714
-rw-r--r--gnu/usr.bin/cvs/src/update.c135
10 files changed, 1280 insertions, 593 deletions
diff --git a/gnu/usr.bin/cvs/src/checkout.c b/gnu/usr.bin/cvs/src/checkout.c
index e876cd22bd2..c2b18c53df6 100644
--- a/gnu/usr.bin/cvs/src/checkout.c
+++ b/gnu/usr.bin/cvs/src/checkout.c
@@ -311,7 +311,7 @@ checkout (argc, argv)
if (expand_modules)
{
- client_send_expansions (local, where);
+ client_send_expansions (local, where, 1);
}
else
{
@@ -343,7 +343,7 @@ checkout (argc, argv)
*/
if (argc > 1 && where != NULL)
{
- char repository[PATH_MAX];
+ char *repository;
(void) CVS_MKDIR (where, 0777);
if ( CVS_CHDIR (where) < 0)
@@ -352,6 +352,7 @@ checkout (argc, argv)
where = (char *) NULL;
if (!isfile (CVSADM))
{
+ repository = xmalloc (strlen (CVSroot_directory) + 80);
(void) sprintf (repository, "%s/%s/%s", CVSroot_directory,
CVSROOTADM, CVSNULLREPOS);
if (!isfile (repository))
@@ -381,6 +382,7 @@ checkout (argc, argv)
#endif
}
}
+ free (repository);
}
/* If we will be calling history_write, work out the name to pass
@@ -433,12 +435,20 @@ checkout (argc, argv)
static int
safe_location ()
{
- char current[PATH_MAX];
+ char *current;
char hardpath[PATH_MAX+5];
size_t hardpath_len;
int x;
+ int retval;
+#ifdef HAVE_READLINK
+ /* FIXME-arbitrary limit: should be retrying this like xgetwd.
+ But how does readlink let us know that the buffer was too small?
+ (by returning sizeof hardpath - 1?). */
x = readlink(CVSroot_directory, hardpath, sizeof hardpath - 1);
+#else
+ x = -1;
+#endif
if (x == -1)
{
strcpy(hardpath, CVSroot_directory);
@@ -447,22 +457,26 @@ safe_location ()
{
hardpath[x] = '\0';
}
- getwd (current);
+ current = xgetwd ();
hardpath_len = strlen (hardpath);
- if (strncmp (current, hardpath, hardpath_len) == 0)
+ if (strlen (current) >= hardpath_len
+ && strncmp (current, hardpath, hardpath_len) == 0)
{
if (/* Current is a subdirectory of hardpath. */
current[hardpath_len] == '/'
/* Current is hardpath itself. */
|| current[hardpath_len] == '\0')
- return 0;
+ retval = 0;
else
/* It isn't a problem. For example, current is
"/foo/cvsroot-bar" and hardpath is "/foo/cvsroot". */
- return 1;
+ retval = 1;
}
- return (1);
+ else
+ retval = 1;
+ free (current);
+ return retval;
}
/*
@@ -486,8 +500,8 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
int which;
char *cp;
char *cp2;
- char repository[PATH_MAX];
- char xwhere[PATH_MAX];
+ char *repository;
+ char *xwhere = NULL;
char *oldupdate = NULL;
char *prepath;
char *realdirs;
@@ -503,6 +517,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
*/
/* set up the repository (maybe) for the bottom directory */
+ repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) + 5);
(void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
/* save the original value of preload_update_dir */
@@ -512,12 +527,14 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
/* fix up argv[] for the case of partial modules */
if (mfile != NULL)
{
- char file[PATH_MAX];
+ char *file;
/* if mfile is really a path, straighten it out first */
if ((cp = strrchr (mfile, '/')) != NULL)
{
*cp = 0;
+ repository = xrealloc (repository,
+ strlen (repository) + strlen (mfile) + 10);
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
@@ -534,9 +551,15 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
if (!shorten)
{
if (where != NULL)
+ {
+ xwhere = xmalloc (strlen (where) + strlen (mfile) + 5);
(void) sprintf (xwhere, "%s/%s", where, mfile);
+ }
else
+ {
+ xwhere = xmalloc (strlen (mwhere) + strlen (mfile) + 5);
(void) sprintf (xwhere, "%s/%s", mwhere, mfile);
+ }
where = xwhere;
}
else
@@ -551,6 +574,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
mfile = cp + 1;
}
+ file = xmalloc (strlen (repository) + strlen (mfile) + 5);
(void) sprintf (file, "%s/%s", repository, mfile);
if (isdir (file))
{
@@ -559,7 +583,8 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
* The portion of a module was a directory, so kludge up where to
* be the subdir, and fix up repository
*/
- (void) strcpy (repository, file);
+ free (repository);
+ repository = xstrdup (file);
/*
* At this point, if shorten is not enabled, we make where either
@@ -572,9 +597,15 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
if (!shorten)
{
if (where != NULL)
+ {
+ xwhere = xmalloc (strlen (where) + strlen (mfile) + 5);
(void) sprintf (xwhere, "%s/%s", where, mfile);
+ }
else
+ {
+ xwhere = xmalloc (strlen (mwhere) + strlen (mfile) + 5);
(void) sprintf (xwhere, "%s/%s", mwhere, mfile);
+ }
where = xwhere;
}
else if (where == NULL)
@@ -597,6 +628,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
if (where == NULL)
where = mwhere;
}
+ free (file);
}
/*
@@ -607,7 +639,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
{
if ((cp = strrchr (argv[0], '/')) != NULL)
{
- (void) strcpy (xwhere, cp + 1);
+ xwhere = xstrdup (cp + 1);
where = xwhere;
}
}
@@ -619,18 +651,18 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
where = mwhere;
else
{
- (void) strcpy (xwhere, argv[0]);
+ xwhere = xstrdup (argv[0]);
where = xwhere;
}
}
if (preload_update_dir != NULL)
{
- char tmp[PATH_MAX];
-
- (void) sprintf (tmp, "%s/%s", preload_update_dir, where);
- free (preload_update_dir);
- preload_update_dir = xstrdup (tmp);
+ preload_update_dir =
+ xrealloc (preload_update_dir,
+ strlen (preload_update_dir) + strlen (where) + 5);
+ strcat (preload_update_dir, "/");
+ strcat (preload_update_dir, where);
}
else
preload_update_dir = xstrdup (where);
@@ -675,9 +707,8 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
{
error (0, 0, "ignoring module %s", omodule);
free (prepath);
- free (preload_update_dir);
- preload_update_dir = oldupdate;
- return (1);
+ err = 1;
+ goto out;
}
/* clean up */
@@ -725,9 +756,8 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
repos, repository);
error (0, 0, "ignoring module %s", omodule);
free (repos);
- free (preload_update_dir);
- preload_update_dir = oldupdate;
- return (1);
+ err = 1;
+ goto out;
}
free (repos);
}
@@ -743,9 +773,8 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
if ( CVS_CHDIR (repository) < 0)
{
error (0, errno, "cannot chdir to %s", repository);
- free (preload_update_dir);
- preload_update_dir = oldupdate;
- return (1);
+ err = 1;
+ goto out;
}
which = W_REPOS;
if (tag != NULL && !tag_validated)
@@ -789,14 +818,15 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
if (strcmp (command_name, "export") != 0 && !pipeout)
history_write ('O', preload_update_dir, history_name, where,
repository);
+ else if (strcmp (command_name, "export") == 0 && !pipeout)
+ history_write ('E', preload_update_dir, tag ? tag : date, where,
+ repository);
err += do_update (0, (char **) NULL, options, tag, date,
force_tag_match, 0 /* !local */ ,
1 /* update -d */ , aflag, checkout_prune_dirs,
pipeout, which, join_rev1, join_rev2,
preload_update_dir);
- free (preload_update_dir);
- preload_update_dir = oldupdate;
- return (err);
+ goto out;
}
if (!pipeout)
@@ -851,8 +881,12 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
force_tag_match, local_specified, 1 /* update -d */,
aflag, checkout_prune_dirs, pipeout, which, join_rev1,
join_rev2, preload_update_dir);
+out:
free (preload_update_dir);
preload_update_dir = oldupdate;
+ if (xwhere != NULL)
+ free (xwhere);
+ free (repository);
return (err);
}
@@ -881,31 +915,58 @@ build_dirs_and_chdir (dir, prepath, realdir, sticky)
int sticky;
{
FILE *fp;
- char repository[PATH_MAX];
- char path[PATH_MAX];
- char path2[PATH_MAX];
+ char *path;
+ char *path2;
char *slash;
char *slash2;
char *cp;
char *cp2;
+ int retval = 0;
- (void) strcpy (path, dir);
- (void) strcpy (path2, realdir);
+ path = xstrdup (dir);
+ path2 = xstrdup (realdir);
for (cp = path, cp2 = path2;
(slash = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL;
cp = slash + 1, cp2 = slash2 + 1)
{
*slash = '\0';
*slash2 = '\0';
+ if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
+ {
+ char *repository;
+
+ repository = xmalloc (strlen (prepath) + strlen (path2) + 5);
+ (void) sprintf (repository, "%s/%s", prepath, path2);
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+ Create_Admin (".", path, repository, sticky ? (char *) NULL : tag,
+ sticky ? (char *) NULL : date);
+ if (!noexec)
+ {
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (path, repository);
+#endif
+ }
+ free (repository);
+ }
+ mkdir_if_needed (cp);
Subdir_Register ((List *) NULL, (char *) NULL, cp);
- (void) CVS_MKDIR (cp, 0777);
if ( CVS_CHDIR (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
- return (1);
+ retval = 1;
+ goto out;
}
if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
{
+ char *repository;
+
+ repository = xmalloc (strlen (prepath) + strlen (path2) + 5);
(void) sprintf (repository, "%s/%s", prepath, path2);
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
@@ -922,16 +983,44 @@ build_dirs_and_chdir (dir, prepath, realdir, sticky)
server_set_entstat (path, repository);
#endif
}
+ free (repository);
}
*slash = '/';
*slash2 = '/';
}
+ if (!isfile (CVSADM) && strcmp (command_name, "export") != 0)
+ {
+ char *repository;
+
+ repository = xmalloc (strlen (prepath) + strlen (path2) + 5);
+ (void) sprintf (repository, "%s/%s", prepath, path2);
+ /* I'm not sure whether this check is redundant. */
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+ Create_Admin (".", path, repository, sticky ? (char *) NULL : tag,
+ sticky ? (char *) NULL : date);
+ if (!noexec)
+ {
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (path, repository);
+#endif
+ }
+ free (repository);
+ }
+ mkdir_if_needed (cp);
Subdir_Register ((List *) NULL, (char *) NULL, cp);
- (void) CVS_MKDIR (cp, 0777);
if ( CVS_CHDIR (cp) < 0)
{
error (0, errno, "cannot chdir to %s", cp);
- return (1);
+ retval = 1;
+ goto out;
}
- return (0);
+out:
+ free (path);
+ free (path2);
+ return retval;
}
diff --git a/gnu/usr.bin/cvs/src/commit.c b/gnu/usr.bin/cvs/src/commit.c
index 5d9c804e9b3..308c726684c 100644
--- a/gnu/usr.bin/cvs/src/commit.c
+++ b/gnu/usr.bin/cvs/src/commit.c
@@ -54,7 +54,7 @@ static void fixbranch PROTO((RCSNode *, char *branch));
static void unlockrcs PROTO((RCSNode *rcs));
static void ci_delproc PROTO((Node *p));
static void masterlist_delproc PROTO((Node *p));
-static void locate_rcs PROTO((char *file, char *repository, char *rcs));
+static char *locate_rcs PROTO((char *file, char *repository));
struct commit_info
{
@@ -271,6 +271,7 @@ find_fileproc (callerdat, finfo)
data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
data->type = status;
data->tag = xstrdup (vers->tag);
+ data->rev_old = data->rev_new = NULL;
node->type = UPDATE;
node->delproc = update_delproc;
@@ -469,6 +470,11 @@ commit (argc, argv)
if (use_editor)
do_editor (".", &message, (char *)NULL, find_args.ulist);
+ /* Run the user-defined script to verify/check information in
+ *the log message
+ */
+ do_verify (message, (char *)NULL);
+
/* We always send some sort of message, even if empty. */
option_with_arg ("-m", message);
@@ -527,7 +533,7 @@ commit (argc, argv)
previous versions of client/server CVS, but it probably is a Good
Thing, or at least Not Such A Bad Thing. */
send_file_names (find_args.argc, find_args.argv, 0);
- send_files (find_args.argc, find_args.argv, local, 0);
+ send_files (find_args.argc, find_args.argv, local, 0, 0);
send_to_server ("ci\012", 0);
return get_responses_and_close ();
@@ -558,7 +564,7 @@ commit (argc, argv)
argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1);
if (err)
{
- lock_tree_cleanup ();
+ Lock_Cleanup ();
error (1, 0, "correct above errors first!");
}
@@ -574,7 +580,7 @@ commit (argc, argv)
/*
* Unlock all the dirs and clean up
*/
- lock_tree_cleanup ();
+ Lock_Cleanup ();
dellist (&mulist);
if (last_register_time)
@@ -591,25 +597,18 @@ commit (argc, argv)
return (err);
}
-/*
- * Check to see if a file is ok to commit and make sure all files are
- * up-to-date
- */
-/* ARGSUSED */
-static int
-check_fileproc (callerdat, finfo)
- void *callerdat;
+/* This routine determines the status of a given file and retrieves
+ the version information that is associated with that file. */
+
+static
+Ctype
+classify_file_internal (finfo, vers)
struct file_info *finfo;
+ Vers_TS **vers;
{
- Ctype status;
- char *xdir;
- Node *p;
- List *ulist, *cilist;
- Vers_TS *vers;
- struct commit_info *ci;
- struct logfile_info *li;
int save_noexec, save_quiet, save_really_quiet;
-
+ Ctype status;
+
save_noexec = noexec;
save_quiet = quiet;
save_really_quiet = really_quiet;
@@ -622,15 +621,15 @@ check_fileproc (callerdat, finfo)
if (numdots (tag) < 2)
{
status = Classify_File (finfo, (char *) NULL, (char *) NULL,
- (char *) NULL, 1, aflag, &vers, 0);
+ (char *) NULL, 1, aflag, vers, 0);
if (status == T_UPTODATE || status == T_MODIFIED ||
status == T_ADDED)
{
Ctype xstatus;
- freevers_ts (&vers);
+ freevers_ts (vers);
xstatus = Classify_File (finfo, tag, (char *) NULL,
- (char *) NULL, 1, aflag, &vers, 0);
+ (char *) NULL, 1, aflag, vers, 0);
if (xstatus == T_REMOVE_ENTRY)
status = T_MODIFIED;
else if (status == T_MODIFIED && xstatus == T_CONFLICT)
@@ -654,31 +653,54 @@ check_fileproc (callerdat, finfo)
*cp = '\0';
}
status = Classify_File (finfo, xtag, (char *) NULL,
- (char *) NULL, 1, aflag, &vers, 0);
+ (char *) NULL, 1, aflag, vers, 0);
if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
&& (cp = strrchr (xtag, '.')) != NULL)
{
/* pluck one more dot off the revision */
*cp = '\0';
- freevers_ts (&vers);
+ freevers_ts (vers);
status = Classify_File (finfo, xtag, (char *) NULL,
- (char *) NULL, 1, aflag, &vers, 0);
+ (char *) NULL, 1, aflag, vers, 0);
if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
status = T_MODIFIED;
}
/* now, muck with vers to make the tag correct */
- free (vers->tag);
- vers->tag = xstrdup (tag);
+ free ((*vers)->tag);
+ (*vers)->tag = xstrdup (tag);
free (xtag);
}
}
else
status = Classify_File (finfo, tag, (char *) NULL, (char *) NULL,
- 1, 0, &vers, 0);
+ 1, 0, vers, 0);
noexec = save_noexec;
quiet = save_quiet;
really_quiet = save_really_quiet;
+ return status;
+}
+
+/*
+ * Check to see if a file is ok to commit and make sure all files are
+ * up-to-date
+ */
+/* ARGSUSED */
+static int
+check_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
+{
+ Ctype status;
+ char *xdir;
+ Node *p;
+ List *ulist, *cilist;
+ Vers_TS *vers;
+ struct commit_info *ci;
+ struct logfile_info *li;
+
+ status = classify_file_internal (finfo, &vers);
+
/*
* If the force-commit option is enabled, and the file in question
* appears to be up-to-date, just make it look modified so that
@@ -768,22 +790,7 @@ check_fileproc (callerdat, finfo)
return (1);
}
- /*
- * If the timestamps differ, look for Conflict indicators
- * in the file to see if we should block the commit anyway
- */
- run_setup ("%s", GREP);
- run_arg (RCS_MERGE_PAT);
- run_arg (finfo->file);
- retcode = run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_REALLY);
-
- if (retcode == -1)
- {
- error (1, errno,
- "fork failed while examining conflict in `%s'",
- finfo->fullname);
- }
- else if (retcode == 0)
+ if (file_has_markers (finfo))
{
error (0, 0,
"file `%s' still contains conflict indicators",
@@ -805,7 +812,12 @@ check_fileproc (callerdat, finfo)
{
if (vers->tag == NULL)
{
- char rcs[PATH_MAX];
+ char *rcs;
+
+ rcs = xmalloc (strlen (finfo->repository)
+ + strlen (finfo->file)
+ + sizeof RCSEXT
+ + 5);
/* Don't look in the attic; if it exists there we
will move it back out in checkaddfile. */
@@ -817,8 +829,10 @@ check_fileproc (callerdat, finfo)
"cannot add file `%s' when RCS file `%s' already exists",
finfo->fullname, rcs);
freevers_ts (&vers);
+ free (rcs);
return (1);
}
+ free (rcs);
}
if (vers->tag && isdigit (*vers->tag) &&
numdots (vers->tag) > 1)
@@ -868,6 +882,8 @@ check_fileproc (callerdat, finfo)
xmalloc (sizeof (struct logfile_info)));
li->type = status;
li->tag = xstrdup (vers->tag);
+ li->rev_old = xstrdup (vers->vn_rcs);
+ li->rev_new = NULL;
p->data = (char *) li;
(void) addnode (ulist, p);
@@ -1017,7 +1033,7 @@ check_filesdoneproc (callerdat, err, repos, update_dir, entries)
* Do the work of committing a file
*/
static int maxrev;
-static char sbranch[PATH_MAX];
+static char *sbranch;
/* ARGSUSED */
static int
@@ -1049,11 +1065,13 @@ commit_fileproc (callerdat, finfo)
* with files as args from the command line. In that latter case, we
* need to get the commit message ourselves
*/
- if (use_editor && !got_message)
- {
+ if (!(got_message))
+ {
got_message = 1;
- do_editor (finfo->update_dir, &message, finfo->repository, ulist);
- }
+ if (use_editor)
+ do_editor (finfo->update_dir, &message, finfo->repository, ulist);
+ do_verify (message, finfo->repository);
+ }
p = findnode (cilist, finfo->file);
if (p == NULL)
@@ -1172,6 +1190,33 @@ out:
if (p)
delnode (p);
}
+ else
+ {
+ /* On success, retrieve the new version number of the file and
+ copy it into the log information (see logmsg.c
+ (logfile_write) for more details). We should only update
+ the version number for files that have been added or
+ modified but not removed. Why? classify_file_internal
+ will return the version number of a file even after it has
+ been removed from the archive, which is not the behavior we
+ want for our commitlog messages; we want the old version
+ number and then "NONE." */
+
+ if (ci->status != T_REMOVED)
+ {
+ p = findnode (ulist, finfo->file);
+ if (p)
+ {
+ Vers_TS *vers;
+ struct logfile_info *li;
+
+ (void) classify_file_internal (finfo, &vers);
+ li = (struct logfile_info *) p->data;
+ li->rev_new = xstrdup (vers->vn_rcs);
+ freevers_ts (&vers);
+ }
+ }
+ }
return (err);
}
@@ -1249,10 +1294,12 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
line[--line_length] = '\0';
repository = Name_Repository ((char *) NULL, update_dir);
run_setup ("%s %s", line, repository);
- (void) printf ("%s %s: Executing '", program_name,
- command_name);
+ cvs_output (program_name, 0);
+ cvs_output (" ", 1);
+ cvs_output (command_name, 0);
+ cvs_output (": Executing '", 0);
run_print (stdout);
- (void) printf ("'\n");
+ cvs_output ("'\n", 0);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
free (repository);
}
@@ -1309,13 +1356,12 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
error (0, 0, "Committing %s", update_dir);
/* get commit message */
+ real_repos = Name_Repository (dir, update_dir);
+ got_message = 1;
if (use_editor)
- {
- got_message = 1;
- real_repos = Name_Repository (dir, update_dir);
do_editor (update_dir, &message, real_repos, ulist);
- free (real_repos);
- }
+ do_verify (message, real_repos);
+ free (real_repos);
return (R_PROCESS);
}
@@ -1423,7 +1469,9 @@ remove_file (finfo, tag, message)
/* commit a new, dead revision. */
/* Print message indicating that file is going to be removed. */
- (void) printf ("Removing %s;\n", finfo->fullname);
+ cvs_output ("Removing ", 0);
+ cvs_output (finfo->fullname, 0);
+ cvs_output (";\n", 0);
rev = NULL;
lockflag = 1;
@@ -1543,10 +1591,12 @@ remove_file (finfo, tag, message)
}
/* Print message that file was removed. */
- (void) printf ("%s <-- %s\n", old_path, finfo->file);
- (void) printf ("new revision: delete; ");
- (void) printf ("previous revision: %s\n", prev_rev);
- (void) printf ("done\n");
+ cvs_output (old_path, 0);
+ cvs_output (" <-- ", 0);
+ cvs_output (finfo->file, 0);
+ cvs_output ("\nnew revision: delete; previous revision: ", 0);
+ cvs_output (prev_rev, 0);
+ cvs_output ("\ndone\n", 0);
free(prev_rev);
if (old_path != finfo->rcs->path)
@@ -1567,20 +1617,23 @@ finaladd (finfo, rev, tag, options)
char *options;
{
int ret;
- char tmp[PATH_MAX];
- char rcs[PATH_MAX];
+ char *rcs;
- locate_rcs (finfo->file, finfo->repository, rcs);
+ rcs = locate_rcs (finfo->file, finfo->repository);
ret = Checkin ('A', finfo, rcs, rev, tag, options, message);
if (ret == 0)
{
+ char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
+ + sizeof (CVSEXT_LOG) + 10);
(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
(void) unlink_file (tmp);
+ free (tmp);
}
else
fixaddfile (finfo->file, finfo->repository);
(void) time (&last_register_time);
+ free (rcs);
return (ret);
}
@@ -1608,10 +1661,10 @@ fixaddfile (file, repository)
char *repository;
{
RCSNode *rcsfile;
- char rcs[PATH_MAX];
+ char *rcs;
int save_really_quiet;
- locate_rcs (file, repository, rcs);
+ rcs = locate_rcs (file, repository);
save_really_quiet = really_quiet;
really_quiet = 1;
if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
@@ -1619,6 +1672,7 @@ fixaddfile (file, repository)
else
freercsnode (&rcsfile);
really_quiet = save_really_quiet;
+ free (rcs);
}
/*
@@ -1631,7 +1685,7 @@ fixbranch (rcs, branch)
{
int retcode;
- if (branch != NULL && branch[0] != '\0')
+ if (branch != NULL)
{
if ((retcode = RCS_setbranch (rcs, branch)) != 0)
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
@@ -1653,15 +1707,18 @@ checkaddfile (file, repository, tag, options, rcsnode)
char *options;
RCSNode **rcsnode;
{
- char rcs[PATH_MAX];
- char fname[PATH_MAX];
+ char *rcs;
+ char *fname;
mode_t omask;
int retcode = 0;
int newfile = 0;
RCSNode *rcsfile = NULL;
+ int retval;
if (tag)
{
+ rcs = xmalloc (strlen (repository) + strlen (file)
+ + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
(void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
if (! isreadable (rcs))
{
@@ -1675,59 +1732,85 @@ checkaddfile (file, repository, tag, options, rcsnode)
}
}
else
- locate_rcs (file, repository, rcs);
+ rcs = locate_rcs (file, repository);
- if (isreadable(rcs))
+ if (isreadable (rcs))
{
/* file has existed in the past. Prepare to resurrect. */
- char oldfile[PATH_MAX];
char *rev;
if ((rcsfile = *rcsnode) == NULL)
{
error (0, 0, "could not find parsed rcsfile %s", file);
- return (1);
+ retval = 1;
+ goto out;
}
if (tag == NULL)
{
+ char *oldfile;
+
/* we are adding on the trunk, so move the file out of the
Attic. */
- strcpy (oldfile, rcs);
+ oldfile = xstrdup (rcs);
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
- if (strcmp (oldfile, rcs) == 0
- || CVS_RENAME (oldfile, rcs) != 0
- || isreadable (oldfile)
+ if (strcmp (oldfile, rcs) == 0)
+ {
+ error (0, 0, "internal error: confused about attic for %s",
+ oldfile);
+ out1:
+ free (oldfile);
+ retval = 1;
+ goto out;
+ }
+ if (CVS_RENAME (oldfile, rcs) != 0)
+ {
+ error (0, errno, "failed to move `%s' out of the attic",
+ oldfile);
+ goto out1;
+ }
+ if (isreadable (oldfile)
|| !isreadable (rcs))
{
- error (0, 0, "failed to move `%s' out of the attic.",
- file);
- return (1);
+ error (0, 0, "\
+internal error: `%s' didn't move out of the attic",
+ oldfile);
+ goto out1;
}
+ free (oldfile);
free (rcsfile->path);
rcsfile->path = xstrdup (rcs);
}
rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
/* and lock it */
- if (lock_RCS (file, rcsfile, rev, repository)) {
+ if (lock_RCS (file, rcsfile, rev, repository))
+ {
error (0, 0, "cannot lock `%s'.", rcs);
- free (rev);
- return (1);
+ if (rev != NULL)
+ free (rev);
+ retval = 1;
+ goto out;
}
- free (rev);
- } else {
+ if (rev != NULL)
+ free (rev);
+ }
+ else
+ {
/* this is the first time we have ever seen this file; create
an rcs file. */
run_setup ("%s%s -x,v/ -i", Rcsbin, RCS);
+ fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ + sizeof (CVSEXT_LOG) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
/* If the file does not exist, no big deal. In particular, the
server does not (yet at least) create CVSEXT_LOG files. */
if (isfile (fname))
run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ free (fname);
/* Set RCS keyword expansion options. */
if (options && options[0] == '-' && options[1] == 'k')
@@ -1737,7 +1820,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"could not create %s", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
newfile = 1;
}
@@ -1749,6 +1833,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
char *tmp;
/* move the new file out of the way. */
+ fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ + sizeof (CVSPREFIX) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
rename_file (file, fname);
copy_file (DEVNULL, file);
@@ -1764,18 +1850,21 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"could not create initial dead revision %s", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
/* put the new file back where it was */
rename_file (fname, file);
+ free (fname);
assert (rcsfile == NULL);
rcsfile = RCS_parse (file, repository);
if (rcsfile == NULL)
{
error (0, 0, "could not read %s", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
if (rcsnode != NULL)
{
@@ -1784,9 +1873,11 @@ checkaddfile (file, repository, tag, options, rcsnode)
}
/* and lock it once again. */
- if (lock_RCS (file, rcsfile, NULL, repository)) {
+ if (lock_RCS (file, rcsfile, NULL, repository))
+ {
error (0, 0, "cannot lock `%s'.", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
}
@@ -1805,16 +1896,18 @@ checkaddfile (file, repository, tag, options, rcsnode)
if (rcsfile == NULL)
{
error (0, 0, "could not read %s", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
}
}
- if (!RCS_nodeisbranch (rcsfile, tag)) {
+ if (!RCS_nodeisbranch (rcsfile, tag))
+ {
/* branch does not exist. Stub it. */
char *head;
char *magicrev;
-
+
head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
magicrev = RCS_magicrev (rcsfile, head);
@@ -1827,15 +1920,18 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
"could not stub branch %s for %s", tag, rcs);
- return (1);
+ retval = 1;
+ goto out;
}
}
else
{
/* lock the branch. (stubbed branches need not be locked.) */
- if (lock_RCS (file, rcsfile, NULL, repository)) {
+ if (lock_RCS (file, rcsfile, NULL, repository))
+ {
error (0, 0, "cannot lock `%s'.", rcs);
- return (1);
+ retval = 1;
+ goto out;
}
}
@@ -1849,7 +1945,11 @@ checkaddfile (file, repository, tag, options, rcsnode)
fileattr_newfile (file);
fix_rcs_modes (rcs, file);
- return (0);
+ retval = 0;
+
+ out:
+ free (rcs);
+ return retval;
}
/*
@@ -1900,13 +2000,14 @@ lock_RCS (user, rcs, rev, repository)
if (err == 0)
{
+ if (sbranch != NULL)
+ free (sbranch);
if (branch)
{
- (void) strcpy (sbranch, branch);
- free (branch);
+ sbranch = branch;
}
else
- sbranch[0] = '\0';
+ sbranch = NULL;
return (0);
}
@@ -1950,6 +2051,10 @@ update_delproc (p)
li = (struct logfile_info *) p->data;
if (li->tag)
free (li->tag);
+ if (li->rev_old)
+ free (li->rev_old);
+ if (li->rev_new)
+ free (li->rev_new);
free (li);
}
@@ -1987,15 +2092,23 @@ masterlist_delproc (p)
free (ml);
}
-/*
- * Find an RCS file in the repository.
- */
-static void
-locate_rcs (file, repository, rcs)
+/* Find an RCS file in the repository. Most parts of CVS will want to
+ rely instead on RCS_parse which performs a similar operation and is
+ called by recurse.c which then puts the result in useful places
+ like the rcs field of struct file_info.
+
+ REPOSITORY is the repository (including the directory) and FILE is
+ the filename within that directory (without RCSEXT). Returns a
+ newly-malloc'd array containing the absolute pathname of the RCS
+ file that was found. */
+static char *
+locate_rcs (file, repository)
char *file;
char *repository;
- char *rcs;
{
+ char *rcs;
+
+ rcs = xmalloc (strlen (repository) + strlen (file) + sizeof (RCSEXT) + 10);
(void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
if (!isreadable (rcs))
{
@@ -2003,4 +2116,5 @@ locate_rcs (file, repository, rcs)
if (!isreadable (rcs))
(void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
}
+ return rcs;
}
diff --git a/gnu/usr.bin/cvs/src/cvs.h b/gnu/usr.bin/cvs/src/cvs.h
index dd96dd063a3..1d48096bdf9 100644
--- a/gnu/usr.bin/cvs/src/cvs.h
+++ b/gnu/usr.bin/cvs/src/cvs.h
@@ -1,5 +1,3 @@
-/* $CVSid: @(#)cvs.h 1.86 94/10/22 $ */
-
/*
* basic information used in all source files
*
@@ -170,6 +168,7 @@ extern int errno;
#define CVSROOTADM_COMMITINFO "commitinfo"
#define CVSROOTADM_TAGINFO "taginfo"
#define CVSROOTADM_EDITINFO "editinfo"
+#define CVSROOTADM_VERIFYMSG "verifymsg"
#define CVSROOTADM_HISTORY "history"
#define CVSROOTADM_VALTAGS "val-tags"
#define CVSROOTADM_IGNORE "cvsignore"
@@ -177,6 +176,9 @@ extern int errno;
#define CVSROOTADM_WRAPPER "cvswrappers"
#define CVSROOTADM_NOTIFY "notify"
#define CVSROOTADM_USERS "users"
+#define CVSROOTADM_READERS "readers"
+#define CVSROOTADM_WRITERS "writers"
+#define CVSROOTADM_PASSWD "passwd"
#define CVSROOTADM_OPTIONS "options"
#define CVSNULLREPOS "Emptydir" /* an empty directory */
@@ -199,8 +201,21 @@ extern int errno;
#define CVSDOTIGNORE ".cvsignore"
#define CVSDOTWRAPPER ".cvswrappers"
+/* Command attributes -- see function lookup_command_attribute(). */
+#define CVS_CMD_IGNORE_ADMROOT 1
+#define CVS_CMD_USES_WORK_DIR 2
+#define CVS_CMD_MODIFIES_REPOSITORY 4
+
/* miscellaneous CVS defines */
+
+/* This is the string which is at the start of the non-log-message lines
+ that we put up for the user when they edit the log message. */
#define CVSEDITPREFIX "CVS: "
+/* Number of characters in CVSEDITPREFIX to compare when deciding to strip
+ off those lines. We don't check for the space, to accomodate users who
+ have editors which strip trailing spaces. */
+#define CVSEDITPREFIXLEN 4
+
#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */
#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */
#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */
@@ -361,6 +376,12 @@ extern int noexec; /* Don't modify disk anywhere */
extern int readonlyfs; /* fail on all write locks; succeed all read locks */
extern int logoff; /* Don't write history entry */
+#ifdef AUTH_SERVER_SUPPORT
+extern char *Pserver_Repos; /* used to check that same repos is
+ transmitted in pserver auth and in
+ CVS protocol. */
+#endif /* AUTH_SERVER_SUPPORT */
+
extern char hostname[];
/* Externs that are included directly in the CVS sources */
@@ -411,10 +432,8 @@ char *xstrdup PROTO((const char *str));
void strip_trailing_newlines PROTO((char *str));
typedef int (*CALLPROC) PROTO((char *repository, char *value));
int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all));
-int Reader_Lock PROTO((char *xrepository));
typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(());
int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup));
-int Writer_Lock PROTO((List * list));
int isdir PROTO((const char *file));
int isfile PROTO((const char *file));
int islink PROTO((const char *file));
@@ -439,15 +458,17 @@ time_t get_date PROTO((char *date, struct timeb *now));
void Create_Admin PROTO((char *dir, char *update_dir,
char *repository, char *tag, char *date));
+/* Locking subsystem (implemented in lock.c). */
+
+int Reader_Lock PROTO((char *xrepository));
void Lock_Cleanup PROTO((void));
/* Writelock an entire subtree, well the part specified by ARGC, ARGV, LOCAL,
and AFLAG, anyway. */
void lock_tree_for_write PROTO ((int argc, char **argv, int local, int aflag));
-/* Remove locks set by lock_tree_for_write. Currently removes readlocks
- too. */
-void lock_tree_cleanup PROTO ((void));
+/* See lock.c for description. */
+extern void lock_dir_for_write PROTO ((char *));
void ParseTag PROTO((char **tagp, char **datep));
void Scratch_Entry PROTO((List * list, char *fname));
@@ -456,7 +477,6 @@ void cat_module PROTO((int status));
void check_entries PROTO((char *dir));
void close_module PROTO((DBM * db));
void copy_file PROTO((const char *from, const char *to));
-void (*error_set_cleanup PROTO((void (*) (void)))) PROTO ((void));
void fperror PROTO((FILE * fp, int status, int errnum, char *message,...));
void free_names PROTO((int *pargc, char *argv[]));
@@ -488,7 +508,6 @@ void rename_file PROTO((const char *from, const char *to));
extern void expand_wild PROTO ((int argc, char **argv,
int *pargc, char ***pargv));
-void strip_path PROTO((char *path));
void strip_trailing_slashes PROTO((char *path));
void update_delproc PROTO((Node * p));
void usage PROTO((const char *const *cpp));
@@ -503,6 +522,8 @@ void Update_Logfile PROTO((char *repository, char *xmessage, FILE * xlogfp,
void do_editor PROTO((char *dir, char **messagep,
char *repository, List * changes));
+void do_verify PROTO((char *message, char *repository));
+
typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
char *mwhere, char *mfile, int horten, int local_specified,
char *omodule, char *msg));
@@ -565,6 +586,7 @@ void SIG_endCrSect PROTO((void));
void read_cvsrc PROTO((int *argc, char ***argv, char *cmdname));
char *make_message_rcslegal PROTO((char *message));
+extern int file_has_markers PROTO ((struct file_info *));
/* flags for run_exec(), the fast system() for CVS */
#define RUN_NORMAL 0x0000 /* no special behaviour */
@@ -699,6 +721,10 @@ struct logfile_info
{
enum classify_type type;
char *tag;
+ char *rev_old; /* rev number before a commit/modify,
+ NULL for add or import */
+ char *rev_new; /* rev number after a commit/modify,
+ add, or import, NULL for remove */
};
/* Wrappers. */
@@ -736,6 +762,25 @@ int unedit PROTO ((int argc, char **argv));
int editors PROTO ((int argc, char **argv));
int watchers PROTO ((int argc, char **argv));
extern int annotate PROTO ((int argc, char **argv));
+extern int add PROTO ((int argc, char **argv));
+extern int admin PROTO ((int argc, char **argv));
+extern int checkout PROTO ((int argc, char **argv));
+extern int commit PROTO ((int argc, char **argv));
+extern int diff PROTO ((int argc, char **argv));
+extern int history PROTO ((int argc, char **argv));
+extern int import PROTO ((int argc, char **argv));
+extern int cvslog PROTO ((int argc, char **argv));
+#ifdef AUTH_CLIENT_SUPPORT
+extern int login PROTO((int argc, char **argv));
+#endif /* AUTH_CLIENT_SUPPORT */
+extern int patch PROTO((int argc, char **argv));
+extern int release PROTO((int argc, char **argv));
+extern int cvsremove PROTO((int argc, char **argv));
+extern int rtag PROTO((int argc, char **argv));
+extern int status PROTO((int argc, char **argv));
+extern int cvstag PROTO((int argc, char **argv));
+
+extern unsigned long int lookup_command_attribute PROTO((char *));
#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT)
char *scramble PROTO ((char *str));
@@ -749,12 +794,11 @@ char *get_cvs_password PROTO((void));
extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *));
extern void tag_check_valid_join PROTO ((char *, int, char **, int, int,
char *));
-extern void tag_lockdir PROTO ((char *));
-extern void tag_unlockdir PROTO ((void));
extern void cvs_output PROTO ((const char *, size_t));
extern void cvs_outerr PROTO ((const char *, size_t));
extern void cvs_flusherr PROTO ((void));
+extern void cvs_flushout PROTO ((void));
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
#include "server.h"
diff --git a/gnu/usr.bin/cvs/src/ignore.c b/gnu/usr.bin/cvs/src/ignore.c
index 6fa9e89ea0b..1a839586f46 100644
--- a/gnu/usr.bin/cvs/src/ignore.c
+++ b/gnu/usr.bin/cvs/src/ignore.c
@@ -43,7 +43,6 @@ void
ign_setup ()
{
char *home_dir;
- char file[PATH_MAX];
char *tmp;
ign_inhibit_server = 0;
@@ -61,18 +60,23 @@ ign_setup ()
if (!client_active)
#endif
{
+ char *file = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_IGNORE) + 10);
/* Then add entries found in repository, if it exists */
(void) sprintf (file, "%s/%s/%s", CVSroot_directory,
CVSROOTADM, CVSROOTADM_IGNORE);
ign_add_file (file, 0);
+ free (file);
}
/* Then add entries found in home dir, (if user has one) and file exists */
home_dir = get_homedir ();
if (home_dir)
{
+ char *file = xmalloc (strlen (home_dir) + sizeof (CVSDOTIGNORE) + 10);
(void) sprintf (file, "%s/%s", home_dir, CVSDOTIGNORE);
ign_add_file (file, 0);
+ free (file);
}
/* Then add entries found in CVSIGNORE environment variable. */
@@ -92,6 +96,7 @@ ign_add_file (file, hold)
int hold;
{
FILE *fp;
+ /* FIXME: arbitrary limit. */
char line[1024];
/* restore the saved list (if any) */
@@ -424,11 +429,16 @@ ignore_files (ilist, entries, update_dir, proc)
{
if (! subdirs)
{
- char temp[PATH_MAX];
+ char *temp;
+ temp = xmalloc (strlen (file) + sizeof (CVSADM) + 10);
(void) sprintf (temp, "%s/%s", file, CVSADM);
if (isdir (temp))
+ {
+ free (temp);
continue;
+ }
+ free (temp);
}
}
#ifdef S_ISLNK
diff --git a/gnu/usr.bin/cvs/src/lock.c b/gnu/usr.bin/cvs/src/lock.c
index 81179bde66c..99772392d5b 100644
--- a/gnu/usr.bin/cvs/src/lock.c
+++ b/gnu/usr.bin/cvs/src/lock.c
@@ -74,39 +74,86 @@
#include "cvs.h"
+struct lock {
+ /* This is the directory in which we may have a lock named by the
+ readlock variable, a lock named by the writelock variable, and/or
+ a lock named CVSLCK. The storage is not allocated along with the
+ struct lock; it is allocated by the Reader_Lock caller or in the
+ case of writelocks, it is just a pointer to the storage allocated
+ for the ->key field. */
+ char *repository;
+ /* Do we have a lock named CVSLCK? */
+ int have_lckdir;
+ /* Note there is no way of knowing whether the readlock and writelock
+ exist. The code which sets the locks doesn't use SIG_beginCrSect
+ to set a flag like we do for CVSLCK. */
+};
+
+static void remove_locks PROTO((void));
static int readers_exist PROTO((char *repository));
-static int set_lock PROTO((char *repository, int will_wait));
-static void clear_lock PROTO((void));
+static int set_lock PROTO ((struct lock *lock, int will_wait));
+static void clear_lock PROTO ((struct lock *lock));
static void set_lockers_name PROTO((struct stat *statp));
static int set_writelock_proc PROTO((Node * p, void *closure));
static int unlock_proc PROTO((Node * p, void *closure));
-static int write_lock PROTO((char *repository));
-static void lock_simple_remove PROTO((char *repository));
+static int write_lock PROTO ((struct lock *lock));
+static void lock_simple_remove PROTO ((struct lock *lock));
static void lock_wait PROTO((char *repository));
static void lock_obtained PROTO((char *repository));
-static int Check_Owner PROTO((char *lockdir));
static char lockers_name[20];
-static char *repository;
static char readlock[PATH_MAX], writelock[PATH_MAX], masterlock[PATH_MAX];
-static int cleanup_lckdir;
static List *locklist;
#define L_OK 0 /* success */
#define L_ERROR 1 /* error condition */
#define L_LOCKED 2 /* lock owned by someone else */
+/* This is the (single) readlock which is set by Reader_Lock. The
+ repository field is NULL if there is no such lock. */
+static struct lock global_readlock;
+
+/* List of locks set by lock_tree_for_write. This is redundant
+ with locklist, sort of. */
+static List *lock_tree_list;
+
+/* If we set locks with lock_dir_for_write, then locked_dir contains
+ the malloc'd name of the repository directory which we have locked.
+ locked_list is the same thing packaged into a list and is redundant
+ with locklist the same way that lock_tree_list is. */
+static char *locked_dir;
+static List *locked_list;
+
/*
* Clean up all outstanding locks
*/
void
Lock_Cleanup ()
{
+ remove_locks ();
+
+ dellist (&lock_tree_list);
+
+ if (locked_dir != NULL)
+ {
+ dellist (&locked_list);
+ free (locked_dir);
+ locked_dir = NULL;
+ locked_list = NULL;
+ }
+}
+
+/*
+ * Remove locks without discarding the lock information
+ */
+static void
+remove_locks ()
+{
/* clean up simple locks (if any) */
- if (repository != NULL)
+ if (global_readlock.repository != NULL)
{
- lock_simple_remove (repository);
- repository = (char *) NULL;
+ lock_simple_remove (&global_readlock);
+ global_readlock.repository = NULL;
}
/* clean up multiple locks (if any) */
@@ -125,87 +172,51 @@ unlock_proc (p, closure)
Node *p;
void *closure;
{
- lock_simple_remove (p->key);
+ lock_simple_remove ((struct lock *)p->data);
return (0);
}
-/*
- * Remove the lock files (without complaining if they are not there),
- */
+/* Remove the lock files. */
static void
-lock_simple_remove (repository)
- char *repository;
+lock_simple_remove (lock)
+ struct lock *lock;
{
char tmp[PATH_MAX];
+ /* If readlock is set, the lock directory *might* have been created, but
+ since Reader_Lock doesn't use SIG_beginCrSect the way that set_lock
+ does, we don't know that. That is why we need to check for
+ existence_error here. */
if (readlock[0] != '\0')
{
- (void) sprintf (tmp, "%s/%s", repository, readlock);
+ (void) sprintf (tmp, "%s/%s", lock->repository, readlock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
}
+ /* If writelock is set, the lock directory *might* have been created, but
+ since write_lock doesn't use SIG_beginCrSect the way that set_lock
+ does, we don't know that. That is why we need to check for
+ existence_error here. */
if (writelock[0] != '\0')
{
- (void) sprintf (tmp, "%s/%s", repository, writelock);
+ (void) sprintf (tmp, "%s/%s", lock->repository, writelock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
}
- /*
- * Only remove the lock directory if it is ours, note that this does
- * lead to the limitation that one user ID should not be committing
- * files into the same Repository directory at the same time. Oh well.
- */
- if (writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir))
+ if (lock->have_lckdir)
{
- (void) sprintf (tmp, "%s/%s", repository, CVSLCK);
- if (Check_Owner(tmp))
- {
-#ifdef AFSCVS
- char rmuidlock[PATH_MAX];
- sprintf(rmuidlock, "rm -f %s/uidlock%d", tmp, geteuid() );
- system(rmuidlock);
-#endif
- (void) CVS_RMDIR (tmp);
- }
+ (void) sprintf (tmp, "%s/%s", lock->repository, CVSLCK);
+ SIG_beginCrSect ();
+ if (CVS_RMDIR (tmp) < 0)
+ error (0, errno, "failed to remove lock dir %s", tmp);
+ lock->have_lckdir = 0;
+ SIG_endCrSect ();
}
- cleanup_lckdir = 0;
}
/*
- * Check the owner of a lock. Returns 1 if we own it, 0 otherwise.
- */
-static int
-Check_Owner(lockdir)
- char *lockdir;
-{
- struct stat sb;
-
-#ifdef AFSCVS
- /* In the Andrew File System (AFS), user ids from stat don't match
- those from geteuid(). The AFSCVS code can deal with either AFS or
- non-AFS repositories; the non-AFSCVS code is faster. */
- char uidlock[PATH_MAX];
-
- /* Check if the uidlock is in the lock directory */
- sprintf(uidlock, "%s/uidlock%d", lockdir, geteuid() );
- if( stat(uidlock, &sb) != -1)
- return 1; /* The file exists, therefore we own the lock */
- else
- return 0; /* The file didn't exist or some other error.
- * Assume that we don't own it.
- */
-#else
- if ( CVS_STAT (lockdir, &sb) != -1 && sb.st_uid == geteuid ())
- return 1;
- else
- return 0;
-#endif
-} /* end Check_Owner() */
-
-
-/*
* Create a lock file for readers
*/
int
@@ -220,7 +231,7 @@ Reader_Lock (xrepository)
return (0);
/* we only do one directory at a time for read locks! */
- if (repository != NULL)
+ if (global_readlock.repository != NULL)
{
error (0, 0, "Reader_Lock called while read locks set - Help!");
return (1);
@@ -235,15 +246,18 @@ Reader_Lock (xrepository)
#endif
(long) getpid ());
- /* remember what we're locking (for lock_cleanup) */
- repository = xrepository;
+ /* remember what we're locking (for Lock_Cleanup) */
+ global_readlock.repository = xrepository;
/* get the lock dir for our own */
- if (set_lock (xrepository, 1) != L_OK)
+ if (set_lock (&global_readlock, 1) != L_OK)
{
error (0, 0, "failed to obtain dir lock in repository `%s'",
xrepository);
readlock[0] = '\0';
+ /* We don't set global_readlock.repository to NULL. I think this
+ only works because recurse.c will give a fatal error if we return
+ a nonzero value. */
return (1);
}
@@ -258,7 +272,7 @@ Reader_Lock (xrepository)
}
/* free the lock dir */
- clear_lock();
+ clear_lock (&global_readlock);
return (err);
}
@@ -268,7 +282,10 @@ Reader_Lock (xrepository)
*/
static char *lock_error_repos;
static int lock_error;
-int
+
+static int Writer_Lock PROTO ((List * list));
+
+static int
Writer_Lock (list)
List *list;
{
@@ -305,7 +322,7 @@ Writer_Lock (list)
return (1);
case L_LOCKED: /* Someone already had a lock */
- Lock_Cleanup (); /* clean up any locks we set */
+ remove_locks (); /* clean up any locks we set */
lock_wait (lock_error_repos); /* sleep a while and try again */
wait_repos = xstrdup (lock_error_repos);
continue;
@@ -342,7 +359,7 @@ set_writelock_proc (p, closure)
/* apply the write lock */
lock_error_repos = p->key;
- lock_error = write_lock (p->key);
+ lock_error = write_lock ((struct lock *)p->data);
return (0);
}
@@ -351,8 +368,8 @@ set_writelock_proc (p, closure)
* lock held by someone else or L_ERROR if an error occurred
*/
static int
-write_lock (repository)
- char *repository;
+write_lock (lock)
+ struct lock *lock;
{
int status;
FILE *fp;
@@ -368,16 +385,16 @@ write_lock (repository)
(long) getpid());
/* make sure the lock dir is ours (not necessarily unique to us!) */
- status = set_lock (repository, 0);
+ status = set_lock (lock, 0);
if (status == L_OK)
{
/* we now own a writer - make sure there are no readers */
- if (readers_exist (repository))
+ if (readers_exist (lock->repository))
{
/* clean up the lock dir if we created it */
if (status == L_OK)
{
- clear_lock();
+ clear_lock (lock);
}
/* indicate we failed due to read locks instead of error */
@@ -385,7 +402,7 @@ write_lock (repository)
}
/* write the write-lock file */
- (void) sprintf (tmp, "%s/%s", repository, writelock);
+ (void) sprintf (tmp, "%s/%s", lock->repository, writelock);
if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
int xerrno = errno;
@@ -396,12 +413,12 @@ write_lock (repository)
/* free the lock dir if we created it */
if (status == L_OK)
{
- clear_lock();
+ clear_lock (lock);
}
/* return the error */
error (0, xerrno, "cannot create write lock in repository `%s'",
- repository);
+ lock->repository);
return (L_ERROR);
}
return (L_OK);
@@ -509,8 +526,8 @@ set_lockers_name (statp)
* seconds old, just try to remove the directory.
*/
static int
-set_lock (repository, will_wait)
- char *repository;
+set_lock (lock, will_wait)
+ struct lock *lock;
int will_wait;
{
int waited;
@@ -520,7 +537,7 @@ set_lock (repository, will_wait)
time_t now;
#endif
- (void) sprintf (masterlock, "%s/%s", repository, CVSLCK);
+ (void) sprintf (masterlock, "%s/%s", lock->repository, CVSLCK);
/*
* Note that it is up to the callers of set_lock() to arrange for signal
@@ -528,7 +545,7 @@ set_lock (repository, will_wait)
* directory before they exit.
*/
waited = 0;
- cleanup_lckdir = 0;
+ lock->have_lckdir = 0;
for (;;)
{
int status = -1;
@@ -536,29 +553,11 @@ set_lock (repository, will_wait)
SIG_beginCrSect ();
if (CVS_MKDIR (masterlock, 0777) == 0)
{
-#ifdef AFSCVS
- char uidlock[PATH_MAX];
- FILE *fp;
-
- sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() );
- if ((fp = CVS_FOPEN (uidlock, "w+")) == NULL)
- {
- /* We failed to create the uidlock,
- so rm masterlock and leave */
- CVS_RMDIR (masterlock);
- SIG_endCrSect ();
- status = L_ERROR;
- goto out;
- }
-
- /* We successfully created the uid lock, so close the file */
- fclose(fp);
-#endif
- cleanup_lckdir = 1;
+ lock->have_lckdir = 1;
SIG_endCrSect ();
status = L_OK;
if (waited)
- lock_obtained (repository);
+ lock_obtained (lock->repository);
goto out;
}
SIG_endCrSect ();
@@ -571,7 +570,7 @@ set_lock (repository, will_wait)
{
error (0, errno,
"failed to create lock directory in repository `%s'",
- repository);
+ lock->repository);
return (L_ERROR);
}
@@ -596,12 +595,6 @@ set_lock (repository, will_wait)
(void) time (&now);
if (now >= (sb.st_ctime + CVSLCKAGE))
{
-#ifdef AFSCVS
- /* Remove the uidlock first */
- char rmuidlock[PATH_MAX];
- sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
- system(rmuidlock);
-#endif
if (CVS_RMDIR (masterlock) >= 0)
continue;
}
@@ -613,7 +606,7 @@ set_lock (repository, will_wait)
/* if he wasn't willing to wait, return an error */
if (!will_wait)
return (L_LOCKED);
- lock_wait (repository);
+ lock_wait (lock->repository);
waited = 1;
}
}
@@ -623,17 +616,14 @@ set_lock (repository, will_wait)
* clear_lock is never called except after a successful set_lock().
*/
static void
-clear_lock()
+clear_lock (lock)
+ struct lock *lock;
{
-#ifdef AFSCVS
- /* Remove the uidlock first */
- char rmuidlock[PATH_MAX];
- sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() );
- system(rmuidlock);
-#endif
+ SIG_beginCrSect ();
if (CVS_RMDIR (masterlock) < 0)
error (0, errno, "failed to remove lock dir `%s'", masterlock);
- cleanup_lckdir = 0;
+ lock->have_lckdir = 0;
+ SIG_endCrSect ();
}
/*
@@ -675,8 +665,6 @@ static int lock_filesdoneproc PROTO ((void *callerdat, int err,
List *entries));
static int fsortcmp PROTO((const Node * p, const Node * q));
-static List *lock_tree_list;
-
/*
* Create a list of repositories to lock
*/
@@ -694,6 +682,10 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
p = getnode ();
p->type = LOCK;
p->key = xstrdup (repository);
+ p->data = xmalloc (sizeof (struct lock));
+ ((struct lock *)p->data)->repository = p->key;
+ ((struct lock *)p->data)->have_lckdir = 0;
+
/* FIXME-KRP: this error condition should not simply be passed by. */
if (p->key == NULL || addnode (lock_tree_list, p) != 0)
freenode (p);
@@ -731,10 +723,33 @@ lock_tree_for_write (argc, argv, local, aflag)
if (Writer_Lock (lock_tree_list) != 0)
error (1, 0, "lock failed - giving up");
}
-
+
+/* Lock a single directory in REPOSITORY. It is OK to call this if
+ a lock has been set with lock_dir_for_write; the new lock will replace
+ the old one. If REPOSITORY is NULL, don't do anything. */
void
-lock_tree_cleanup ()
+lock_dir_for_write (repository)
+ char *repository;
{
- Lock_Cleanup ();
- dellist (&lock_tree_list);
+ if (repository != NULL
+ && (locked_dir == NULL
+ || strcmp (locked_dir, repository) != 0))
+ {
+ Node *node;
+
+ if (locked_dir != NULL)
+ Lock_Cleanup ();
+
+ locked_dir = xstrdup (repository);
+ locked_list = getlist ();
+ node = getnode ();
+ node->type = LOCK;
+ node->key = xstrdup (repository);
+ node->data = xmalloc (sizeof (struct lock));
+ ((struct lock *)node->data)->repository = node->key;
+ ((struct lock *)node->data)->have_lckdir = 0;
+
+ (void) addnode (locked_list, node);
+ Writer_Lock (locked_list);
+ }
}
diff --git a/gnu/usr.bin/cvs/src/main.c b/gnu/usr.bin/cvs/src/main.c
index d882632b666..1196ce4d105 100644
--- a/gnu/usr.bin/cvs/src/main.c
+++ b/gnu/usr.bin/cvs/src/main.c
@@ -52,27 +52,6 @@ char *CurDir;
char *Rcsbin = RCSBIN_DFLT;
char *Tmpdir = TMPDIR_DFLT;
char *Editor = EDITOR_DFLT;
-/*
- * The path found in CVS/Root must match $CVSROOT and/or 'cvs -d root'
- */
-int add PROTO((int argc, char **argv));
-int admin PROTO((int argc, char **argv));
-int checkout PROTO((int argc, char **argv));
-int commit PROTO((int argc, char **argv));
-int diff PROTO((int argc, char **argv));
-int history PROTO((int argc, char **argv));
-int import PROTO((int argc, char **argv));
-int cvslog PROTO((int argc, char **argv));
-#ifdef AUTH_CLIENT_SUPPORT
-int login PROTO((int argc, char **argv));
-#endif /* AUTH_CLIENT_SUPPORT */
-int patch PROTO((int argc, char **argv));
-int release PROTO((int argc, char **argv));
-int cvsremove PROTO((int argc, char **argv));
-int rtag PROTO((int argc, char **argv));
-int status PROTO((int argc, char **argv));
-int tag PROTO((int argc, char **argv));
-int update PROTO((int argc, char **argv));
static const struct cmd
{
@@ -100,7 +79,7 @@ static const struct cmd
char *nick1;
char *nick2;
-
+
int (*func) (); /* Function takes (argc, argv) arguments. */
} cmds[] =
@@ -132,7 +111,7 @@ static const struct cmd
{ "remove", "rm", "delete", cvsremove },
{ "status", "st", "stat", status },
{ "rtag", "rt", "rfreeze", rtag },
- { "tag", "ta", "freeze", tag },
+ { "tag", "ta", "freeze", cvstag },
{ "unedit", NULL, NULL, unedit },
{ "update", "up", "upd", update },
{ "watch", NULL, NULL, watch },
@@ -240,6 +219,50 @@ cmd_synonyms ()
return (const char * const*) synonyms; /* will never be freed */
}
+
+unsigned long int
+lookup_command_attribute (char *cmd_name)
+{
+ unsigned long int ret = 0;
+
+ if (strcmp (cmd_name, "import") != 0)
+ {
+ ret |= CVS_CMD_IGNORE_ADMROOT;
+ }
+
+
+ if ((strcmp (cmd_name, "checkout") != 0) &&
+ (strcmp (cmd_name, "login") != 0) &&
+ (strcmp (cmd_name, "rdiff") != 0) &&
+ (strcmp (cmd_name, "release") != 0) &&
+ (strcmp (cmd_name, "rtag") != 0))
+ {
+ ret |= CVS_CMD_USES_WORK_DIR;
+ }
+
+
+ /* The following commands do not modify the repository; we
+ conservatively assume that everything else does. Feel free to
+ add to this list if you are _certain_ something is safe. */
+ if ((strcmp (cmd_name, "checkout") != 0) &&
+ (strcmp (cmd_name, "diff") != 0) &&
+ (strcmp (cmd_name, "update") != 0) &&
+ (strcmp (cmd_name, "history") != 0) &&
+ (strcmp (cmd_name, "editors") != 0) &&
+ (strcmp (cmd_name, "export") != 0) &&
+ (strcmp (cmd_name, "history") != 0) &&
+ (strcmp (cmd_name, "log") != 0) &&
+ (strcmp (cmd_name, "noop") != 0) &&
+ (strcmp (cmd_name, "watchers") != 0) &&
+ (strcmp (cmd_name, "status") != 0))
+ {
+ ret |= CVS_CMD_MODIFIES_REPOSITORY;
+ }
+
+ return ret;
+}
+
+
static RETSIGTYPE
main_cleanup (sig)
int sig;
@@ -287,16 +310,6 @@ main_cleanup (sig)
#endif /* !DONT_USE_SIGNALS */
}
-static void
-error_cleanup PROTO((void))
-{
- Lock_Cleanup();
-#ifdef SERVER_SUPPORT
- if (server_active)
- server_cleanup (0);
-#endif
-}
-
int
main (argc, argv)
int argc;
@@ -325,14 +338,18 @@ main (argc, argv)
int option_index = 0;
int need_to_create_root = 0;
- error_set_cleanup (error_cleanup);
-
#ifdef SYSTEM_INITIALIZE
/* Hook for OS-specific behavior, for example socket subsystems on
NT and OS2 or dealing with windows and arguments on Mac. */
SYSTEM_INITIALIZE (&argc, &argv);
#endif
+#ifdef HAVE_TZSET
+ /* On systems that have tzset (which is almost all the ones I know
+ of), it's a good idea to call it. */
+ tzset ();
+#endif
+
/*
* Just save the last component of the path for error messages
*/
@@ -616,13 +633,13 @@ main (argc, argv)
ignores CVS directories and CVS/Root is likely to
specify a different repository than the one we are
importing to. */
-#if 0
- if (lookup_command_attribute (command_name) & CVS_CMD_IGNORE_ADMROOT)
- CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
-#else
- if (strcmp (command_name, "import") != 0)
+
+ if (lookup_command_attribute (command_name)
+ & CVS_CMD_IGNORE_ADMROOT)
+ {
CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
-#endif
+ }
+
if (CVSADM_Root != NULL)
{
if (CVSroot == NULL || !cvs_update_env)
@@ -651,16 +668,12 @@ main (argc, argv)
"cvs login" command. Ahh, the things one
discovers. */
-#if 0
- if (lookup_command_attribute (command_name) & CVS_CMD_USES_WORK_DIR)
-#else
- if ((strcmp (command_name, "checkout") != 0) &&
- (strcmp (command_name, "login") != 0) &&
- (strcmp (command_name, "rdiff") != 0) &&
- (strcmp (command_name, "release") != 0) &&
- (strcmp (command_name, "rtag") != 0))
-#endif
+ if (lookup_command_attribute (command_name)
+ & CVS_CMD_USES_WORK_DIR)
+ {
need_to_create_root = 1;
+ }
+
}
}
@@ -827,28 +840,13 @@ main (argc, argv)
gethostname(hostname, sizeof (hostname));
-#ifdef HAVE_SETVBUF
- /*
- * Make stdout line buffered, so 'tail -f' can monitor progress.
- * Patch creates too much output to monitor and it runs slowly.
- */
-# ifndef KLUDGE_FOR_WNT_TESTSUITE
-
- if (strcmp (cm->fullname, "patch"))
-# ifdef BUFSIZ /* traditional SysV chokes when size == 0 */
- (void) setvbuf (stdout, (char *) NULL, _IOLBF, BUFSIZ);
-# else
- (void) setvbuf (stdout, (char *) NULL, _IOLBF, 0);
-# endif
-
-# else /* KLUDGE_FOR_WNT_TESTSUITE */
-
- (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
- (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
-
-# endif /* KLUDGE_FOR_WNT_TESTSUITE */
-
-#endif /* HAVE_SETVBUF */
+#ifdef KLUDGE_FOR_WNT_TESTSUITE
+ /* Probably the need for this will go away at some point once
+ we call fflush enough places (e.g. fflush (stdout) in
+ cvs_outerr). */
+ (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
+ (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
+#endif /* KLUDGE_FOR_WNT_TESTSUITE */
if (use_cvsrc)
read_cvsrc (&argc, &argv, command_name);
@@ -910,7 +908,7 @@ usage (cpp)
(void) fprintf (stderr, *cpp++, program_name, command_name);
for (; *cpp; cpp++)
(void) fprintf (stderr, *cpp);
- exit (EXIT_FAILURE);
+ error_exit();
}
void
diff --git a/gnu/usr.bin/cvs/src/patch.c b/gnu/usr.bin/cvs/src/patch.c
index fd0fdd0295e..10e33b065c6 100644
--- a/gnu/usr.bin/cvs/src/patch.c
+++ b/gnu/usr.bin/cvs/src/patch.c
@@ -356,6 +356,11 @@ patch_fileproc (callerdat, finfo)
char *cp1, *cp2;
FILE *fp;
+ line1 = NULL;
+ line1_chars_allocated = 0;
+ line2 = NULL;
+ line2_chars_allocated = 0;
+
/* find the parsed rcs file */
if ((rcsfile = finfo->rcs) == NULL)
return (1);
@@ -449,7 +454,7 @@ patch_fileproc (callerdat, finfo)
if (vers_tag != NULL)
{
retcode = RCS_checkout (rcsfile, (char *) NULL, vers_tag,
- (char *) NULL, options, tmpfile1);
+ rev1, options, tmpfile1);
if (retcode != 0)
{
if (!really_quiet)
@@ -471,7 +476,7 @@ patch_fileproc (callerdat, finfo)
if (vers_head != NULL)
{
retcode = RCS_checkout (rcsfile, (char *) NULL, vers_head,
- (char *) NULL, options, tmpfile2);
+ rev2, options, tmpfile2);
if (retcode != 0)
{
if (!really_quiet)
@@ -488,11 +493,6 @@ patch_fileproc (callerdat, finfo)
run_arg (tmpfile1);
run_arg (tmpfile2);
- line1 = NULL;
- line1_chars_allocated = 0;
- line2 = NULL;
- line2_chars_allocated = 0;
-
switch (run_exec (RUN_TTY, tmpfile3, RUN_TTY, RUN_REALLY))
{
case -1: /* fork/wait failure */
diff --git a/gnu/usr.bin/cvs/src/rcscmds.c b/gnu/usr.bin/cvs/src/rcscmds.c
index 7b2c440d5fc..3bfa944c233 100644
--- a/gnu/usr.bin/cvs/src/rcscmds.c
+++ b/gnu/usr.bin/cvs/src/rcscmds.c
@@ -152,12 +152,10 @@ RCS_merge(path, options, rev1, rev2)
#ifndef HAVE_RCS5
if (status == 0)
{
- /* Run GREP to see if there appear to be conflicts in the file */
- run_setup ("%s", GREP);
- run_arg (RCS_MERGE_PAT);
- run_arg (path);
- status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0);
-
+ error (1, 0, "CVS no longer supports RCS versions older than RCS5");
+ /* This case needs to call file_has_markers to see if the file
+ contains conflict indicators. But is anyone using the !HAVE_RCS5
+ code any more? */
}
#endif
return status;
diff --git a/gnu/usr.bin/cvs/src/server.c b/gnu/usr.bin/cvs/src/server.c
index 20f973b2058..2490230c79a 100644
--- a/gnu/usr.bin/cvs/src/server.c
+++ b/gnu/usr.bin/cvs/src/server.c
@@ -1,3 +1,13 @@
+/* This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+
#include <assert.h>
#include "cvs.h"
#include "watch.h"
@@ -8,6 +18,10 @@
#ifdef SERVER_SUPPORT
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>
+#endif
+
#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS)
#include <sys/socket.h>
#endif
@@ -30,7 +44,17 @@ static Key_schedule sched;
#ifdef HAVE_SYS_BSDTYPES_H
#include <sys/bsdtypes.h>
#endif
-#include <sys/time.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
@@ -63,22 +87,20 @@ static Key_schedule sched;
#endif /* AUTH_SERVER_SUPPORT */
-/* Functions which the server calls. */
-int add PROTO((int argc, char **argv));
-int admin PROTO((int argc, char **argv));
-int checkout PROTO((int argc, char **argv));
-int commit PROTO((int argc, char **argv));
-int diff PROTO((int argc, char **argv));
-int history PROTO((int argc, char **argv));
-int import PROTO((int argc, char **argv));
-int cvslog PROTO((int argc, char **argv));
-int patch PROTO((int argc, char **argv));
-int release PROTO((int argc, char **argv));
-int cvsremove PROTO((int argc, char **argv));
-int rtag PROTO((int argc, char **argv));
-int status PROTO((int argc, char **argv));
-int tag PROTO((int argc, char **argv));
-int update PROTO((int argc, char **argv));
+#ifdef AUTH_SERVER_SUPPORT
+
+/* The cvs username sent by the client, which might or might not be
+ the same as the system username the server eventually switches to
+ run as. CVS_Username gets set iff password authentication is
+ successful. */
+static char *CVS_Username = NULL;
+
+/* Used to check that same repos is transmitted in pserver auth and in
+ later CVS protocol. Exported because root.c also uses. */
+char *Pserver_Repos = NULL;
+
+#endif /* AUTH_SERVER_SUPPORT */
+
/* 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
@@ -395,7 +417,9 @@ print_pending_error ()
/* Is an error pending? */
#define error_pending() (pending_error || pending_error_text)
-int
+static int supported_response PROTO ((char *));
+
+static int
supported_response (name)
char *name;
{
@@ -448,6 +472,16 @@ serve_valid_responses (arg)
cause deadlock, as noted in server_cleanup. */
buf_flush (buf_to_net, 1);
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
else if (rs->status == rs_optional)
@@ -455,8 +489,6 @@ serve_valid_responses (arg)
}
}
-static int use_dir_and_repos = 0;
-
static void
serve_root (arg)
char *arg;
@@ -656,7 +688,13 @@ static void
serve_repository (arg)
char *arg;
{
- dirswitch (arg + 1, arg);
+ pending_error_text = malloc (80);
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else
+ strcpy (pending_error_text,
+ "E Repository request is obsolete; aborted");
+ return;
}
static void
@@ -666,7 +704,6 @@ serve_directory (arg)
int status;
char *repos;
- use_dir_and_repos = 1;
status = buf_read_line (buf_from_net, &repos, (int *) NULL);
if (status == 0)
{
@@ -1016,56 +1053,11 @@ serve_modified (arg)
}
}
-#endif /* SERVER_SUPPORT */
-#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
-
-int use_unchanged = 0;
-
-#endif
-#ifdef SERVER_SUPPORT
-
static void
serve_enable_unchanged (arg)
char *arg;
{
- use_unchanged = 1;
-}
-
-static void
-serve_lost (arg)
- char *arg;
-{
- if (use_unchanged)
- {
- /* A missing file already indicates it is nonexistent. */
- return;
- }
- else
- {
- struct utimbuf ut;
- int fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0 || close (fd) < 0)
- {
- pending_error = errno;
- pending_error_text = malloc (80 + strlen(arg));
- sprintf(pending_error_text, "E cannot open %s", arg);
- return;
- }
- /*
- * Set the times to the beginning of the epoch to tell time_stamp()
- * that the file was lost.
- */
- ut.actime = 0;
- ut.modtime = 0;
- if (utime (arg, &ut) < 0)
- {
- pending_error = errno;
- pending_error_text = malloc (80 + strlen(arg));
- sprintf(pending_error_text, "E cannot utime %s", arg);
- return;
- }
- }
}
struct an_entry {
@@ -1079,43 +1071,36 @@ static void
serve_unchanged (arg)
char *arg;
{
+ struct an_entry *p;
+ char *name;
+ char *cp;
+ char *timefield;
+
if (error_pending ())
return;
- if (!use_unchanged)
- {
- /* A missing file already indicates it is unchanged. */
- return;
- }
- else
- {
- struct an_entry *p;
- char *name;
- char *cp;
- char *timefield;
- /* Rewrite entries file to have `=' in timestamp field. */
- for (p = entries; p != NULL; p = p->next)
+ /* Rewrite entries file to have `=' in timestamp field. */
+ for (p = entries; p != NULL; p = p->next)
+ {
+ name = p->entry + 1;
+ cp = strchr (name, '/');
+ if (cp != NULL
+ && strlen (arg) == cp - name
+ && strncmp (arg, name, cp - name) == 0)
{
- name = p->entry + 1;
- cp = strchr (name, '/');
- if (cp != NULL
- && strlen (arg) == cp - name
- && strncmp (arg, name, cp - name) == 0)
+ timefield = strchr (cp + 1, '/') + 1;
+ if (*timefield != '=')
{
- timefield = strchr (cp + 1, '/') + 1;
- if (*timefield != '=')
+ cp = timefield + strlen (timefield);
+ cp[1] = '\0';
+ while (cp > timefield)
{
- cp = timefield + strlen (timefield);
- cp[1] = '\0';
- while (cp > timefield)
- {
- *cp = cp[-1];
- --cp;
- }
- *timefield = '=';
+ *cp = cp[-1];
+ --cp;
}
- break;
+ *timefield = '=';
}
+ break;
}
}
}
@@ -1338,9 +1323,6 @@ server_notify ()
{
struct notify_note *p;
char *repos;
- List *list;
- Node *node;
- int status;
while (notify_list != NULL)
{
@@ -1351,14 +1333,7 @@ server_notify ()
}
repos = Name_Repository (NULL, NULL);
- /* Now writelock. */
- list = getlist ();
- node = getnode ();
- node->type = LOCK;
- node->key = xstrdup (repos);
- status = addnode (list, node);
- assert (status == 0);
- Writer_Lock (list);
+ lock_dir_for_write (repos);
fileattr_startdir (repos);
@@ -1366,7 +1341,6 @@ server_notify ()
notify_list->val, notify_list->watches, repos);
buf_output0 (buf_to_net, "Notified ");
- if (use_dir_and_repos)
{
char *dir = notify_list->dir + strlen (server_temp_dir) + 1;
if (dir[0] == '\0')
@@ -1391,9 +1365,7 @@ server_notify ()
fileattr_write ();
fileattr_free ();
- /* Remove the writelock. */
Lock_Cleanup ();
- dellist (&list);
}
/* The code used to call fflush (stdout) here, but that is no
@@ -1642,8 +1614,7 @@ error ENOMEM Virtual memory exhausted.\n";
/* If this gives an error, not much we could do. syslog() it? */
write (STDOUT_FILENO, msg, sizeof (msg) - 1);
- server_cleanup (0);
- exit (EXIT_FAILURE);
+ error_exit ();
}
static void
@@ -1653,6 +1624,164 @@ input_memory_error (buf)
outbuf_memory_error (buf);
}
+
+
+/* If command is legal, return 1.
+ * Else if command is illegal and croak_on_illegal is set, then die.
+ * Else just return 0 to indicate that command is illegal.
+ */
+static int
+check_command_legal_p (char *cmd_name)
+{
+ /* Right now, only pserver notices illegal commands -- namely,
+ * write attempts by a read-only user. Therefore, if CVS_Username
+ * is not set, this just returns 1, because CVS_Username unset
+ * means pserver is not active.
+ */
+#ifdef AUTH_SERVER_SUPPORT
+ if (CVS_Username == NULL)
+ return 1;
+
+ if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY)
+ {
+ /* This command has the potential to modify the repository, so
+ * we check if the user have permission to do that.
+ *
+ * (Only relevant for remote users -- local users can do
+ * whatever normal Unix file permissions allow them to do.)
+ *
+ * The decision method:
+ *
+ * If $CVSROOT/CVSADMROOT_READERS exists and user is listed
+ * in it, then read-only access for user.
+ *
+ * Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
+ * listed in it, then also read-only access for user.
+ *
+ * Else read-write access for user.
+ */
+
+ char *linebuf = NULL;
+ int num_red = 0;
+ size_t linebuf_len = 0;
+ char *fname;
+ size_t flen;
+ FILE *fp;
+ int found_it = 0;
+
+ /* else */
+ flen = strlen (CVSroot_directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_READERS)
+ + 3;
+
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
+ CVSROOTADM, CVSROOTADM_READERS);
+
+ fp = fopen (fname, "r");
+ free (fname);
+
+ if (fp == NULL)
+ goto do_writers;
+ else /* successfully opened readers file */
+ {
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Hmmm, is it worth importing my own readline
+ library into CVS? It takes care of chopping
+ leading and trailing whitespace, "#" comments, and
+ newlines automatically when so requested. Would
+ save some code here... -kff */
+
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ {
+ free (linebuf);
+ linebuf = NULL;
+ linebuf_len = 0;
+ goto handle_illegal;
+ }
+ /* else */
+ free (linebuf);
+ linebuf = NULL;
+ linebuf_len = 0;
+ }
+
+ /* If not listed specifically as a reader, then this user
+ has write access by default unless writers are also
+ specified in a file . */
+ fclose (fp);
+ goto do_writers;
+ }
+
+ do_writers:
+
+ flen = strlen (CVSroot_directory)
+ + strlen (CVSROOTADM)
+ + strlen (CVSROOTADM_WRITERS)
+ + 3;
+
+ fname = xmalloc (flen);
+ (void) sprintf (fname, "%s/%s/%s", CVSroot_directory,
+ CVSROOTADM, CVSROOTADM_WRITERS);
+
+ fp = fopen (fname, "r");
+ free (fname);
+
+ if (fp == NULL)
+ {
+ /* writers file does not exist, so everyone is a writer,
+ by default */
+ return 1;
+ }
+
+ /* else */
+
+ found_it = 0;
+ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ {
+ /* Chop newline by hand, for strcmp()'s sake. */
+ if (linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+ {
+ free (linebuf);
+ linebuf = NULL;
+ linebuf_len = 0;
+ found_it = 1;
+ break;
+ }
+ /* else */
+ free (linebuf);
+ linebuf = NULL;
+ linebuf_len = 0;
+ }
+
+ if (found_it)
+ {
+ fclose (fp);
+ return 1;
+ }
+ else /* writers file exists, but this user not listed in it */
+ {
+ handle_illegal:
+ fclose (fp);
+ return 0;
+ }
+ }
+#endif /* AUTH_SERVER_SUPPORT */
+
+ /* If ever reach end of this function, command must be legal. */
+ return 1;
+}
+
+
+
/* Execute COMMAND in a subprocess with the approriate funky things done. */
static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain;
@@ -1663,7 +1792,8 @@ static int flowcontrol_pipe[2];
#endif /* SERVER_FLOWCONTROL */
static void
-do_cvs_command (command)
+do_cvs_command (cmd_name, command)
+ char *cmd_name;
int (*command) PROTO((int argc, char **argv));
{
/*
@@ -1699,6 +1829,21 @@ do_cvs_command (command)
if (print_pending_error ())
goto free_args_and_return;
+ /* Global `command_name' is probably "server" right now -- only
+ serve_export() sets it to anything else. So we will use local
+ parameter `cmd_name' to determine if this command is legal for
+ this user. */
+ if (!check_command_legal_p (cmd_name))
+ {
+ buf_output0 (buf_to_net, "E ");
+ buf_output0 (buf_to_net, program_name);
+ buf_output0 (buf_to_net, " [server aborted]: \"");
+ buf_output0 (buf_to_net, cmd_name);
+ buf_output0 (buf_to_net, "\" requires write access to the repository\n\
+error \n");
+ goto free_args_and_return;
+ }
+
(void) server_notify ();
/*
@@ -1734,7 +1879,7 @@ do_cvs_command (command)
set_nonblock_fd (flowcontrol_pipe[1]);
#endif /* SERVER_FLOWCONTROL */
- dev_null_fd = CVS_OPEN ("/dev/null", O_RDONLY);
+ dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY);
if (dev_null_fd < 0)
{
print_error (errno);
@@ -2266,6 +2411,9 @@ server_pause_check()
}
#endif /* SERVER_FLOWCONTROL */
+/* This variable commented in server.h. */
+char *server_dir = NULL;
+
static void output_dir PROTO((char *, char *));
static void
@@ -2273,14 +2421,16 @@ output_dir (update_dir, repository)
char *update_dir;
char *repository;
{
- if (use_dir_and_repos)
+ if (server_dir != NULL)
{
- if (update_dir[0] == '\0')
- buf_output0 (protocol, ".");
- else
- buf_output0 (protocol, update_dir);
- buf_output0 (protocol, "/\n");
+ buf_output0 (protocol, server_dir);
+ buf_output0 (protocol, "/");
}
+ if (update_dir[0] == '\0')
+ buf_output0 (protocol, ".");
+ else
+ buf_output0 (protocol, update_dir);
+ buf_output0 (protocol, "/\n");
buf_output0 (protocol, repository);
buf_output0 (protocol, "/");
}
@@ -2426,11 +2576,12 @@ new_entries_line ()
entries_line = NULL;
}
+
static void
serve_ci (arg)
char *arg;
{
- do_cvs_command (commit);
+ do_cvs_command ("commit", commit);
}
static void
@@ -2525,91 +2676,91 @@ static void
serve_update (arg)
char *arg;
{
- do_cvs_command (update);
+ do_cvs_command ("update", update);
}
static void
serve_diff (arg)
char *arg;
{
- do_cvs_command (diff);
+ do_cvs_command ("diff", diff);
}
static void
serve_log (arg)
char *arg;
{
- do_cvs_command (cvslog);
+ do_cvs_command ("cvslog", cvslog);
}
static void
serve_add (arg)
char *arg;
{
- do_cvs_command (add);
+ do_cvs_command ("add", add);
}
static void
serve_remove (arg)
char *arg;
{
- do_cvs_command (cvsremove);
+ do_cvs_command ("cvsremove", cvsremove);
}
static void
serve_status (arg)
char *arg;
{
- do_cvs_command (status);
+ do_cvs_command ("status", status);
}
static void
serve_rdiff (arg)
char *arg;
{
- do_cvs_command (patch);
+ do_cvs_command ("patch", patch);
}
static void
serve_tag (arg)
char *arg;
{
- do_cvs_command (tag);
+ do_cvs_command ("cvstag", cvstag);
}
static void
serve_rtag (arg)
char *arg;
{
- do_cvs_command (rtag);
+ do_cvs_command ("rtag", rtag);
}
static void
serve_import (arg)
char *arg;
{
- do_cvs_command (import);
+ do_cvs_command ("import", import);
}
static void
serve_admin (arg)
char *arg;
{
- do_cvs_command (admin);
+ do_cvs_command ("admin", admin);
}
static void
serve_history (arg)
char *arg;
{
- do_cvs_command (history);
+ do_cvs_command ("history", history);
}
static void
serve_release (arg)
char *arg;
{
- do_cvs_command (release);
+ do_cvs_command ("release", release);
}
static void serve_watch_on PROTO ((char *));
@@ -2618,7 +2769,7 @@ static void
serve_watch_on (arg)
char *arg;
{
- do_cvs_command (watch_on);
+ do_cvs_command ("watch_on", watch_on);
}
static void serve_watch_off PROTO ((char *));
@@ -2627,7 +2778,7 @@ static void
serve_watch_off (arg)
char *arg;
{
- do_cvs_command (watch_off);
+ do_cvs_command ("watch_off", watch_off);
}
static void serve_watch_add PROTO ((char *));
@@ -2636,7 +2787,7 @@ static void
serve_watch_add (arg)
char *arg;
{
- do_cvs_command (watch_add);
+ do_cvs_command ("watch_add", watch_add);
}
static void serve_watch_remove PROTO ((char *));
@@ -2645,7 +2796,7 @@ static void
serve_watch_remove (arg)
char *arg;
{
- do_cvs_command (watch_remove);
+ do_cvs_command ("watch_remove", watch_remove);
}
static void serve_watchers PROTO ((char *));
@@ -2654,7 +2805,7 @@ static void
serve_watchers (arg)
char *arg;
{
- do_cvs_command (watchers);
+ do_cvs_command ("watchers", watchers);
}
static void serve_editors PROTO ((char *));
@@ -2663,7 +2814,7 @@ static void
serve_editors (arg)
char *arg;
{
- do_cvs_command (editors);
+ do_cvs_command ("editors", editors);
}
static int noop PROTO ((int, char **));
@@ -2682,7 +2833,7 @@ static void
serve_noop (arg)
char *arg;
{
- do_cvs_command (noop);
+ do_cvs_command ("noop", noop);
}
static void serve_init PROTO ((char *));
@@ -2693,7 +2844,7 @@ serve_init (arg)
{
set_local_cvsroot (arg);
- do_cvs_command (init);
+ do_cvs_command ("init", init);
}
static void serve_annotate PROTO ((char *));
@@ -2702,7 +2853,7 @@ static void
serve_annotate (arg)
char *arg;
{
- do_cvs_command (annotate);
+ do_cvs_command ("annotate", annotate);
}
static void
@@ -2751,7 +2902,15 @@ serve_co (arg)
}
free (tempdir);
}
- do_cvs_command (checkout);
+
+ /* Compensate for server_export()'s setting of command_name.
+ *
+ * [It probably doesn't matter if do_cvs_command() gets "export"
+ * or "checkout", but we ought to be accurate where possible.]
+ */
+ do_cvs_command ((strcmp (command_name, "export") == 0) ?
+ "export" : "checkout",
+ checkout);
}
static void
@@ -2871,9 +3030,8 @@ server_updated (finfo, vers, updated, file_info, checksum)
char *mode_string;
/* FIXME: When we check out files the umask of the server
- (set in .bashrc if rsh is in use, or set in main.c in
- the kerberos case, I think) affects what mode we send,
- and it shouldn't. */
+ (set in .bashrc if rsh is in use) affects what mode we
+ send, and it shouldn't. */
if (file_info != NULL)
mode_string = mode_to_string (file_info->st_mode);
else
@@ -3249,11 +3407,6 @@ serve_expand_modules (arg)
DBM *db;
err = 0;
- /*
- * FIXME: error handling is bogus; do_module can write to stdout and/or
- * stderr and we're not using do_cvs_command.
- */
-
server_expanding = 1;
db = open_module ();
for (i = 1; i < argument_count; i++)
@@ -3392,7 +3545,7 @@ struct request requests[] =
REQ_LINE("Valid-responses", serve_valid_responses, rq_essential),
REQ_LINE("valid-requests", serve_valid_requests, rq_essential),
REQ_LINE("Repository", serve_repository, rq_essential),
- REQ_LINE("Directory", serve_directory, rq_optional),
+ REQ_LINE("Directory", serve_directory, rq_essential),
REQ_LINE("Max-dotdot", serve_max_dotdot, rq_optional),
REQ_LINE("Static-directory", serve_static_directory, rq_optional),
REQ_LINE("Sticky", serve_sticky, rq_optional),
@@ -3400,9 +3553,13 @@ struct request requests[] =
REQ_LINE("Update-prog", serve_update_prog, rq_optional),
REQ_LINE("Entry", serve_entry, rq_essential),
REQ_LINE("Modified", serve_modified, rq_essential),
- REQ_LINE("Lost", serve_lost, rq_optional),
+
+ /* The client must send this request to interoperate with CVS 1.5
+ through 1.9 servers. The server must support it (although it can
+ be and is a noop) to interoperate with CVS 1.5 to 1.9 clients. */
REQ_LINE("UseUnchanged", serve_enable_unchanged, rq_enableme),
- REQ_LINE("Unchanged", serve_unchanged, rq_optional),
+
+ REQ_LINE("Unchanged", serve_unchanged, rq_essential),
REQ_LINE("Notify", serve_notify, rq_optional),
REQ_LINE("Questionable", serve_questionable, rq_optional),
REQ_LINE("Case", serve_case, rq_optional),
@@ -3685,6 +3842,17 @@ server (argc, argv)
{
printf ("E Fatal server error, aborting.\n\
error ENOMEM Virtual memory exhausted.\n");
+
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
putenv (env);
@@ -3717,6 +3885,8 @@ error ENOMEM Virtual memory exhausted.\n");
}
else
{
+ int status;
+
server_temp_dir = malloc (strlen (Tmpdir) + 80);
if (server_temp_dir == NULL)
{
@@ -3726,6 +3896,18 @@ error ENOMEM Virtual memory exhausted.\n");
*/
printf ("E Fatal server error, aborting.\n\
error ENOMEM Virtual memory exhausted.\n");
+
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket
+ subsystems on NT and OS2 or dealing with windows
+ and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
strcpy (server_temp_dir, Tmpdir);
@@ -3746,15 +3928,41 @@ error ENOMEM Virtual memory exhausted.\n");
sprintf (p, "%ld", (long) getpid ());
orig_server_temp_dir = server_temp_dir;
+
+ /* Create the temporary directory, and set the mode to
+ 700, to discourage random people from tampering with
+ it. */
+ status = mkdir_p (server_temp_dir);
+ if (status == EEXIST)
+ status = 0;
+#ifndef CHMOD_BROKEN
+ if (status == 0)
+ status = chmod (server_temp_dir, S_IRWXU);
+#endif
+ if (status != 0)
+ {
+ pending_error_text = "E can't create temporary directory";
+ pending_error = status;
+ }
}
}
+#ifdef SIGHUP
(void) SIG_register (SIGHUP, server_cleanup);
+#endif
+#ifdef SIGINT
(void) SIG_register (SIGINT, server_cleanup);
+#endif
+#ifdef SIGQUIT
(void) SIG_register (SIGQUIT, server_cleanup);
+#endif
+#ifdef SIGPIPE
(void) SIG_register (SIGPIPE, server_cleanup);
+#endif
+#ifdef SIGTERM
(void) SIG_register (SIGTERM, server_cleanup);
-
+#endif
+
/* Now initialize our argument vector (for arguments from the client). */
/* Small for testing. */
@@ -3769,6 +3977,17 @@ error ENOMEM Virtual memory exhausted.\n");
*/
printf ("E Fatal server error, aborting.\n\
error ENOMEM Virtual memory exhausted.\n");
+
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
@@ -3851,6 +4070,16 @@ switch_to_user (username)
{
printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", username);
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
@@ -3872,9 +4101,10 @@ error 0 %s: no such user\n", username);
#endif
setuid (pw->pw_uid);
- /* Inhibit access by randoms. Don't want people randomly
- changing our temporary tree before we check things in. */
- umask (077);
+ /* We don't want our umask to change file modes. The modes should
+ be set by the modes used in the repository, and by the umask of
+ the client. */
+ umask (0);
#if HAVE_PUTENV
/* Set LOGNAME and USER in the environment, in case they are
@@ -3903,6 +4133,12 @@ extern char *crypt PROTO((const char *, const char *));
* 0 means no entry found for this user.
* 1 means entry found and password matches.
* 2 means entry found, but password does not match.
+ *
+ * If success, host_user_ptr will be set to point at the system
+ * username (i.e., the "real" identity, which may or may not be the
+ * CVS username) of this user; caller may free this. Global
+ * CVS_Username will point at an allocated copy of cvs username (i.e.,
+ * the username argument below).
*/
static int
check_repository_password (username, password, repository, host_user_ptr)
@@ -3916,16 +4152,20 @@ check_repository_password (username, password, repository, host_user_ptr)
int found_it = 0;
int namelen;
+ /* We don't use CVSroot_directory because it hasn't been set yet
+ * -- our `repository' argument came from the authentication
+ * protocol, not the regular CVS protocol.
+ */
+
filename = xmalloc (strlen (repository)
+ 1
- + strlen ("CVSROOT")
+ + strlen (CVSROOTADM)
+ 1
- + strlen ("passwd")
+ + strlen (CVSROOTADM_PASSWD)
+ 1);
- strcpy (filename, repository);
- strcat (filename, "/CVSROOT");
- strcat (filename, "/passwd");
+ (void) sprintf (filename, "%s/%s/%s", repository,
+ CVSROOTADM, CVSROOTADM_PASSWD);
fp = CVS_FOPEN (filename, "r");
if (fp == NULL)
@@ -3956,16 +4196,27 @@ check_repository_password (username, password, repository, host_user_ptr)
/* If found_it != 0, then linebuf contains the information we need. */
if (found_it)
{
- char *found_password;
+ char *found_password, *host_user_tmp;
strtok (linebuf, ":");
found_password = strtok (NULL, ": \n");
- *host_user_ptr = strtok (NULL, ": \n");
- if (*host_user_ptr == NULL) *host_user_ptr = username;
+ host_user_tmp = strtok (NULL, ": \n");
+ if (host_user_tmp == NULL)
+ host_user_tmp = username;
+
if (strcmp (found_password, crypt (password, found_password)) == 0)
+ {
+ /* Give host_user_ptr permanent storage. */
+ *host_user_ptr = xmalloc (strlen (host_user_tmp) + 1);
+ strcpy (*host_user_ptr, host_user_tmp);
+
retval = 1;
+ }
else
- retval = 2;
+ {
+ *host_user_ptr = NULL;
+ retval = 2;
+ }
}
else
{
@@ -3985,7 +4236,7 @@ check_password (username, password, repository)
char *username, *password, *repository;
{
int rc;
- char *host_user;
+ char *host_user = NULL;
/* First we see if this user has a password in the CVS-specific
password file. If so, that's enough to authenticate with. If
@@ -3994,10 +4245,16 @@ check_password (username, password, repository)
rc = check_repository_password (username, password, repository,
&host_user);
+ if (rc == 2)
+ return NULL;
+
+ /* else */
+
if (rc == 1)
- return host_user;
- else if (rc == 2)
- return 0;
+ {
+ /* host_user already set by reference, so just return. */
+ goto handle_return;
+ }
else if (rc == 0)
{
/* No cvs password found, so try /etc/passwd. */
@@ -4025,23 +4282,56 @@ check_password (username, password, repository)
{
printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", username);
+
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
if (found_passwd && *found_passwd)
- return ((! strcmp (found_passwd, crypt (password, found_passwd)))
- ? username : NULL);
+ {
+ host_user = ((! strcmp (found_passwd,
+ crypt (password, found_passwd)))
+ ? username : NULL);
+ goto handle_return;
+ }
else if (password && *password)
- return username;
+ {
+ host_user = username;
+ goto handle_return;
+ }
else
- return NULL;
+ {
+ host_user = NULL;
+ goto handle_return;
+ }
}
else
{
/* Something strange happened. We don't know what it was, but
we certainly won't grant authorization. */
- return NULL;
+ host_user = NULL;
+ goto handle_return;
+ }
+
+handle_return:
+ if (host_user)
+ {
+ /* Set CVS_Username here, in allocated space.
+ It might or might not be the same as host_user. */
+ CVS_Username = xmalloc (strlen (username) + 1);
+ strcpy (CVS_Username, username);
}
+
+ return host_user;
}
/* Read username and password from client (i.e., stdin).
@@ -4152,12 +4442,35 @@ pserver_authenticate_connection ()
{
printf ("I HATE YOU\n");
fflush (stdout);
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
exit (EXIT_FAILURE);
}
/* Don't go any farther if we're just responding to "cvs login". */
if (verify_and_exit)
+ {
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
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);
/* Switch to run as this user. */
switch_to_user (host_user);
@@ -4188,6 +4501,11 @@ kserver_authenticate_connection ()
{
printf ("E Fatal error, aborting.\n\
error %s getpeername or getsockname failed\n", strerror (errno));
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
exit (EXIT_FAILURE);
}
@@ -4209,6 +4527,11 @@ error %s getpeername or getsockname failed\n", strerror (errno));
{
printf ("E Fatal error, aborting.\n\
error 0 kerberos: %s\n", krb_get_err_text(status));
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
exit (EXIT_FAILURE);
}
@@ -4220,6 +4543,11 @@ error 0 kerberos: %s\n", krb_get_err_text(status));
{
printf ("E Fatal error, aborting.\n\
error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status));
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket subsystems on
+ NT and OS2 or dealing with windows and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
exit (EXIT_FAILURE);
}
@@ -4691,6 +5019,12 @@ cvs_outerr (str, len)
size_t to_write = len;
const char *p = str;
+ /* Make sure that output appears in order if stdout and stderr
+ point to the same place. For the server case this is taken
+ care of by the fact that saved_outerr always holds less
+ than a line. */
+ fflush (stdout);
+
while (to_write > 0)
{
written = fwrite (p, 1, to_write, stderr);
@@ -4724,3 +5058,29 @@ cvs_flusherr ()
#endif
fflush (stderr);
}
+
+/* Make it possible for the user to see what has been written to
+ stdout (it is up to the implementation to decide exactly how far it
+ should go to ensure this). */
+
+void
+cvs_flushout ()
+{
+#ifdef SERVER_SUPPORT
+ if (error_use_protocol)
+ {
+ /* Flush what we can to the network, but don't block. */
+ buf_flush (buf_to_net, 0);
+ }
+ else if (server_active)
+ {
+ /* Just do nothing. This is because the code which
+ cvs_flushout replaces, setting stdout to line buffering in
+ main.c, didn't get called in the server child process. But
+ in the future it is quite plausible that we'll want to make
+ this case work analogously to cvs_flusherr. */
+ }
+ else
+#endif
+ fflush (stdout);
+}
diff --git a/gnu/usr.bin/cvs/src/update.c b/gnu/usr.bin/cvs/src/update.c
index c1a8d11846f..87d338a0e3f 100644
--- a/gnu/usr.bin/cvs/src/update.c
+++ b/gnu/usr.bin/cvs/src/update.c
@@ -34,6 +34,7 @@
*/
#include "cvs.h"
+#include "savecwd.h"
#ifdef SERVER_SUPPORT
#include "md5.h"
#endif
@@ -49,7 +50,6 @@ static int patch_file PROTO ((struct file_info *finfo,
int *docheckout, struct stat *file_info,
unsigned char *checksum));
#endif
-static int isemptydir PROTO((char *dir));
static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers));
static int scratch_file PROTO((struct file_info *finfo));
static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir,
@@ -256,7 +256,7 @@ update (argc, argv)
if (failed_patches == NULL)
{
send_file_names (argc, argv, SEND_EXPAND_WILD);
- send_files (argc, argv, local, aflag);
+ send_files (argc, argv, local, aflag, update_build_dirs);
}
else
{
@@ -265,7 +265,7 @@ update (argc, argv)
(void) printf ("%s client: refetching unpatchable files\n",
program_name);
- if (toplevel_wd[0] != '\0'
+ if (toplevel_wd != NULL
&& CVS_CHDIR (toplevel_wd) < 0)
{
error (1, errno, "could not chdir to %s", toplevel_wd);
@@ -275,7 +275,7 @@ update (argc, argv)
(void) unlink_file (failed_patches[i]);
send_file_names (failed_patches_count, failed_patches, 0);
send_files (failed_patches_count, failed_patches, local,
- aflag);
+ aflag, update_build_dirs);
}
failed_patches = NULL;
@@ -539,22 +539,11 @@ update_fileproc (callerdat, finfo)
if (retcode)
{
- /*
- * If the timestamps differ, look for Conflict
- * indicators to see if 'C' anyway.
- */
- run_setup ("%s", GREP);
- run_arg (RCS_MERGE_PAT);
- run_arg (finfo->file);
- retcode = run_exec (RUN_TTY, DEVNULL,
- RUN_TTY,RUN_NORMAL);
- if (retcode == -1)
- {
- error (1, errno,
- "fork failed while examining conflict in `%s'",
- finfo->fullname);
- }
+ /* The timestamps differ. But if there are conflict
+ markers print 'C' anyway. */
+ retcode = !file_has_markers (finfo);
}
+
if (!retcode)
{
(void) write_letter (finfo->file, 'C', finfo->update_dir);
@@ -840,9 +829,12 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
if ((cp = strrchr (line, '\n')) != NULL)
*cp = '\0';
run_setup ("%s %s", line, repository);
- (void) printf ("%s %s: Executing '", program_name, command_name);
+ cvs_output (program_name, 0);
+ cvs_output (" ", 1);
+ cvs_output (command_name, 0);
+ cvs_output (": Executing '", 0);
run_print (stdout);
- (void) printf ("'\n");
+ cvs_output ("'\n", 0);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
(void) fclose (fp);
@@ -854,7 +846,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
/* FIXME: chdir ("..") loses with symlinks. */
/* Prune empty dirs on the way out - if necessary */
(void) CVS_CHDIR ("..");
- if (update_prune_dirs && isemptydir (dir))
+ if (update_prune_dirs && isemptydir (dir, 0))
{
/* I'm not sure the existence_error is actually possible (except
in cases where we really should print a message), but since
@@ -868,30 +860,92 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
return (err);
}
-/*
- * Returns 1 if the argument directory is completely empty, other than the
- * existence of the CVS directory entry. Zero otherwise.
- */
+static int isremoved PROTO ((Node *, void *));
+
+/* Returns 1 if the file indicated by node has been removed. */
static int
-isemptydir (dir)
+isremoved (node, closure)
+ Node *node;
+ void *closure;
+{
+ Entnode *entdata = (Entnode*) node->data;
+
+ /* If the first character of the version is a '-', the file has been
+ removed. */
+ return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
+}
+
+/* Returns 1 if the argument directory is completely empty, other than the
+ existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
+ and the directory doesn't exist, then just return 0. */
+int
+isemptydir (dir, might_not_exist)
char *dir;
+ int might_not_exist;
{
DIR *dirp;
struct dirent *dp;
if ((dirp = CVS_OPENDIR (dir)) == NULL)
{
- error (0, 0, "cannot open directory %s for empty check", dir);
+ if (might_not_exist && existence_error (errno))
+ return 0;
+ error (0, errno, "cannot open directory %s for empty check", dir);
return (0);
}
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
- if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
- strcmp (dp->d_name, CVSADM) != 0)
+ if (strcmp (dp->d_name, ".") != 0
+ && strcmp (dp->d_name, "..") != 0)
{
- (void) closedir (dirp);
- return (0);
+ if (strcmp (dp->d_name, CVSADM) != 0)
+ {
+ /* An entry other than the CVS directory. The directory
+ is certainly not empty. */
+ (void) closedir (dirp);
+ return (0);
+ }
+ else
+ {
+ /* The CVS directory entry. We don't have to worry about
+ this unless the Entries file indicates that files have
+ been removed, but not committed, in this directory.
+ (Removing the directory would prevent people from
+ comitting the fact that they removed the files!) */
+ List *l;
+ int files_removed;
+ struct saved_cwd cwd;
+
+ if (save_cwd (&cwd))
+ error_exit ();
+
+ if (CVS_CHDIR (dir) < 0)
+ error (1, errno, "cannot change directory to %s", dir);
+ l = Entries_Open (0);
+ files_removed = walklist (l, isremoved, 0);
+ Entries_Close (l);
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
+
+ if (files_removed != 0)
+ {
+ /* There are files that have been removed, but not
+ committed! Do not consider the directory empty. */
+ (void) closedir (dirp);
+ return (0);
+ }
+ }
}
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory %s", dir);
+ (void) closedir (dirp);
+ return (0);
}
(void) closedir (dirp);
return (1);
@@ -947,12 +1001,17 @@ checkout_file (finfo, vers_ts, adding)
{
if (!quiet)
{
- (void) fprintf (stderr, "\
-===================================================================\n");
- (void) fprintf (stderr, "Checking out %s\n", finfo->fullname);
- (void) fprintf (stderr, "RCS: %s\n", vers_ts->srcfile->path);
- (void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs);
- (void) fprintf (stderr, "***************\n");
+ cvs_outerr ("\
+===================================================================\n\
+Checking out ", 0);
+ cvs_outerr (finfo->fullname, 0);
+ cvs_outerr ("\n\
+RCS: ", 0);
+ cvs_outerr (vers_ts->srcfile->path, 0);
+ cvs_outerr ("\n\
+VERS: ", 0);
+ cvs_outerr (vers_ts->vn_rcs, 0);
+ cvs_outerr ("\n***************\n", 0);
}
}