subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bre...@apache.org
Subject svn commit: r1428209 - in /subversion/trunk: Makefile.in build.conf build/win32/make_dist.py tools/server-side/svnauthz-validate.c tools/server-side/svnauthz.c
Date Thu, 03 Jan 2013 08:19:37 GMT
Author: breser
Date: Thu Jan  3 08:19:36 2013
New Revision: 1428209

URL: http://svn.apache.org/viewvc?rev=1428209&view=rev
Log:
Rename svnauthz-validate to svnauthz and start using subcommands.

svnauthz now has a validate and accessof subcommands.  If run with an argv[0]
that starts with 'svnauthz-validate' it enables a compat mode that behaves
almost exactly as svnauthz-validate did in 1.7.  Only difference being that
it will accept file:// URLs.  On UNIX we install a symlink as part of
the install-tools target now to make the old command work.

* Makefile.in
  (INSTALL_EXTRA_TOOLS): symlink svnauthz-validate to svnauthz

* build/win32/make_dist.py
  (_disttree): Rename svnauthz-validate.exe to svnauthz.exe

* build.conf
  (__ALL__, svnauthz-validate, svnauthz): Rename svnauthz-validate to svnauthz

* tools/server-side/svnauthz-validate.c: Rename to ... 

* tools/serverside/svnauthz.c
  (svnauthz__cmdline_options_t): Replace an anonymous enum.
  (options_table): Move options struct from sub_main().
  (svnauthz_opt_state): typedef previous anonymous opts struct in sub_main().
  (SVNAUTHZ_COMPAT_NAME): prefix of command name to enter compat mode.
  (usage, subcommand_help): Replace usage() with subcommand_help().
  (cmd_table): New struct for subcommands.
  (get_authz, subcommand_validate, subcommand_accessof): New functions, split
    off from sub_main().
  (EXIT_FAILURE): Redefine to 2 to match our contract.
  (handle_exit_error, EXIT_ERROR): Add exit_code argument.
  (SVN_INT_ERR): Pass EXIT_FAILURE to EXIT_ERROR().
  (use_compat_mode): New function.
  (sub_main): Refactor to use subcommands and support compat mode.
  (main): Use EXIT_FAILURE instead of hardcoded 2.

Added:
    subversion/trunk/tools/server-side/svnauthz.c
      - copied, changed from r1427958, subversion/trunk/tools/server-side/svnauthz-validate.c
Removed:
    subversion/trunk/tools/server-side/svnauthz-validate.c
Modified:
    subversion/trunk/Makefile.in
    subversion/trunk/build.conf
    subversion/trunk/build/win32/make_dist.py

Modified: subversion/trunk/Makefile.in
URL: http://svn.apache.org/viewvc/subversion/trunk/Makefile.in?rev=1428209&r1=1428208&r2=1428209&view=diff
==============================================================================
--- subversion/trunk/Makefile.in (original)
+++ subversion/trunk/Makefile.in Thu Jan  3 08:19:36 2013
@@ -926,4 +926,5 @@ INSTALL_EXTRA_TOOLS=\
   $(MKDIR) $(DESTDIR)$(bindir); \
   test -n "$$SVN_SVNMUCC_IS_SVNSYITF" && \
   ln -sf svnmucc$(EXEEXT) $(DESTDIR)$(bindir)/svnsyitf$(EXEEXT); \
-  ln -sf $(DESTDIR)$(bindir)/svnmucc$(EXEEXT) $(DESTDIR)$(toolsdir)/svnmucc$(EXEEXT)
+  ln -sf $(DESTDIR)$(bindir)/svnmucc$(EXEEXT) $(DESTDIR)$(toolsdir)/svnmucc$(EXEEXT); \
+  ln -sf $(DESTDIR)$(toolsdir)/svnauthz$(EXEEXT) $(DESTDIR)$(toolsdir)/svnauthz-validate

Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1428209&r1=1428208&r2=1428209&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Thu Jan  3 08:19:36 2013
@@ -1204,7 +1204,7 @@ path = build/win32
 libs = svn svnadmin svndumpfilter svnlook svnmucc svnserve svnrdump svnsync
        svnversion
        mod_authz_svn mod_dav_svn mod_dontdothat
-       svnauthz-validate svnraisetreeconflict
+       svnauthz svnraisetreeconflict
 
 [__ALL_TESTS__]
 type = project
@@ -1322,11 +1322,11 @@ install = tools
 libs = libsvn_client libsvn_wc libsvn_ra libsvn_subr libsvn_delta
        apriconv apr
 
-[svnauthz-validate]
-description = Authz config file validator
+[svnauthz]
+description = Authz config file tool
 type = exe
 path = tools/server-side
-sources = svnauthz-validate.c
+sources = svnauthz.c
 install = tools
 libs = libsvn_repos libsvn_fs libsvn_subr apr
 

Modified: subversion/trunk/build/win32/make_dist.py
URL: http://svn.apache.org/viewvc/subversion/trunk/build/win32/make_dist.py?rev=1428209&r1=1428208&r2=1428209&view=diff
==============================================================================
--- subversion/trunk/build/win32/make_dist.py (original)
+++ subversion/trunk/build/win32/make_dist.py Thu Jan  3 08:19:36 2013
@@ -215,8 +215,8 @@ _disttree = {'': OptFile('%(readme)s', '
                      File('%(blddir)s/svnmucc/svnmucc.pdb'),
                      File('%(blddir)s/../contrib/client-side/svn-push/svn-push.exe'),
                      File('%(blddir)s/../contrib/client-side/svn-push/svn-push.pdb'),
-                     File('%(blddir)s/../tools/server-side/svnauthz-validate.exe'),
-                     File('%(blddir)s/../tools/server-side/svnauthz-validate.pdb'),
+                     File('%(blddir)s/../tools/server-side/svnauthz.exe'),
+                     File('%(blddir)s/../tools/server-side/svnauthz.pdb'),
                      File('%(blddir)s/../tools/server-side/svn-populate-node-origins-index.exe'),
                      File('%(blddir)s/../tools/server-side/svn-populate-node-origins-index.pdb'),
                      File('%(blddir)s/../tools/dev/svnraisetreeconflict/svnraisetreeconflict.exe'),

Copied: subversion/trunk/tools/server-side/svnauthz.c (from r1427958, subversion/trunk/tools/server-side/svnauthz-validate.c)
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/svnauthz.c?p2=subversion/trunk/tools/server-side/svnauthz.c&p1=subversion/trunk/tools/server-side/svnauthz-validate.c&r1=1427958&r2=1428209&rev=1428209&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/svnauthz-validate.c (original)
+++ subversion/trunk/tools/server-side/svnauthz.c Thu Jan  3 08:19:36 2013
@@ -1,5 +1,5 @@
 /*
- * svnauthz-validate.c : Load and validate an authz file.
+ * svnauthz.c : Tool for working with authz files.
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,6 @@
  *    specific language governing permissions and limitations
  *    under the License.
  * ====================================================================
- *
- *
- * svnauthz-validate.c : load and validate an authz file, returns
- *       value == 0 if syntax of authz file is correct
- *       value == 1 if syntax of authz file is invalid or file not found
- *       value == 2 in case of general error
- *
  */
 
 #include "svn_cmdline.h"
@@ -36,34 +29,134 @@
 #include "svn_utf.h"
 #include "svn_path.h"
 
-enum {
-  OPT_USERNAME = SVN_OPT_FIRST_LONGOPT_ID,
-  OPT_PATH,
-  OPT_REPOS
+
+/*** Option Processing. ***/
+
+enum svnauthz__cmdline_options_t
+{
+  svnauthz__version = SVN_OPT_FIRST_LONGOPT_ID,
+  svnauthz__username,
+  svnauthz__path,
+  svnauthz__repos
 };
 
-static int
-usage(const char *argv0)
+/* Option codes and descriptions.
+ *
+ * The entire list must be terminated with an entry of nulls.
+ */
+static const apr_getopt_option_t options_table[] =
+{
+  {"help", 'h', 0, ("show help on a subcommand")},
+  {NULL, '?', 0, ("show help on a subcommand")},
+  {"version", svnauthz__version, 0, ("show program version information")},
+  {"username", svnauthz__username, 1, ("username to check access of")},
+  {"path", svnauthz__path, 1, ("path within repository to check access of")},
+  {"repository", svnauthz__repos, 1, ("repository authz name")},
+  {"transaction", 't', 1, ("transaction id")},
+  {0, 0, 0, 0}
+};
+
+struct svnauthz_opt_state
+{
+  svn_boolean_t help;
+  svn_boolean_t version;
+  const char *authz_file;
+  const char *username;
+  const char *fspath;
+  const char *repos_name;
+  const char *txn;
+  const char *repos_path;
+};
+
+#define SVNAUTHZ_COMPAT_NAME "svnauthz-validate"
+
+
+
+/*** Subcommands. */
+
+static svn_opt_subcommand_t
+  subcommand_help,
+  subcommand_validate,
+  subcommand_accessof;
+
+/* Array of available subcommands.
+ * The entire list must be terminated with an entry of nulls.
+ */
+static const svn_opt_subcommand_desc2_t cmd_table[] =
+{
+  {"help", subcommand_help, {"?", "h"},
+   ("usage: svnauthz help [SUBCOMMAND...]\n\n"
+    "Describe the usage of this program or its subcommands.\n"),
+   {0} },
+  {"validate", subcommand_validate, {0} /* no aliases */,
+   ("Checks the syntax of an authz file.\n"
+    "usage: 1. svnauthz validate TARGET\n"
+    "       2. svnauthz validate --transaction TXN REPOS_PATH FILE_PATH\n\n"
+    "  1. Loads and validates the syntax of the authz file at TARGET.\n"
+    "     TARGET can be a path to a file or an absolute file:// URL to an authz\n"
+    "     file in a repository, but cannot be a repository relative URL (^/).\n\n"
+    "  2. Loads and validates the syntax of the authz file at FILE_PATH in the\n"
+    "     transaction TXN in the repository at REPOS_PATH.\n\n"
+    "Returns:\n"
+    "    0   when syntax is OK.\n"
+    "    1   when syntax is invalid.\n"
+    "    2   operational error\n"
+    ),
+   {'t'} },
+  {"accessof", subcommand_accessof, {0} /* no aliases */,
+   ("Output the permissions set by an authz file for a specific circumstance.\n"
+    "usage: 1. svnauthz accessof [--username USER] TARGET\n"
+    "       2. svnauthz accessof [--username USER] -t TXN REPOS_PATH FILE_PATH\n\n" 
+    "  1. Prints the access of USER based on TARGET.\n"
+    "     TARGET can be a path to a file or an absolute file:// URL to an authz\n"
+    "     file in a repository, but cannot be a repository relative URL (^/).\n\n"
+    "  2. Prints the access of USER based on authz file at FILE_PATH in the\n"
+    "     transaction TXN in the repository at REPOS_PATH.\n\n"
+    "  If the --username argument is ommitted then access of an anonymous user\n"
+    "  will be printed.  If --path argument is ommitted prints if any access\n"
+    "  to the repo is allowed.\n\n"
+    "Outputs one of the following:\n"
+    "     rw    write access (which also implies read)\n"
+    "      r    read access\n"
+    "     no    no access\n\n"
+    "Returns:\n"
+    "    0   when syntax is OK.\n"
+    "    1   when syntax is invalid.\n"
+    "    2   operational error\n"
+    ),
+   {'t', svnauthz__username, svnauthz__path, svnauthz__repos} },
+};
+
+static svn_error_t *
+subcommand_help(apr_getopt_t *os, void *baton, apr_pool_t *pool)
 {
-  printf("Usage: 1. %s [OPTION]... TARGET\n", argv0);
-  printf("       2. %s [OPTION]... --transaction TXN REPOS_PATH FILE_PATH\n\n", argv0); 
-  printf(" 1. Loads and validates the syntax of the authz file at TARGET.\n"
-         "    TARGET can be a path to a file or an absolute file:// URL to an authz\n"
-         "    file in a repository, but cannot be a repository relative URL (^/).\n\n"
-         " 2. Loads and validates the syntax of the authz file at FILE_PATH in the\n"
-         "    transaction TXN in the repository at REPOS_PATH.\n\n"
-         " Options:\n\n"
-         "   --username USER         : prints access available for a user\n"
-         "   --path FSPATH           : makes --username print access available for FSPATH\n"
-         "   --repository REPOS_NAME : use REPOS_NAME as repository authz name when\n"
-         "                               determining access available with --username\n"
-         "   -t, --transaction TXN   : enables mode 2 which looks for the file in an\n"
-         "                               uncommitted transaction TXN\n\n"
-         "Returns:\n"
-         "    0   when syntax is OK.\n"
-         "    1   when syntax is invalid.\n"
-         "    2   operational error\n");
-  return 2;
+  struct svnauthz_opt_state *opt_state = baton;
+  const char *header =
+    ("general usage: svnauthz SUBCOMMAND TARGET [ARGS & OPTIONS ...]\n"
+     "               " SVNAUTHZ_COMPAT_NAME " TARGET\n\n"
+     "If the filename for the command starts with '" SVNAUTHZ_COMPAT_NAME "', runs in\n"
+     "pre 1.8 compatability mode; which runs the validate subcommand on TARGET.\n\n"
+     "Type 'svnauthz help <subcommand>' for help on a specific subcommand.\n"
+     "Type 'svnauthz --version' to see the program version.\n\n"
+     "Available subcommands:\n");
+
+  const char *fs_desc_start
+    = ("The following repository back-end (FS) modules are available:\n\n");
+
+  svn_stringbuf_t *version_footer;
+
+  version_footer = svn_stringbuf_create(fs_desc_start, pool);
+  SVN_ERR(svn_fs_print_modules(version_footer, pool));
+
+  SVN_ERR(svn_opt_print_help4(os, "svnauthz",
+                              opt_state ? opt_state->version : FALSE,
+                              FALSE, /* quiet */
+                              FALSE, /* verbose */
+                              version_footer->data,
+                              header, cmd_table, options_table, NULL, NULL,
+                              pool));
+
+  return SVN_NO_ERROR;
 }
 
 /* Loads the authz config into *AUTHZ from the file at AUTHZ_FILE
@@ -105,13 +198,78 @@ get_authz_from_txn(svn_authz_t **authz, 
   return SVN_NO_ERROR;
 }
 
-/* Similar to svn_cmdline_handle_exit_error but returns 2 rather than
-   EXIT_FAILURE since our contract demands that we exit with 2 for
-   internal failures.  Also is missing the pool argument since we
-   don't need it given main/sub_main. */
+/* Loads the authz config into *AUTHZ from OPT_STATE->AUTHZ_FILE.  If
+   OPT_STATE->TXN is set then OPT_STATE->AUTHZ_FILE is treated as a fspath
+   in repository at OPT_STATE->REPOS_PATH. */
+static svn_error_t *
+get_authz(svn_authz_t **authz, struct svnauthz_opt_state *opt_state,
+          apr_pool_t *pool)
+{
+  /* Read the access file and validate it. */
+  if (opt_state->txn)
+    return get_authz_from_txn(authz, opt_state->repos_path,
+                              opt_state->authz_file, opt_state->txn, pool);
+
+  /* Else */
+  return svn_repos_authz_read2(authz, opt_state->authz_file, TRUE, NULL, pool);
+}
+
+static svn_error_t *
+subcommand_validate(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnauthz_opt_state *opt_state = baton;
+  svn_authz_t *authz;
+
+  /* Not much to do here since just loading the authz file also validates. */
+  return get_authz(&authz, opt_state, pool);
+}
+
+static svn_error_t *
+subcommand_accessof(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  svn_authz_t *authz;
+  svn_boolean_t read_access, write_access;
+  svn_error_t *err;
+  struct svnauthz_opt_state *opt_state = baton;
+  const char *user = opt_state->username;
+  const char *path = opt_state->fspath;
+  const char *repos = opt_state->repos_name;
+ 
+  SVN_ERR(get_authz(&authz, opt_state, pool));
+
+  if (path && path[0] != '/')
+    path = apr_pstrcat(pool, "/", path, NULL);
+
+  err = svn_repos_authz_check_access(authz, repos, path, user,
+                                     svn_authz_write, &write_access,
+                                     pool);
+  if (!write_access && !err)
+    err = svn_repos_authz_check_access(authz, repos, path, user,
+                                       svn_authz_read, &read_access,
+                                       pool);
+  if (!err)
+    printf("%s\n",
+           write_access ? "rw" : read_access ? "r" : "no"
+          );
+
+  return err;
+}
+
+
+
+/*** Main. ***/
+
+/* A redefinition of EXIT_FAILURE since our contract demands that we
+   exit with 2 for internal failures. */
+#undef EXIT_FAILURE
+#define EXIT_FAILURE 2
+
+/* Similar to svn_cmdline_handle_exit_error but with an exit_code argument
+   so we can comply with our contract an exit with 2 for internal failures.
+   Also is missing the pool argument since we don't need it given
+   main/sub_main. */
 static int
-handle_exit_error(svn_error_t *err,
-                      const char *prefix)
+handle_exit_error(svn_error_t *err, const char *prefix, int exit_code)
 {
   /* Issue #3014:
    * Don't print anything on broken pipes. The pipe was likely
@@ -123,174 +281,286 @@ handle_exit_error(svn_error_t *err,
   if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
     svn_handle_error2(err, stderr, FALSE, prefix);
   svn_error_clear(err);
-  return 2;
+  return exit_code;
 }
 
 /* Report and clear the error ERR, and return EXIT_FAILURE. */
-#define EXIT_ERROR(err)                                                 \
-  handle_exit_error(err, "svnauthz-validate: ")
+#define EXIT_ERROR(err, exit_code)                               \
+  handle_exit_error(err, "svnauthz: ", exit_code)
 
 /* A redefinition of the public SVN_INT_ERR macro, that suppresses the
  * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR, amd with the
- * program name 'svnauthz-validate' instead of 'svn'. */
+ * program name 'svnauthz' instead of 'svn'. */
 #undef SVN_INT_ERR
 #define SVN_INT_ERR(expr)                                        \
   do {                                                           \
     svn_error_t *svn_err__temp = (expr);                         \
     if (svn_err__temp)                                           \
-      return EXIT_ERROR(svn_err__temp);                          \
+      return EXIT_ERROR(svn_err__temp, EXIT_FAILURE);            \
   } while (0)
 
 
+static svn_boolean_t
+use_compat_mode(const char *cmd, apr_pool_t *pool)
+{
+  cmd = svn_dirent_internal_style(cmd, pool);
+  cmd = svn_dirent_basename(cmd, NULL);
+
+  /* Deliberately look only for the start of the name to deal with
+     the executable extension on some platforms. */
+  return 0 == strncmp(SVNAUTHZ_COMPAT_NAME, cmd,
+                      strlen(SVNAUTHZ_COMPAT_NAME));
+}
+
 static int
 sub_main(int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err;
-  apr_status_t apr_err;
-  svn_authz_t *authz;
+
+  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  struct svnauthz_opt_state opt_state = { 0 };
   apr_getopt_t *os;
-  const apr_getopt_option_t options[] =
-    {
-      {"username", OPT_USERNAME, 1, ("the authenticated username")},
-      {"path", OPT_PATH, 1, ("path within the repository")},
-      {"repository", OPT_REPOS, 1, ("repository authz name")},
-      {"transaction", 't', 1, ("transaction id")},
-      {0,             0,  0,  0}
-    };
-  struct {
-    const char *authz_file;
-    const char *username;
-    const char *fspath;
-    const char *repos_name;
-    const char *txn;
-    const char *repos_path;
-  } opts;
-  opts.username = opts.fspath = opts.repos_name = opts.txn = NULL;
-  opts.repos_path = NULL;
+  apr_array_header_t *received_opts;
+  int i;
 
   /* Initialize the FS library. */
   SVN_INT_ERR(svn_fs_initialize(pool));
 
-  /* Repeat svn_cmdline__getopt_init() inline. */
-  apr_err = apr_getopt_init(&os, pool, argc, argv);
-  if (apr_err)
+  received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
+
+  /* Initialize opt_state */
+  opt_state.username = opt_state.fspath = opt_state.repos_name = NULL;
+  opt_state.txn = opt_state.repos_path = NULL;
+
+  /* Parse options. */
+  SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+  os->interleave = 1;
+
+  if (!use_compat_mode(argv[0], pool))
+    {
+      while (1)
+        {
+          int opt;
+          const char *arg;
+          apr_status_t status = apr_getopt_long(os, options_table, &opt, &arg);
+
+          if (APR_STATUS_IS_EOF(status))
+            break;
+          if (status != APR_SUCCESS)
+            {
+              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+              return EXIT_FAILURE;
+            }
+
+          /* Stash the option code in an array before parsing it. */
+          APR_ARRAY_PUSH(received_opts, int) = opt;
+
+          switch (opt)
+            {
+            case 'h':
+            case '?':
+              opt_state.help = TRUE;
+              break;
+            case 't':
+              SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.txn, arg, pool));
+              break;
+            case svnauthz__version:
+              opt_state.version = TRUE;
+              break;
+            case svnauthz__username:
+              SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.username, arg, pool));
+              break;
+            case svnauthz__path:
+              SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.fspath, arg, pool));
+              break;
+            case svnauthz__repos:
+              SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_name, arg, pool));
+              break;
+            default:
+                {
+                  SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+                  return EXIT_FAILURE;
+                }
+            }
+        }
+    }
+  else
     {
-       err = svn_error_wrap_apr(apr_err,
-                                ("Error initializing command line arguments"));
-       svn_handle_warning2(stderr, err, "svnauthz-validate: ");
-       return 2;
+      /* Pre 1.8 compatability mode. */
+      if (argc == 1) /* No path argument */
+        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
+      else
+        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "validate");
     }
 
-  os->interleave = 1;
-  while (1)
+  /* If the user asked for help, then the rest of the arguments are
+     the names of subcommands to get help on (if any), or else they're
+     just typos/mistakes.  Whatever the case, the subcommand to
+     actually run is subcommand_help(). */
+  if (opt_state.help)
+    subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
+
+  if (subcommand == NULL)
     {
-      int opt;
-      const char *arg;
-      apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
-      if (APR_STATUS_IS_EOF(status))
-        break;
-      if (status != APR_SUCCESS)
-        {
-          return usage(argv[0]);
-        }
-      switch (opt)
-        {
-        case OPT_USERNAME:
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.username, arg, pool));
-          break;
-        case OPT_PATH:
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.fspath, arg, pool));
-          break;
-        case OPT_REPOS:
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.repos_name, arg, pool));
-          break;
-        case 't':
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.txn, arg, pool));
-          break;
-        default:
-          return usage(argv[0]);
+      if (os->ind >= os->argc)
+        {
+          if (opt_state.version)
+            {
+              /* Use the "help" subcommand to handle the "--version" option. */
+              static const svn_opt_subcommand_desc2_t pseudo_cmd = 
+                { "--version", subcommand_help, {0}, "",
+                  {svnauthz__version /* must accept its own option */ } };
+
+              subcommand = &pseudo_cmd;
+            }
+          else
+            {
+              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
+                                        ("subcommand argument required\n")));
+              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+              return EXIT_FAILURE;
+            }
+        }
+      else
+        {
+          const char *first_arg = os->argv[os->ind++];
+          subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg);
+          if (subcommand == NULL)
+            {
+              const char *first_arg_utf8;
+
+              os->ind++;
+              SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
+                                                  first_arg, pool));
+              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
+                                                  ("Unknown command: '%s'\n"),
+                                                  first_arg_utf8));
+              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+              return EXIT_FAILURE;
+            }
         }
     }
 
-  /* Consume a non-option argument (repos_path) if --transaction */
-  if (opts.txn)
+  /* Every subcommand except `help' requires one or two non-option arguments.
+     Parse them and store them in opt_state.*/
+  if (subcommand->cmd_func != subcommand_help)
     {
-      if (os->ind +2 != argc)
-        return usage(argv[0]);
+      /* Consume a non-option argument (repos_path) if --transaction */
+      if (opt_state.txn)
+        {
+          if (os->ind +2 != argc)
+            {
+              err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                     ("Repository and authz file arguments "
+                                      "required"));
+              return EXIT_ERROR(err, EXIT_FAILURE); 
+            }
+
+          SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_path, os->argv[os->ind],
+                                              pool));
+          os->ind++;
+
+          opt_state.repos_path = svn_dirent_internal_style(opt_state.repos_path, pool);
+        }
+
+      /* Exactly 1 non-option argument */
+      if (os->ind + 1 != argc)
+        {
+          err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                 ("Authz file argument required"));
+          return EXIT_ERROR(err, EXIT_FAILURE); 
+        }
 
-      SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.repos_path, os->argv[os->ind],
+      /* Grab AUTHZ_FILE from argv. */
+      SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.authz_file, os->argv[os->ind],
                                           pool));
-      os->ind++;
 
-      opts.repos_path = svn_dirent_internal_style(opts.repos_path, pool);
+      /* Can't accept repos relative urls since we don't have the path to the
+       * repository and URLs don't need to be converted to internal style. */
+      if (svn_path_is_repos_relative_url(opt_state.authz_file))
+        {
+          err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                  ("'%s' is a repository relative URL when it "
+                                   "should be a local path or file:// URL"),
+                                  opt_state.authz_file);
+          return EXIT_ERROR(err, EXIT_FAILURE);
+        }
+      else if (!svn_path_is_url(opt_state.authz_file))
+        opt_state.authz_file = svn_dirent_internal_style(opt_state.authz_file, pool);
+      else if (opt_state.txn) /* don't allow urls with transaction argument */
+        {
+          err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                  ("'%s' is a URL when it should be a "
+                                   "local path"), opt_state.authz_file);
+          return EXIT_ERROR(err, EXIT_FAILURE);
+        }
     }
 
-  /* Exactly 1 non-option argument, and no --repository/--path
-     unless --username.  */
-  if (os->ind + 1 != argc || (!opts.username && (opts.fspath || opts.repos_name)))
+  /* Check that the subcommand wasn't passed any inappropriate options. */
+  for (i = 0; i < received_opts->nelts; i++)
     {
-      return usage(argv[0]);
-    }
+      int opt_id = APR_ARRAY_IDX(received_opts, i, int);
 
-  /* Grab AUTHZ_FILE from argv. */
-  SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.authz_file, os->argv[os->ind],
-                                      pool));
-
-  /* Can't accept repos relative urls since we don't have the path to the
-   * repository and URLs don't need to be converted to internal style. */
-  if (svn_path_is_repos_relative_url(opts.authz_file))
-    return usage(argv[0]);
-  else if (!svn_path_is_url(opts.authz_file))
-    opts.authz_file = svn_dirent_internal_style(opts.authz_file, pool);
-  else if (opts.txn) /* don't allow urls with transaction argument */
-    return usage(argv[0]);
+      /* All commands implicitly accept --help, so just skip over this
+         when we see it. Note that we don't want to include this option
+         in their "accepted options" list because it would be awfully
+         redundant to display it in every commands' help text. */
+      if (opt_id == 'h' || opt_id == '?')
+        continue;
 
-  /* Read the access file and validate it. */
-  if (opts.txn)
-    {
-      err = get_authz_from_txn(&authz, opts.repos_path,
-                               opts.authz_file, opts.txn, pool);
-    }
-  else
-    {
-      err = svn_repos_authz_read2(&authz, opts.authz_file, TRUE, NULL, pool);
+      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
+        {
+          const char *optstr;
+          const apr_getopt_option_t *badopt =
+            svn_opt_get_option_from_code2(opt_id, options_table, subcommand,
+                                          pool);
+          svn_opt_format_option(&optstr, badopt, FALSE, pool);
+          if (subcommand->name[0] == '-')
+            SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+          else
+            svn_error_clear(svn_cmdline_fprintf(stderr, pool,
+                            ("Subcommand '%s' doesn't accept option '%s'\n"
+                             "Type 'svnauthz help %s' for usage.\n"),
+                            subcommand->name, optstr, subcommand->name));
+          return EXIT_FAILURE;
+        }
     }
 
-  /* Optionally, print the access a USER has to a given PATH in REPOS.
-     PATH and REPOS may be NULL. */
-  if (!err && opts.username)
-    {
-      const char *user = opts.username;
-      const char *path = opts.fspath;
-      const char *repos = opts.repos_name;
-      svn_boolean_t read_access, write_access;
-
-      if (path && path[0] != '/')
-        path = apr_pstrcat(pool, "/", path, NULL);
-
-      err = svn_repos_authz_check_access(authz, repos, path, user,
-                                         svn_authz_write, &write_access,
-                                         pool);
-      if (!write_access && !err)
-        err = svn_repos_authz_check_access(authz, repos, path, user,
-                                           svn_authz_read, &read_access,
-                                           pool);
-      if (!err)
-        printf("%s\n",
-               write_access ? "rw" : read_access ? "r" : "no"
-               );
-    }
+  /* Run the subcommand. */
+  err = (*subcommand->cmd_func)(os, &opt_state, pool);
 
   if (err)
     {
-      svn_handle_error2(err, stderr, FALSE, "svnauthz-validate: ");
-      svn_error_clear(err);
-      return 1;
+      if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS
+          || err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
+        {
+          /* For argument-related problems, suggest using the 'help'
+             subcommand. */
+          err = svn_error_quick_wrap(err,
+                                     ("Try 'svnauthz help' for more info"));
+        }
+      else if (err->apr_err == SVN_ERR_AUTHZ_INVALID_CONFIG
+               || err->apr_err == SVN_ERR_MALFORMED_FILE)
+        {
+          /* Follow our contract that says we exit with 1 if the file does not
+             validate. */
+          return EXIT_ERROR(err, 1);
+        }
+
+      return EXIT_ERROR(err, EXIT_FAILURE);
     }
   else
     {
-      return 0;
+      /* Ensure that everything is written to stdout, so the user will
+         see any print errors. */
+      err = svn_cmdline_fflush(stdout);
+      if (err)
+        {
+          return EXIT_ERROR(err, EXIT_FAILURE);
+        }
+      return EXIT_SUCCESS;
     }
+
 }
 
 int
@@ -301,7 +571,7 @@ main(int argc, const char *argv[])
 
   /* Initialize the app.  Send all error messages to 'stderr'.  */
   if (svn_cmdline_init(argv[0], stderr) != EXIT_SUCCESS)
-    return 2;
+    return EXIT_FAILURE;
 
   pool = svn_pool_create(NULL);
 



Mime
View raw message