Index: src/admin.c
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/admin.c,v
retrieving revision 1.108
diff -u -p -r1.108 admin.c
--- src/admin.c	2 Sep 2005 21:51:08 -0000	1.108
+++ src/admin.c	4 Nov 2005 19:15:17 -0000
@@ -65,6 +65,8 @@ static const char *const admin_usage[] =
     "\t-u[rev]    Unlock the revision (latest revision on branch,\n",
     "\t           latest revision on trunk if omitted).\n",
     "\t-U         Unset strict locking.\n",
+    "\t--no-execute Turn off execute bits on repository file.\n",
+    "\t--execute    Turn on execute bits on respoitory file.\n",
     "(Specify the --help global option for a list of other help options)\n",
     NULL
 };
@@ -101,6 +103,8 @@ struct admin_data
     /* Interactive (-I).  Problematic with client/server.  */
     int interactive;
 
+    enum {AVOID = 0, NOEXECUTE, EXECUTE} execute;
+
     /* This is the cheesy part.  It is a vector with the options which
        we don't deal with above (e.g. "-afoo" "-abar,baz").  In the future
        this presumably will be replaced by other variables which break
@@ -206,6 +210,93 @@ admin_filesdoneproc (void *callerdat, in
 
 
 
+static struct option long_options[] =
+{
+    {"no-execute", 0, NULL, 1},
+    {"execute", 0, NULL, 2},
+    {0, 0, 0, 0}
+};
+
+
+
+/* Accept a `;' delimited string and break it into tokens.  Allocate a return
+ * string.  Copy the first token into the return string.  For remaining tokens,
+ * convert to the long option VAL (from the global LONG_OPTIONS above) and
+ * append that char to the return value.  When long option tokens are
+ * unrecognized, a warning is printed and they are ignored.
+ *
+ * i.e., S will be of the format `[SHORTOPTIONS][;LONGOPTION]...'.  It is
+ * perfectly acceptable for SHORTOPTIONS to resolve to the empty string, but
+ * an empty LONGOPTION will cause a warning message to be printed.
+ */
+char *
+make_UserAdminOptions (const char *infopath, unsigned int ln, const char *s)
+{
+    const char *p;
+    bool first = true;
+    char *ns = xmalloc (1);
+
+    assert (s);
+
+    p = s;
+    *ns = '\0';
+    do
+    {
+	struct option *found;
+	const char *q;
+	size_t len;
+
+	q = strchr (p, ';');
+	if (q) len = q - p;
+	else len = strlen (p);
+
+	if (first)
+	{
+	    first = false;
+	    found = NULL;
+	}
+	else
+	    for (found = long_options; found->name; found++)
+		if (len == strlen (found->name)
+		    && !strncmp (p, found->name, len))
+		    break;
+
+	if (found && found->name)
+	{
+	    ns = xrealloc (ns, len + 2);
+	    ns[len++] = found->val;
+	    ns[len] = '\0';
+	    TRACE (TRACE_FUNCTION, "Adding long UserAdminOptions `%s'",
+		   found->name);
+	}
+	else if (first)
+	{
+	    size_t nslen = strlen (ns);
+	    ns = xrealloc (ns, nslen + len + 1);
+	    strncat (ns, p, len);
+	    ns[nslen + len] = '\0';
+	    TRACE (TRACE_FUNCTION, "Appending `%s' to UserAdminOptions",
+		   ns + nslen);
+	}
+	else
+	{
+	    char *tmp = xmalloc (len + 1);
+	    strncpy (tmp, p, len);
+	    ns[len] = '\0';
+	    error (0, 0,
+		   "%s [%u]: Unrecognized long admin option `%s'.",
+		   infopath, ln, tmp);
+	    free (tmp);
+	}
+
+	p = q;
+    } while (p);
+	
+    return ns;
+}
+
+
+
 int
 admin (int argc, char **argv)
 {
@@ -219,6 +310,9 @@ admin (int argc, char **argv)
     int i;
     bool only_allowed_options;
 
+    static const char short_options[] =
+	"+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:";
+
     if (argc <= 1)
 	usage (admin_usage);
 
@@ -231,8 +325,9 @@ admin (int argc, char **argv)
 
     optind = 0;
     only_allowed_options = true;
-    while ((c = getopt (argc, argv,
-			"+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
+    while ((c = getopt_long
+	    (argc, argv, short_options, long_options, &optind))
+	   != EOF)
     {
 	if (
 # ifdef CLIENT_SUPPORT
@@ -244,6 +339,14 @@ admin (int argc, char **argv)
 
 	switch (c)
 	{
+	    case 1:		/* --no-execute */
+		admin_data.execute = NOEXECUTE;
+		break;
+
+	    case 2:		/* --execute */
+		admin_data.execute = EXECUTE;
+		break;
+
 	    case 'i':
 		/* This has always been documented as useless in cvs.texinfo
 		   and it really is--admin_fileproc silently does nothing
@@ -532,6 +635,10 @@ admin (int argc, char **argv)
 	    send_arg ("-U");
 	if (admin_data.delete_revs != NULL)
 	    send_arg (admin_data.delete_revs);
+	if (admin_data.execute == EXECUTE)
+	    send_arg ("--execute");
+	else if (admin_data.execute == NOEXECUTE)
+	    send_arg ("--no-execute");
 	if (admin_data.desc != NULL)
 	{
 	    char *p = admin_data.desc;
@@ -974,6 +1081,52 @@ admin_fileproc (void *callerdat, struct 
     if (status == 0)
     {
 	RCS_rewrite (rcs, NULL, NULL);
+
+        /*
+         * Update the execute bit for the file if requested.
+         */
+        if (admin_data->execute != AVOID)
+        {
+            struct stat sb;
+ 
+            if (stat (rcs->path, &sb) < 0)
+                error (0, errno, "cannot stat `%s'", rcs->path);
+            else
+            {
+                mode_t mode, oumask;
+ 
+                oumask = umask (0);
+                (void) umask (oumask);
+ 
+                if (admin_data->execute == EXECUTE)
+                    mode = (sb.st_mode
+                            | (~oumask
+                               & (((sb.st_mode & S_IRUSR) ? S_IXUSR : 0)
+                                  | ((sb.st_mode & S_IRGRP) ? S_IXGRP : 0)
+                                  | ((sb.st_mode & S_IROTH) ? S_IXOTH : 0))));
+                else /* admin_data->execute == NOEXECUTE */
+                    mode = (sb.st_mode
+                            & ~(S_IEXEC | S_IXGRP | S_IXOTH) & ~oumask);
+ 
+                if (mode == sb.st_mode)
+                    error (0, 0, "%s: already has mode=0%o",
+			   rcs->path, mode);
+                else
+                {
+                    TRACE (TRACE_FLOW, "chmod(%s,0%o)", rcs->path,
+                           (unsigned int) mode);
+                    
+		    if (!noexec)
+		    {
+			if (chmod (rcs->path, mode) < 0)
+			    error (0, errno,
+				   "cannot change mode of file `%s'",
+				   rcs->path);
+		    }
+                }
+            }
+        }
+
 	if (!really_quiet)
 	    cvs_output ("done\n", 5);
     }
Index: src/parseinfo.c
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/parseinfo.c,v
retrieving revision 1.84
diff -u -p -r1.84 parseinfo.c
--- src/parseinfo.c	6 Sep 2005 04:41:48 -0000	1.84
+++ src/parseinfo.c	4 Nov 2005 19:15:18 -0000
@@ -15,6 +15,13 @@
 #include "getline.h"
 #include "history.h"
 
+
+/* From admin.c.  */
+char *make_UserAdminOptions (const char *infopath, unsigned int ln,
+			     const char *s);
+
+
+
 /*
  * Parse the INFOFILE file for the specified REPOSITORY.  Invoke CALLPROC for
  * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
@@ -657,7 +664,7 @@ parse_config (const char *cvsroot, const
 	     */
 	}
 	else if (strcmp (line, "UserAdminOptions") == 0)
-	    retval->UserAdminOptions = xstrdup (p);
+	    retval->UserAdminOptions = make_UserAdminOptions (infopath, ln, p);
 	else if (strcmp (line, "UseNewInfoFmtStrings") == 0)
 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
 	    readBool (infopath, "UseNewInfoFmtStrings", p,
