summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-12-12 14:43:57 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-12-12 14:43:57 +0000
commit98556d4ac9e1cc382f4da894a69bf8f381a1d38d (patch)
treef5459a680a26e4d35ed43028302f9c8df85742a8
parent1fc2ac9e3c2ee1d4777acdb8a83788bf09ed237e (diff)
Add a check for absolute pathnames; from cvs 1.11.10; deraadt@ OK
-rw-r--r--gnu/usr.bin/cvs/src/modules.c677
1 files changed, 447 insertions, 230 deletions
diff --git a/gnu/usr.bin/cvs/src/modules.c b/gnu/usr.bin/cvs/src/modules.c
index 9dcce131473..a4658815d24 100644
--- a/gnu/usr.bin/cvs/src/modules.c
+++ b/gnu/usr.bin/cvs/src/modules.c
@@ -3,7 +3,7 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
- * as specified in the README file that comes with the CVS 1.4 kit.
+ * as specified in the README file that comes with the CVS source distribution.
*
* Modules
*
@@ -20,18 +20,32 @@
* command line.
*/
+#include <assert.h>
#include "cvs.h"
-#include "save-cwd.h"
+#include "savecwd.h"
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)modules.c 1.62 94/09/29 $";
-USE(rcsid);
-#endif
+
+/* Defines related to the syntax of the modules file. */
+
+/* Options in modules file. Note that it is OK to use GNU getopt features;
+ we already are arranging to make sure we are using the getopt distributed
+ with CVS. */
+#define CVSMODULE_OPTS "+ad:i:lo:e:s:t:u:"
+/* Special delimiter. */
+#define CVSMODULE_SPEC '&'
+
struct sortrec
{
+ /* Name of the module, malloc'd. */
char *modname;
+ /* If Status variable is set, this is either def_status or the malloc'd
+ name of the status. If Status is not set, the field is left
+ uninitialized. */
char *status;
+ /* Pointer to a malloc'd array which contains (1) the raw contents
+ of the options and arguments, excluding comments, (2) a '\0',
+ and (3) the storage for the "comment" field. */
char *rest;
char *comment;
};
@@ -48,17 +62,22 @@ static void save_d PROTO((char *k, int ks, char *d, int ds));
DBM *
open_module ()
{
- char mfile[PATH_MAX];
+ char *mfile;
+ DBM *retval;
- if (CVSroot == NULL)
+ if (current_parsed_root == NULL)
{
- (void) fprintf (stderr,
- "%s: must set the CVSROOT environment variable\n",
- program_name);
- error (1, 0, "or specify the '-d' option to %s", program_name);
+ error (0, 0, "must set the CVSROOT environment variable");
+ error (1, 0, "or specify the '-d' global option");
}
- (void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES);
- return (dbm_open (mfile, O_RDONLY, 0666));
+ mfile = xmalloc (strlen (current_parsed_root->directory)
+ + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_MODULES) + 3);
+ (void) sprintf (mfile, "%s/%s/%s", current_parsed_root->directory,
+ CVSROOTADM, CVSROOTADM_MODULES);
+ retval = dbm_open (mfile, O_RDONLY, 0666);
+ free (mfile);
+ return retval;
}
/*
@@ -78,17 +97,18 @@ close_module (db)
* It runs the post checkout or post tag proc from the modules file
*/
int
-do_module (db, mname, m_type, msg, callback_proc, where,
- shorten, local_specified, run_module_prog, extra_arg)
+do_module (db, mname, m_type, msg, callback_proc, where, shorten,
+ local_specified, run_module_prog, build_dirs, extra_arg)
DBM *db;
char *mname;
enum mtype m_type;
char *msg;
- int (*callback_proc) ();
+ CALLBACKPROC callback_proc;
char *where;
int shorten;
int local_specified;
int run_module_prog;
+ int build_dirs;
char *extra_arg;
{
char *checkin_prog = NULL;
@@ -97,43 +117,68 @@ do_module (db, mname, m_type, msg, callback_proc, where,
char *tag_prog = NULL;
char *update_prog = NULL;
struct saved_cwd cwd;
- char line[MAXLINELEN];
- char *xmodargv[MAXFILEPERDIR];
+ int cwd_saved = 0;
+ char *line;
+ int modargc;
+ int xmodargc;
char **modargv;
- char *value;
- char *zvalue;
+ char **xmodargv = NULL;
+ /* Found entry from modules file, including options and such. */
+ char *value = NULL;
char *mwhere = NULL;
char *mfile = NULL;
char *spec_opt = NULL;
- char xvalue[PATH_MAX];
- int modargc, alias = 0;
+ char *xvalue = NULL;
+ int alias = 0;
datum key, val;
char *cp;
int c, err = 0;
+ int nonalias_opt = 0;
#ifdef SERVER_SUPPORT
+ int restore_server_dir = 0;
+ char *server_dir_to_restore = NULL;
if (trace)
- {
- fprintf (stderr, "%c-> do_module (%s, %s, %s, %s)\n",
- (server_active) ? 'S' : ' ',
- mname, msg, where ? where : "",
- extra_arg ? extra_arg : "");
- }
+ {
+ char *buf;
+
+ /* We use cvs_outerr, rather than fprintf to stderr, because
+ this may be called by server code with error_use_protocol
+ set. */
+ buf = xmalloc (100
+ + strlen (mname)
+ + strlen (msg)
+ + (where ? strlen (where) : 0)
+ + (extra_arg ? strlen (extra_arg) : 0));
+ sprintf (buf, "%s-> do_module (%s, %s, %s, %s)\n",
+ CLIENT_SERVER_STR,
+ mname, msg, where ? where : "",
+ extra_arg ? extra_arg : "");
+ cvs_outerr (buf, 0);
+ free (buf);
+ }
#endif
- /* remember where we start */
- if (save_cwd (&cwd))
- exit (1);
+ /* Don't process absolute directories. Anything else could be a security
+ * problem. Before this check was put in place:
+ *
+ * $ cvs -d:fork:/cvsroot co /foo
+ * cvs server: warning: cannot make directory CVS in /: Permission denied
+ * cvs [server aborted]: cannot make directory /foo: Permission denied
+ * $
+ */
+ if (isabsolute (mname))
+ error (1, 0, "Absolute module reference invalid: `%s'", mname);
/* if this is a directory to ignore, add it to that list */
if (mname[0] == '!' && mname[1] != '\0')
{
ign_dir_add (mname+1);
- return(err);
+ goto do_module_return;
}
/* strip extra stuff from the module name */
- strip_path (mname);
+ strip_trailing_slashes (mname);
/*
* Look up the module using the following scheme:
@@ -153,52 +198,55 @@ do_module (db, mname, m_type, msg, callback_proc, where,
val.dptr = NULL;
if (val.dptr != NULL)
{
- /* null terminate the value XXX - is this space ours? */
- val.dptr[val.dsize] = '\0';
+ /* copy and null terminate the value */
+ value = xmalloc (val.dsize + 1);
+ memcpy (value, val.dptr, val.dsize);
+ value[val.dsize] = '\0';
/* If the line ends in a comment, strip it off */
- if ((cp = strchr (val.dptr, '#')) != NULL)
- {
- do
- *cp-- = '\0';
- while (isspace (*cp));
- }
+ if ((cp = strchr (value, '#')) != NULL)
+ *cp = '\0';
else
- {
- /* Always strip trailing spaces */
- cp = strchr (val.dptr, '\0');
- while (cp > val.dptr && isspace(*--cp))
- *cp = '\0';
- }
+ cp = value + val.dsize;
+
+ /* Always strip trailing spaces */
+ while (cp > value && isspace ((unsigned char) *--cp))
+ *cp = '\0';
- value = val.dptr;
mwhere = xstrdup (mname);
goto found;
}
else
{
- char file[PATH_MAX];
- char attic_file[PATH_MAX];
+ char *file;
+ char *attic_file;
char *acp;
+ int is_found = 0;
/* check to see if mname is a directory or file */
-
- (void) sprintf (file, "%s/%s", CVSroot, mname);
+ file = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (mname) + sizeof(RCSEXT) + 2);
+ (void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
+ attic_file = xmalloc (strlen (current_parsed_root->directory)
+ + strlen (mname)
+ + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
if ((acp = strrchr (mname, '/')) != NULL)
{
*acp = '\0';
- (void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname,
- CVSATTIC, acp + 1, RCSEXT);
+ (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
+ mname, CVSATTIC, acp + 1, RCSEXT);
*acp = '/';
}
else
- (void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC,
- mname, RCSEXT);
+ (void) sprintf (attic_file, "%s/%s/%s%s", current_parsed_root->directory,
+ CVSATTIC, mname, RCSEXT);
if (isdir (file))
{
- value = mname;
- goto found;
+ modargv = xmalloc (sizeof (*modargv));
+ modargv[0] = xstrdup (mname);
+ modargc = 1;
+ is_found = 1;
}
else
{
@@ -208,12 +256,12 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* if mname was a file, we have to split it into "dir file" */
if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
{
- char *slashp;
-
- /* put the ' ' in a copy so we don't mess up the original */
- value = strcpy (xvalue, mname);
- slashp = strrchr (value, '/');
- *slashp = ' ';
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xmalloc (strlen (mname) + 2);
+ strncpy (modargv[0], mname, cp - mname);
+ modargv[0][cp - mname] = '\0';
+ modargv[1] = xstrdup (cp + 1);
+ modargc = 2;
}
else
{
@@ -225,19 +273,54 @@ do_module (db, mname, m_type, msg, callback_proc, where,
if (cp == mname)
{
/* drop the leading / if specified */
- value = strcpy (xvalue, ". ");
- (void) strcat (xvalue, mname + 1);
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname + 1);
+ modargc = 2;
}
else
{
/* otherwise just copy it */
- value = strcpy (xvalue, ". ");
- (void) strcat (xvalue, mname);
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname);
+ modargc = 2;
}
}
- goto found;
+ is_found = 1;
}
}
+ free (attic_file);
+ free (file);
+
+ if (is_found)
+ {
+ assert (value == NULL);
+
+ /* OK, we have now set up modargv with the actual
+ file/directory we want to work on. We duplicate a
+ small amount of code here because the vast majority of
+ the code after the "found" label does not pertain to
+ the case where we found a file/directory rather than
+ finding an entry in the modules file. */
+ if (save_cwd (&cwd))
+ error_exit ();
+ cwd_saved = 1;
+
+ err += callback_proc (modargc, modargv, where, mwhere, mfile,
+ shorten,
+ local_specified, mname, msg);
+
+ free_names (&modargc, modargv);
+
+ /* cd back to where we started. */
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
+ cwd_saved = 0;
+
+ goto do_module_return;
+ }
}
/* look up everything to the first / as a module */
@@ -259,17 +342,20 @@ do_module (db, mname, m_type, msg, callback_proc, where,
{
char *cp2;
- /* null terminate the value XXX - is this space ours? */
- val.dptr[val.dsize] = '\0';
+ /* copy and null terminate the value */
+ value = xmalloc (val.dsize + 1);
+ memcpy (value, val.dptr, val.dsize);
+ value[val.dsize] = '\0';
/* If the line ends in a comment, strip it off */
- if ((cp2 = strchr (val.dptr, '#')) != NULL)
- {
- do
- *cp2-- = '\0';
- while (isspace (*cp2));
- }
- value = val.dptr;
+ if ((cp2 = strchr (value, '#')) != NULL)
+ *cp2 = '\0';
+ else
+ cp2 = value + val.dsize;
+
+ /* Always strip trailing spaces */
+ while (cp2 > value && isspace ((unsigned char) *--cp2))
+ *cp2 = '\0';
/* mwhere gets just the module name */
mwhere = xstrdup (mname);
@@ -288,9 +374,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* if we got here, we couldn't find it using our search, so give up */
error (0, 0, "cannot find module `%s' - ignored", mname);
err++;
- if (mwhere)
- free (mwhere);
- return (err);
+ goto do_module_return;
/*
@@ -299,10 +383,12 @@ do_module (db, mname, m_type, msg, callback_proc, where,
*/
found:
- /* copy value to our own string since if we go recursive we'll be
- really screwed if we do another dbm lookup */
- zvalue = xstrdup (value);
- value = zvalue;
+ /* remember where we start */
+ if (save_cwd (&cwd))
+ error_exit ();
+ cwd_saved = 1;
+
+ assert (value != NULL);
/* search the value for the special delimiter and save for later */
if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
@@ -310,66 +396,9 @@ do_module (db, mname, m_type, msg, callback_proc, where,
*cp = '\0'; /* null out the special char */
spec_opt = cp + 1; /* save the options for later */
- if (cp != value) /* strip whitespace if necessary */
- while (isspace (*--cp))
- *cp = '\0';
-
- if (cp == value)
- {
- /*
- * we had nothing but special options, so skip arg
- * parsing and regular stuff entirely
- *
- * If there were only special ones though, we must
- * make the appropriate directory and cd to it
- */
- char *dir;
-
- /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to
- be !pipeout, but we don't know that here yet */
- if (!run_module_prog)
- goto out;
-
- dir = where ? where : mname;
- /* XXX - think about making null repositories at each dir here
- instead of just at the bottom */
- make_directories (dir);
- if (chdir (dir) < 0)
- {
- error (0, errno, "cannot chdir to %s", dir);
- spec_opt = NULL;
- err++;
- goto out;
- }
- if (!isfile (CVSADM))
- {
- char nullrepos[PATH_MAX];
-
- (void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
- CVSROOTADM, CVSNULLREPOS);
- if (!isfile (nullrepos))
- (void) CVS_MKDIR (nullrepos, 0777);
- if (!isdir (nullrepos))
- error (1, 0, "there is no repository %s", nullrepos);
-
- Create_Admin (".", dir,
- nullrepos, (char *) NULL, (char *) NULL);
- if (!noexec)
- {
- FILE *fp;
-
- 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 (dir, nullrepos);
-#endif
- }
- }
- out:
- goto do_special;
- }
+ /* strip whitespace if necessary */
+ while (cp > value && isspace ((unsigned char) *--cp))
+ *cp = '\0';
}
/* don't do special options only part of a module was specified */
@@ -386,14 +415,18 @@ do_module (db, mname, m_type, msg, callback_proc, where,
*/
/* Put the value on a line with XXX prepended for getopt to eat */
- (void) sprintf (line, "%s %s", "XXX", value);
+ line = xmalloc (strlen (value) + 5);
+ strcpy(line, "XXX ");
+ strcpy(line + 4, value);
/* turn the line into an argv[] array */
- line2argv (&modargc, xmodargv, line);
+ line2argv (&xmodargc, &xmodargv, line, " \t");
+ free (line);
+ modargc = xmodargc;
modargv = xmodargv;
/* parse the args */
- optind = 1;
+ optind = 0;
while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
{
switch (c)
@@ -405,44 +438,69 @@ do_module (db, mname, m_type, msg, callback_proc, where,
if (mwhere)
free (mwhere);
mwhere = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case 'i':
- checkin_prog = optarg;
+ if (checkin_prog)
+ free (checkin_prog);
+ checkin_prog = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case 'l':
local_specified = 1;
+ nonalias_opt = 1;
+ break;
case 'o':
- checkout_prog = optarg;
+ if (checkout_prog)
+ free (checkout_prog);
+ checkout_prog = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case 'e':
- export_prog = optarg;
+ if (export_prog)
+ free (export_prog);
+ export_prog = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case 't':
- tag_prog = optarg;
+ if (tag_prog)
+ free (tag_prog);
+ tag_prog = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case 'u':
- update_prog = optarg;
+ if (update_prog)
+ free (update_prog);
+ update_prog = xstrdup (optarg);
+ nonalias_opt = 1;
break;
case '?':
error (0, 0,
"modules file has invalid option for key %s value %s",
- key.dptr, val.dptr);
+ key.dptr, value);
err++;
- if (mwhere)
- free (mwhere);
- free (zvalue);
- return (err);
+ goto do_module_return;
}
}
modargc -= optind;
modargv += optind;
- if (modargc == 0)
+ if (modargc == 0 && spec_opt == NULL)
{
error (0, 0, "modules file missing directory for module %s", mname);
- if (mwhere)
- free (mwhere);
- free (zvalue);
- return (++err);
+ ++err;
+ goto do_module_return;
+ }
+
+ if (alias && nonalias_opt)
+ {
+ /* The documentation has never said it is legal to specify
+ -a along with another option. And I believe that in the past
+ CVS has ignored the options other than -a, more or less, in this
+ situation. */
+ error (0, 0, "\
+-a cannot be specified in the modules file along with other options");
+ ++err;
+ goto do_module_return;
}
/* if this was an alias, call ourselves recursively for each module */
@@ -459,29 +517,117 @@ do_module (db, mname, m_type, msg, callback_proc, where,
else
err += do_module (db, modargv[i], m_type, msg, callback_proc,
where, shorten, local_specified,
- run_module_prog, extra_arg);
+ run_module_prog, build_dirs, extra_arg);
}
- if (mwhere)
- free (mwhere);
- free (zvalue);
- return (err);
+ goto do_module_return;
+ }
+
+ if (mfile != NULL && modargc > 1)
+ {
+ error (0, 0, "\
+module `%s' is a request for a file in a module which is not a directory",
+ mname);
+ ++err;
+ goto do_module_return;
}
/* otherwise, process this module */
- err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten,
- local_specified, mname, msg);
+ if (modargc > 0)
+ {
+ err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten,
+ local_specified, mname, msg);
+ }
+ else
+ {
+ /*
+ * we had nothing but special options, so we must
+ * make the appropriate directory and cd to it
+ */
+ char *dir;
- /* clean up */
- free_names (&modargc, modargv);
+ if (!build_dirs)
+ goto do_special;
+
+ dir = where ? where : (mwhere ? mwhere : mname);
+ /* XXX - think about making null repositories at each dir here
+ instead of just at the bottom */
+ make_directories (dir);
+ if ( CVS_CHDIR (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ spec_opt = NULL;
+ err++;
+ goto do_special;
+ }
+ if (!isfile (CVSADM))
+ {
+ char *nullrepos;
+
+ nullrepos = emptydir_name ();
+
+ Create_Admin (".", dir,
+ nullrepos, (char *) NULL, (char *) NULL, 0, 0, 1);
+ if (!noexec)
+ {
+ FILE *fp;
+
+ 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 (dir, nullrepos);
+#endif
+ }
+ free (nullrepos);
+ }
+ }
/* if there were special include args, process them now */
do_special:
+ free_names (&xmodargc, xmodargv);
+ xmodargv = NULL;
+
/* blow off special options if -l was specified */
if (local_specified)
spec_opt = NULL;
+#ifdef SERVER_SUPPORT
+ /* We want to check out into the directory named by the module.
+ So we set a global variable which tells the server to glom that
+ directory name onto the front. A cleaner approach would be some
+ way of passing it down to the recursive call, through the
+ callback_proc, to start_recursion, and then into the update_dir in
+ the struct file_info. That way the "Updating foo" message could
+ print the actual directory we are checking out into.
+
+ For local CVS, this is handled by the chdir call above
+ (directly or via the callback_proc). */
+ if (server_active && spec_opt != NULL)
+ {
+ char *change_to;
+
+ change_to = where ? where : (mwhere ? mwhere : mname);
+ server_dir_to_restore = server_dir;
+ restore_server_dir = 1;
+ server_dir =
+ xmalloc ((server_dir_to_restore != NULL
+ ? strlen (server_dir_to_restore)
+ : 0)
+ + strlen (change_to)
+ + 5);
+ server_dir[0] = '\0';
+ if (server_dir_to_restore != NULL)
+ {
+ strcat (server_dir, server_dir_to_restore);
+ strcat (server_dir, "/");
+ }
+ strcat (server_dir, change_to);
+ }
+#endif
+
while (spec_opt != NULL)
{
char *next_opt;
@@ -495,13 +641,13 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* strip whitespace off the end */
do
*cp = '\0';
- while (isspace (*--cp));
+ while (cp > spec_opt && isspace ((unsigned char) *--cp));
}
else
next_opt = NULL;
/* strip whitespace from front */
- while (isspace (*spec_opt))
+ while (isspace ((unsigned char) *spec_opt))
spec_opt++;
if (*spec_opt == '\0')
@@ -510,10 +656,18 @@ do_module (db, mname, m_type, msg, callback_proc, where,
else
err += do_module (db, spec_opt, m_type, msg, callback_proc,
(char *) NULL, 0, local_specified,
- run_module_prog, extra_arg);
+ run_module_prog, build_dirs, extra_arg);
spec_opt = next_opt;
}
+#ifdef SERVER_SUPPORT
+ if (server_active && restore_server_dir)
+ {
+ free (server_dir);
+ server_dir = server_dir_to_restore;
+ }
+#endif
+
/* write out the checkin/update prog files if necessary */
#ifdef SERVER_SUPPORT
if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding)
@@ -547,8 +701,9 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* cd back to where we started */
if (restore_cwd (&cwd, NULL))
- exit (1);
+ error_exit ();
free_cwd (&cwd);
+ cwd_saved = 0;
/* run checkout or tag prog if appropriate */
if (err == 0 && run_module_prog)
@@ -563,38 +718,71 @@ do_module (db, mname, m_type, msg, callback_proc, where,
* if we can't find a matching program, just punt and use
* whatever is specified in the modules file.
*/
- char real_prog[PATH_MAX];
+ char *real_prog = NULL;
char *prog = (m_type == TAG ? tag_prog :
(m_type == CHECKOUT ? checkout_prog : export_prog));
char *real_where = (where != NULL ? where : mwhere);
+ char *expanded_path;
if ((*prog != '/') && (*prog != '.'))
{
+ real_prog = xmalloc (strlen (real_where) + strlen (prog)
+ + 10);
(void) sprintf (real_prog, "%s/%s", real_where, prog);
if (isfile (real_prog))
prog = real_prog;
}
- run_setup ("%s %s", prog, real_where);
- if (extra_arg)
- run_arg (extra_arg);
-
- if (!quiet)
+ /* XXX can we determine the line number for this entry??? */
+ expanded_path = expand_path (prog, "modules", 0);
+ if (expanded_path != NULL)
{
- (void) printf ("%s %s: Executing '", program_name,
- command_name);
- run_print (stdout);
- (void) printf ("'\n");
+ run_setup (expanded_path);
+ run_arg (real_where);
+
+ if (extra_arg)
+ run_arg (extra_arg);
+
+ if (!quiet)
+ {
+ cvs_output (program_name, 0);
+ cvs_output (" ", 1);
+ cvs_output (command_name, 0);
+ cvs_output (": Executing '", 0);
+ run_print (stdout);
+ cvs_output ("'\n", 0);
+ cvs_flushout ();
+ }
+ err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ free (expanded_path);
}
- err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ free (real_prog);
}
}
+ do_module_return:
/* clean up */
+ if (xmodargv != NULL)
+ free_names (&xmodargc, xmodargv);
if (mwhere)
free (mwhere);
- free (zvalue);
-
+ if (checkin_prog)
+ free (checkin_prog);
+ if (checkout_prog)
+ free (checkout_prog);
+ if (export_prog)
+ free (export_prog);
+ if (tag_prog)
+ free (tag_prog);
+ if (update_prog)
+ free (update_prog);
+ if (cwd_saved)
+ free_cwd (&cwd);
+ if (value != NULL)
+ free (value);
+
+ if (xvalue != NULL)
+ free (xvalue);
return (err);
}
@@ -683,15 +871,15 @@ save_d (k, ks, d, ds)
cp = d;
*(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
/* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
while (*cp)
{
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
{
*cp2++ = ' ';
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
}
else
@@ -704,15 +892,19 @@ save_d (k, ks, d, ds)
{
s_rec->status = def_status;
- /* Minor kluge, but general enough to maintain */
for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
{
if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
{
- s_rec->status = (cp2 += 3);
- while (*cp2 != ' ')
+ char *status_start;
+
+ cp2 += 3;
+ status_start = cp2;
+ while (*cp2 != ' ' && *cp2 != '\0')
cp2++;
- *cp2++ = '\0';
+ s_rec->status = xmalloc (cp2 - status_start + 1);
+ strncpy (s_rec->status, status_start, cp2 - status_start);
+ s_rec->status[cp2 - status_start] = '\0';
cp = cp2;
break;
}
@@ -749,23 +941,7 @@ cat_module (status)
int moduleargc;
struct sortrec *s_h;
char *cp, *cp2, **argv;
- char line[MAXLINELEN], *moduleargv[MAXFILEPERDIR];
-
-#ifdef sun
-#ifdef TIOCGSIZE
- struct ttysize ts;
-
- (void) ioctl (0, TIOCGSIZE, &ts);
- cols = ts.ts_cols;
-#endif
-#else
-#ifdef TIOCGWINSZ
- struct winsize ws;
-
- (void) ioctl (0, TIOCGWINSZ, &ws);
- cols = ws.ws_col;
-#endif
-#endif
+ char **moduleargv;
Status = status;
@@ -780,6 +956,8 @@ cat_module (status)
save_d (key.dptr, key.dsize, val.dptr, val.dsize);
}
+ close_module (db);
+
/* Sort the list as requested */
qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
@@ -791,22 +969,30 @@ cat_module (status)
fill = cols - (indent + 2);
for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
{
+ char *line;
+
/* Print module name (and status, if wanted) */
- (void) printf ("%-12s", s_h->modname);
+ line = xmalloc (strlen (s_h->modname) + 15);
+ sprintf (line, "%-12s", s_h->modname);
+ cvs_output (line, 0);
+ free (line);
if (status)
{
- (void) printf (" %-11s", s_h->status);
- if (s_h->status != def_status)
- *(s_h->status + strlen (s_h->status)) = ' ';
+ line = xmalloc (strlen (s_h->status) + 15);
+ sprintf (line, " %-11s", s_h->status);
+ cvs_output (line, 0);
+ free (line);
}
+ line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 15);
/* Parse module file entry as command line and print options */
(void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
- line2argv (&moduleargc, moduleargv, line);
+ line2argv (&moduleargc, &moduleargv, line, " \t");
+ free (line);
argc = moduleargc;
argv = moduleargv;
- optind = 1;
+ optind = 0;
wid = 0;
while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
{
@@ -814,17 +1000,28 @@ cat_module (status)
{
if (c == 'a' || c == 'l')
{
- (void) printf (" -%c", c);
+ char buf[5];
+
+ sprintf (buf, " -%c", c);
+ cvs_output (buf, 0);
wid += 3; /* Could just set it to 3 */
}
else
{
+ char buf[10];
+
if (strlen (optarg) + 4 + wid > (unsigned) fill)
{
- (void) printf ("\n%*s", indent, "");
+ int j;
+
+ cvs_output ("\n", 1);
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
wid = 0;
}
- (void) printf (" -%c %s", c, optarg);
+ sprintf (buf, " -%c ", c);
+ cvs_output (buf, 0);
+ cvs_output (optarg, 0);
wid += strlen (optarg) + 4;
}
}
@@ -837,21 +1034,31 @@ cat_module (status)
{
if (strlen (*argv) + wid > (unsigned) fill)
{
- (void) printf ("\n%*s", indent, "");
+ int j;
+
+ cvs_output ("\n", 1);
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
wid = 0;
}
- (void) printf (" %s", *argv);
+ cvs_output (" ", 1);
+ cvs_output (*argv, 0);
wid += strlen (*argv) + 1;
}
- (void) printf ("\n");
+ cvs_output ("\n", 1);
/* Format the comment field -- save_d (), compressed spaces */
for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
{
- (void) printf ("%*s # ", indent, "");
+ int j;
+
+ for (j = 0; j < indent; ++j)
+ cvs_output (" ", 1);
+ cvs_output (" # ", 0);
if (strlen (cp2) < (unsigned) (fill - 2))
{
- (void) printf ("%s\n", cp2);
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
break;
}
cp += fill - 2;
@@ -859,12 +1066,22 @@ cat_module (status)
cp--;
if (cp == cp2)
{
- (void) printf ("%s\n", cp2);
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
break;
}
*cp++ = '\0';
- (void) printf ("%s\n", cp2);
+ cvs_output (cp2, 0);
+ cvs_output ("\n", 1);
}
+
+ free_names(&moduleargc, moduleargv);
+ /* FIXME-leak: here is where we would free s_h->modname, s_h->rest,
+ and if applicable, s_h->status. Not exactly a memory leak,
+ in the sense that we are about to exit(), but may be worth
+ noting if we ever do a multithreaded server or something of
+ the sort. */
}
+ /* FIXME-leak: as above, here is where we would free s_head. */
}