You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/11/27 12:52:46 UTC

svn commit: r1546002 [29/39] - in /subversion/branches/verify-keep-going: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/ contrib/server-side/svnc...

Modified: subversion/branches/verify-keep-going/subversion/svnauth/svnauth.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/svnauth/svnauth.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/svnauth/svnauth.c (original)
+++ subversion/branches/verify-keep-going/subversion/svnauth/svnauth.c Wed Nov 27 11:52:35 2013
@@ -25,12 +25,21 @@
 
 #include <apr_general.h>
 #include <apr_getopt.h>
+#include <apr_fnmatch.h>
 #include <apr_tables.h>
 
+#include "svn_private_config.h"
+
+#ifdef SVN_HAVE_SERF
+#include <serf.h>
+#endif
+
+#include "svn_private_config.h"
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_opt.h"
 #include "svn_dirent_uri.h"
+#include "svn_hash.h"
 #include "svn_utf.h"
 #include "svn_cmdline.h"
 #include "svn_config.h"
@@ -38,8 +47,7 @@
 #include "svn_sorts.h"
 
 #include "private/svn_cmdline_private.h"
-
-#include "svn_private_config.h"
+#include "private/svn_token.h"
 
 /* Baton for passing option/argument state to a subcommand function. */
 struct svnauth_opt_state
@@ -59,7 +67,8 @@ typedef enum svnauth__longopt_t {
 /** Subcommands. **/
 static svn_opt_subcommand_t
   subcommand_help,
-  subcommand_list;
+  subcommand_list,
+  subcommand_delete;
 
 /* Array of available subcommands.
  * The entire list must be terminated with an entry of nulls.
@@ -72,10 +81,42 @@ static const svn_opt_subcommand_desc2_t 
    {0} },
 
   {"list", subcommand_list, {0}, N_
-   ("usage: svnauth list\n\n"
-    "List cached authentication credentials.\n"),
+   ("usage: svnauth list [PATTERN ...]\n"
+    "\n"
+    "  List cached authentication credentials.\n"
+    "\n"
+    "  If PATTERN is specified, only list credentials with attributes matching\n"
+    "  the pattern. All attributes except passwords can be matched. If more than\n"
+    "  one pattern is specified credentials are shown if their attributes match\n"
+    "  all patterns. Patterns are matched case-sensitively and may contain\n"
+    "  glob wildcards:\n"
+    "    ?      matches any single character\n"
+    "    *      matches a sequence of arbitrary characters\n"
+    "    [abc]  matches any of the characters listed inside the brackets\n"
+    "  Note that wildcards will usually need to be quoted or escaped on the\n"
+    "  command line because many command shells will interfere by trying to\n"
+    "  expand them.\n"
+    "\n"
+    "  If no pattern is specified, all cached credentials are shown.\n"),
    {opt_config_dir, opt_show_passwords} },
 
+  {"delete", subcommand_delete, {"del", "remove", "rm"}, N_
+   ("usage: svnauth delete PATTERN ...\n"
+    "\n"
+    "  Delete cached authentication credentials matching a pattern.\n"
+    "\n"
+    "  All credential attributes except passwords can be matched. If more than \n"
+    "  one pattern is specified credentials are deleted only if their attributes\n"
+    "  match all patterns. Patterns are matched case-sensitively and may contain\n"
+    "  glob wildcards:\n"
+    "    ?      matches any single character\n"
+    "    *      matches a sequence of arbitrary characters\n"
+    "    [abc]  matches any of the characters listed inside the brackets\n"
+    "  Note that wildcards will usually need to be quoted or escaped on the\n"
+    "  command line because many command shells will interfere by trying to\n"
+    "  expand them.\n"),
+   {opt_config_dir} },
+
   {NULL}
 };
 
@@ -97,6 +138,46 @@ static const apr_getopt_option_t options
     {NULL}
   };
 
+/* Parse the remaining command-line arguments from OS, returning them
+   in a new array *ARGS (allocated from POOL) and optionally verifying
+   that we got the expected number thereof.  If MIN_EXPECTED is not
+   negative, return an error if the function would return fewer than
+   MIN_EXPECTED arguments.  If MAX_EXPECTED is not negative, return an
+   error if the function would return more than MAX_EXPECTED
+   arguments.
+
+   As a special case, when MIN_EXPECTED and MAX_EXPECTED are both 0,
+   allow ARGS to be NULL.  */
+static svn_error_t *
+parse_args(apr_array_header_t **args,
+           apr_getopt_t *os,
+           int min_expected,
+           int max_expected,
+           apr_pool_t *pool)
+{
+  int num_args = os ? (os->argc - os->ind) : 0;
+
+  if (min_expected || max_expected)
+    SVN_ERR_ASSERT(args);
+
+  if ((min_expected >= 0) && (num_args < min_expected))
+    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
+  if ((max_expected >= 0) && (num_args > max_expected))
+    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
+                            _("Too many arguments provided"));
+  if (args)
+    {
+      *args = apr_array_make(pool, num_args, sizeof(const char *));
+
+      if (num_args)
+        while (os->ind < os->argc)
+          APR_ARRAY_PUSH(*args, const char *) =
+            apr_pstrdup(pool, os->argv[os->ind++]);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *
 subcommand_help(apr_getopt_t *os, void *baton, apr_pool_t *pool)
@@ -104,6 +185,7 @@ subcommand_help(apr_getopt_t *os, void *
   struct svnauth_opt_state *opt_state = baton;
   const char *header =
     _("general usage: svnauth SUBCOMMAND [ARGS & OPTIONS ...]\n"
+      "Subversion authentication credentials management tool.\n"
       "Type 'svnauth help <subcommand>' for help on a specific subcommand.\n"
       "Type 'svnauth --version' to see the program version and available\n"
       "authentication credential caches.\n"
@@ -131,16 +213,16 @@ subcommand_help(apr_getopt_t *os, void *
                             footer, svn_dirent_local_style(config_path, pool));
 #endif
 #ifdef SVN_HAVE_GNOME_KEYRING
-      footer = apr_pstrcat(pool, footer, "  Gnome Keyring\n", NULL);
+      footer = apr_pstrcat(pool, footer, "  Gnome Keyring\n", SVN_VA_NULL);
 #endif
 #ifdef SVN_HAVE_GPG_AGENT
-      footer = apr_pstrcat(pool, footer, "  GPG-Agent\n", NULL);
+      footer = apr_pstrcat(pool, footer, "  GPG-Agent\n", SVN_VA_NULL);
 #endif
 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
-      footer = apr_pstrcat(pool, footer, "  Mac OS X Keychain\n", NULL);
+      footer = apr_pstrcat(pool, footer, "  Mac OS X Keychain\n", SVN_VA_NULL);
 #endif
 #ifdef SVN_HAVE_KWALLET
-      footer = apr_pstrcat(pool, footer, "  KWallet (KDE)\n", NULL);
+      footer = apr_pstrcat(pool, footer, "  KWallet (KDE)\n", SVN_VA_NULL);
 #endif
     }
 
@@ -157,50 +239,553 @@ subcommand_help(apr_getopt_t *os, void *
 #define SEP_STRING \
   "------------------------------------------------------------------------\n"
 
-/* This implements `svn_config_auth_walk_func_t` */
+#ifdef SVN_HAVE_SERF
+/* Because APR hash order is unstable we use a token map of keys
+ * to ensure values are always presented in the same order. */
+typedef enum svnauth__cert_info_keys {
+  svnauth__cert_key_cn,
+  svnauth__cert_key_e,
+  svnauth__cert_key_ou,
+  svnauth__cert_key_o,
+  svnauth__cert_key_l,
+  svnauth__cert_key_st,
+  svnauth__cert_key_c,
+  svnauth__cert_key_sha1,
+  svnauth__cert_key_not_before,
+  svnauth__cert_key_not_after,
+} svnauth__cert_info_keys;
+
+static svn_token_map_t cert_info_key_map[] = {
+    { "CN",         svnauth__cert_key_cn },
+    { "E",          svnauth__cert_key_e },
+    { "OU",         svnauth__cert_key_ou },
+    { "O",          svnauth__cert_key_o },
+    { "L",          svnauth__cert_key_l },
+    { "ST",         svnauth__cert_key_st },
+    { "C",          svnauth__cert_key_c },
+    { "sha1",       svnauth__cert_key_sha1 },
+    { "notBefore",  svnauth__cert_key_not_before },
+    { "notAfter",   svnauth__cert_key_not_after }
+};
+
+/* Show information stored in CERT_INFO.
+ * Assume all hash table keys occur in the above key map. */
 static svn_error_t *
-list_credentials(svn_boolean_t *delete_cred,
-                 void *baton,
+show_cert_info(apr_hash_t *cert_info,
+               apr_pool_t *scratch_pool)
+{
+  int i;
+
+  for (i = 0; i < sizeof(cert_info_key_map) / sizeof(svn_token_map_t); i++)
+    {
+      const char *key = cert_info_key_map[i].str;
+      const char *value = svn_hash_gets(cert_info, key);
+
+      if (value)
+        {
+          int token;
+
+          token = svn_token__from_word(cert_info_key_map, key);
+          switch (token)
+            {
+              case svnauth__cert_key_cn:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Common Name: %s\n"), value));
+                break;
+              case svnauth__cert_key_e:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Email Address: %s\n"), value));
+                break;
+              case svnauth__cert_key_o:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Organization Name: %s\n"),
+                                           value));
+                break;
+              case svnauth__cert_key_ou:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Organizational Unit: %s\n"),
+                                           value));
+                break;
+              case svnauth__cert_key_l:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Locality: %s\n"), value));
+                break;
+              case svnauth__cert_key_st:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  State or Province: %s\n"),
+                                           value));
+                break;
+              case svnauth__cert_key_c:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Country: %s\n"), value));
+                break;
+              case svnauth__cert_key_sha1:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  SHA1 Fingerprint: %s\n"),
+                                           value));
+                break;
+              case svnauth__cert_key_not_before:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Valid as of: %s\n"), value));
+                break;
+              case svnauth__cert_key_not_after:
+                SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                           _("  Valid until: %s\n"), value));
+                break;
+              case SVN_TOKEN_UNKNOWN:
+              default:
+#ifdef SVN_DEBUG
+                SVN_ERR_MALFUNCTION();
+#endif
+                break;
+            }
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+#define MAX_CERT_LINE_LEN 78
+
+/* Break ASCII_CERT into lines of at most MAX_CERT_LINE_LEN characters.
+ * Otherwise, OpenSSL won't parse it due to the way it is invoked by serf. */
+static const char *
+split_ascii_cert(const char *ascii_cert,
+                 apr_pool_t *result_pool)
+{
+  apr_array_header_t *lines;
+  int i;
+  apr_size_t cert_len, nlines;
+  const char *p;
+  svn_stringbuf_t *line;
+
+  p = ascii_cert;
+  cert_len = strlen(ascii_cert);
+  nlines = cert_len / MAX_CERT_LINE_LEN;
+  lines = apr_array_make(result_pool, 22, sizeof(const char *));
+  for (i = 0; i < nlines; i++)
+    {
+      line = svn_stringbuf_create_ensure(MAX_CERT_LINE_LEN, result_pool);
+      svn_stringbuf_appendbytes(line, p, MAX_CERT_LINE_LEN);
+      p += MAX_CERT_LINE_LEN;
+      APR_ARRAY_PUSH(lines, const char *) = line->data;
+    }
+  if (*p)
+    {
+      line = svn_stringbuf_create_ensure(MAX_CERT_LINE_LEN, result_pool);
+      while (*p)
+        svn_stringbuf_appendbyte(line, *p++);
+      APR_ARRAY_PUSH(lines, const char *) = line->data;
+    }
+
+  return svn_cstring_join(lines, "\n", result_pool);
+}
+#endif /* SVN_HAVE_SERF */
+
+#ifdef SVN_HAVE_SERF
+static svn_error_t *
+load_cert(serf_ssl_certificate_t **cert,
+          const char *ascii_cert,
+          apr_pool_t *result_pool,
+          apr_pool_t *scratch_pool)
+{
+  apr_file_t *pem_file;
+  const char *pem_path;
+  const char *pem;
+  apr_size_t pem_len;
+  apr_size_t written;
+  apr_status_t status;
+
+  SVN_ERR(svn_io_open_unique_file3(&pem_file, &pem_path, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   scratch_pool, scratch_pool));
+  pem = apr_psprintf(scratch_pool, "%s%s%s",
+                     "-----BEGIN CERTIFICATE-----\n",
+                     split_ascii_cert(ascii_cert, scratch_pool),
+                     "-----END CERTIFICATE-----\n");
+  pem_len = strlen(pem);
+  SVN_ERR(svn_io_file_write_full(pem_file, pem, pem_len, &written,
+                                 scratch_pool));
+  if (written != pem_len)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("Base64-encoded certificate: %s\n"),
+                                 ascii_cert));
+      return SVN_NO_ERROR;
+    }
+  SVN_ERR(svn_io_file_flush_to_disk(pem_file, scratch_pool));
+
+  status = serf_ssl_load_cert_file(cert, pem_path, result_pool);
+  if (status)
+    {
+      svn_error_t *err;
+      
+      err = svn_error_wrap_apr(status, _("serf error: %s"),
+                               serf_error_string(status));
+      svn_handle_warning2(stderr, err, "svnauth: ");
+      svn_error_clear(err);
+
+      *cert = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  return SVN_NO_ERROR;
+}
+#endif
+
+/* ### from libsvn_subr/ssl_server_trust_providers.c */
+#define AUTHN_ASCII_CERT_KEY            "ascii_cert"
+#define AUTHN_FAILURES_KEY              "failures"
+
+/* Display the base64-encoded DER certificate ASCII_CERT. */
+static svn_error_t *
+show_ascii_cert(const char *ascii_cert,
+                apr_pool_t *scratch_pool)
+{
+#ifdef SVN_HAVE_SERF
+  serf_ssl_certificate_t *cert;
+  apr_hash_t *cert_info;
+
+  SVN_ERR(load_cert(&cert, ascii_cert, scratch_pool, scratch_pool));
+
+  if (cert == NULL)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("Base64-encoded certificate: %s\n"),
+                                 ascii_cert));
+      return SVN_NO_ERROR;
+    }
+
+  cert_info = serf_ssl_cert_issuer(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool, _("Certificate issuer:\n")));
+      SVN_ERR(show_cert_info(cert_info, scratch_pool));
+    }
+
+  cert_info = serf_ssl_cert_subject(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool, _("Certificate subject:\n")));
+      SVN_ERR(show_cert_info(cert_info, scratch_pool));
+    }
+
+  cert_info = serf_ssl_cert_certificate(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(svn_cmdline_printf(scratch_pool, _("Certificate validity:\n")));
+      SVN_ERR(show_cert_info(cert_info, scratch_pool));
+    }
+#else
+  SVN_ERR(svn_cmdline_printf(scratch_pool,
+                             _("Base64-encoded certificate: %s\n"),
+                             ascii_cert));
+#endif /* SVN_HAVE_SERF */
+
+  return SVN_NO_ERROR;
+}
+                
+static svn_error_t *
+show_cert_failures(const char *failure_string,
+                   apr_pool_t *scratch_pool)
+{
+  unsigned int failures;
+
+  SVN_ERR(svn_cstring_atoui(&failures, failure_string));
+
+  if (0 == (failures & (SVN_AUTH_SSL_NOTYETVALID | SVN_AUTH_SSL_EXPIRED |
+                        SVN_AUTH_SSL_CNMISMATCH | SVN_AUTH_SSL_UNKNOWNCA |
+                        SVN_AUTH_SSL_OTHER)))
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_cmdline_printf(
+            scratch_pool, _("Automatic certificate validity check failed "
+                            "because:\n")));
+
+  if (failures & SVN_AUTH_SSL_NOTYETVALID)
+    SVN_ERR(svn_cmdline_printf(
+              scratch_pool, _("  The certificate is not yet valid.\n")));
+
+  if (failures & SVN_AUTH_SSL_EXPIRED)
+    SVN_ERR(svn_cmdline_printf(
+              scratch_pool, _("  The certificate has expired.\n")));
+
+  if (failures & SVN_AUTH_SSL_CNMISMATCH)
+    SVN_ERR(svn_cmdline_printf(
+              scratch_pool, _("  The certificate's Common Name (hostname) "
+                              "does not match the remote hostname.\n")));
+
+  if (failures & SVN_AUTH_SSL_UNKNOWNCA)
+    SVN_ERR(svn_cmdline_printf(
+              scratch_pool, _("  The certificate issuer is unknown.\n")));
+
+  if (failures & SVN_AUTH_SSL_OTHER)
+    SVN_ERR(svn_cmdline_printf(
+              scratch_pool, _("  Unknown verification failure.\n")));
+
+  return SVN_NO_ERROR;
+}
+
+/* ### from libsvn_subr/simple_providers.c */
+#define AUTHN_USERNAME_KEY            "username"
+#define AUTHN_PASSWORD_KEY            "password"
+#define AUTHN_PASSTYPE_KEY            "passtype"
+
+/* ### from libsvn_subr/ssl_client_cert_pw_providers.c */
+#define AUTHN_PASSPHRASE_KEY            "passphrase"
+
+struct walk_credentials_baton_t
+{
+  int matches;
+  svn_boolean_t list;
+  svn_boolean_t delete;
+  svn_boolean_t show_passwords;
+  apr_array_header_t *patterns;
+};
+
+static svn_boolean_t
+match_pattern(const char *pattern, const char *value,
+              apr_pool_t *scratch_pool)
+{
+  const char *p = apr_psprintf(scratch_pool, "*%s*", pattern);
+
+  return (apr_fnmatch(p, value, 0) == APR_SUCCESS);
+}
+
+#ifdef SVN_HAVE_SERF
+static svn_error_t *
+match_cert_info(svn_boolean_t *match,
+                const char *pattern,
+                apr_hash_t *cert_info,
+                apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_pool_t *iterpool;
+
+  *match = FALSE;
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sizeof(cert_info_key_map) / sizeof(svn_token_map_t); i++)
+    {
+      const char *key = cert_info_key_map[i].str;
+      const char *value = svn_hash_gets(cert_info, key);
+
+      svn_pool_clear(iterpool);
+      if (value)
+        *match = match_pattern(pattern, value, iterpool);
+      if (*match)
+        break;
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+#endif
+
+
+static svn_error_t *
+match_ascii_cert(svn_boolean_t *match,
+                 const char *pattern,
+                 const char *ascii_cert,
+                 apr_pool_t *scratch_pool)
+{
+#ifdef SVN_HAVE_SERF
+  serf_ssl_certificate_t *cert;
+  apr_hash_t *cert_info;
+
+  *match = FALSE;
+
+  SVN_ERR(load_cert(&cert, ascii_cert, scratch_pool, scratch_pool));
+
+  cert_info = serf_ssl_cert_issuer(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(match_cert_info(match, pattern, cert_info, scratch_pool));
+      if (*match)
+        return SVN_NO_ERROR;
+    }
+
+  cert_info = serf_ssl_cert_subject(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(match_cert_info(match, pattern, cert_info, scratch_pool));
+      if (*match)
+        return SVN_NO_ERROR;
+    }
+
+  cert_info = serf_ssl_cert_certificate(cert, scratch_pool);
+  if (cert_info && apr_hash_count(cert_info) > 0)
+    {
+      SVN_ERR(match_cert_info(match, pattern, cert_info, scratch_pool));
+      if (*match)
+        return SVN_NO_ERROR;
+    }
+#else
+  *match = FALSE;
+#endif
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+match_credential(svn_boolean_t *match,
                  const char *cred_kind,
                  const char *realmstring,
-                 apr_hash_t *hash,
+                 apr_array_header_t *patterns,
+                 apr_array_header_t *cred_items,
                  apr_pool_t *scratch_pool)
 {
-  struct svnauth_opt_state *opt_state = baton;
-  apr_array_header_t *sorted_hash_items;
   int i;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  *delete_cred = FALSE;
+  *match = FALSE;
+
+  for (i = 0; i < patterns->nelts; i++)
+    {
+      const char *pattern = APR_ARRAY_IDX(patterns, i, const char *);
+      int j;
+
+      *match = match_pattern(pattern, cred_kind, iterpool);
+      if (!*match)
+        *match = match_pattern(pattern, realmstring, iterpool);
+      if (!*match)
+        {
+          svn_pool_clear(iterpool);
+          for (j = 0; j < cred_items->nelts; j++)
+            {
+              svn_sort__item_t item;
+              const char *key;
+              svn_string_t *value;
+
+              item = APR_ARRAY_IDX(cred_items, j, svn_sort__item_t);
+              key = item.key;
+              value = item.value;
+              if (strcmp(key, AUTHN_PASSWORD_KEY) == 0 ||
+                  strcmp(key, AUTHN_PASSPHRASE_KEY) == 0)
+                continue; /* don't match secrets */
+              else if (strcmp(key, AUTHN_ASCII_CERT_KEY) == 0)
+                SVN_ERR(match_ascii_cert(match, pattern, value->data,
+                                         iterpool));
+              else
+                *match = match_pattern(pattern, value->data, iterpool);
+
+              if (*match)
+                break;
+            }
+        }
+      if (!*match)
+        break;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+list_credential(const char *cred_kind,
+                const char *realmstring,
+                apr_array_header_t *cred_items,
+                svn_boolean_t show_passwords,
+                apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_cmdline_printf(scratch_pool, SEP_STRING));
   SVN_ERR(svn_cmdline_printf(scratch_pool,
                              _("Credential kind: %s\n"), cred_kind));
   SVN_ERR(svn_cmdline_printf(scratch_pool,
-                              _("Authentication realm: %s\n"), realmstring));
+                             _("Authentication realm: %s\n"), realmstring));
 
-  sorted_hash_items = svn_sort__hash(hash, svn_sort_compare_items_lexically,
-                                     scratch_pool);
-  for (i = 0; i < sorted_hash_items->nelts; i++)
+  for (i = 0; i < cred_items->nelts; i++)
     {
       svn_sort__item_t item;
       const char *key;
       svn_string_t *value;
       
-      item = APR_ARRAY_IDX(sorted_hash_items, i, svn_sort__item_t);
+      svn_pool_clear(iterpool);
+      item = APR_ARRAY_IDX(cred_items, i, svn_sort__item_t);
       key = item.key;
       value = item.value;
-      if (!opt_state->show_passwords && strcmp(key, "password") == 0)
-        SVN_ERR(svn_cmdline_printf(scratch_pool, _("%s: [not shown]\n"), key));
-      else if (strcmp(value->data, realmstring) == 0)
+      if (strcmp(value->data, realmstring) == 0)
         continue; /* realm string was already shown above */
+      else if (strcmp(key, AUTHN_PASSWORD_KEY) == 0)
+        {
+          if (show_passwords)
+            SVN_ERR(svn_cmdline_printf(iterpool,
+                                       _("Password: %s\n"), value->data));
+          else
+            SVN_ERR(svn_cmdline_printf(iterpool, _("Password: [not shown]\n")));
+        }
+      else if (strcmp(key, AUTHN_PASSPHRASE_KEY) == 0)
+        {
+          if (show_passwords)
+            SVN_ERR(svn_cmdline_printf(iterpool,
+                                       _("Passphrase: %s\n"), value->data));
+          else
+            SVN_ERR(svn_cmdline_printf(iterpool,
+                                       _("Passphrase: [not shown]\n")));
+        }
+      else if (strcmp(key, AUTHN_PASSTYPE_KEY) == 0)
+        SVN_ERR(svn_cmdline_printf(iterpool, _("Password cache: %s\n"),
+                                   value->data));
+      else if (strcmp(key, AUTHN_USERNAME_KEY) == 0)
+        SVN_ERR(svn_cmdline_printf(iterpool, _("Username: %s\n"), value->data));
+      else if (strcmp(key, AUTHN_ASCII_CERT_KEY) == 0)
+        SVN_ERR(show_ascii_cert(value->data, iterpool));
+      else if (strcmp(key, AUTHN_FAILURES_KEY) == 0)
+        SVN_ERR(show_cert_failures(value->data, iterpool));
       else
-        SVN_ERR(svn_cmdline_printf(scratch_pool, "%s: %s\n", key, value->data));
+        SVN_ERR(svn_cmdline_printf(iterpool, "%s: %s\n", key, value->data));
     }
+  svn_pool_destroy(iterpool);
 
   SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
   return SVN_NO_ERROR;
 }
 
+/* This implements `svn_config_auth_walk_func_t` */
+static svn_error_t *
+walk_credentials(svn_boolean_t *delete_cred,
+                 void *baton,
+                 const char *cred_kind,
+                 const char *realmstring,
+                 apr_hash_t *cred_hash,
+                 apr_pool_t *scratch_pool)
+{
+  struct walk_credentials_baton_t *b = baton;
+  apr_array_header_t *sorted_cred_items;
+
+  *delete_cred = FALSE;
+
+  sorted_cred_items = svn_sort__hash(cred_hash,
+                                     svn_sort_compare_items_lexically,
+                                     scratch_pool);
+  if (b->patterns->nelts > 0)
+    {
+      svn_boolean_t match;
+
+      SVN_ERR(match_credential(&match, cred_kind, realmstring,
+                               b->patterns, sorted_cred_items,
+                               scratch_pool));
+      if (!match)
+        return SVN_NO_ERROR;
+    }
+
+  b->matches++;
+
+  if (b->list)
+    SVN_ERR(list_credential(cred_kind, realmstring, sorted_cred_items,
+                            b->show_passwords, scratch_pool));
+  if (b->delete)
+    {
+      *delete_cred = TRUE;
+      SVN_ERR(svn_cmdline_printf(scratch_pool,
+                                 _("Deleting %s credential for realm '%s'\n"),
+                                 cred_kind, realmstring));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *
@@ -208,35 +793,92 @@ subcommand_list(apr_getopt_t *os, void *
 {
   struct svnauth_opt_state *opt_state = baton;
   const char *config_path;
+  struct walk_credentials_baton_t b;
+
+  b.matches = 0;
+  b.show_passwords = opt_state->show_passwords;
+  b.list = TRUE;
+  b.delete = FALSE;
+  SVN_ERR(parse_args(&b.patterns, os, 0, -1, pool));
 
   SVN_ERR(svn_config_get_user_config_path(&config_path,
                                           opt_state->config_dir, NULL,
                                           pool));
 
-  SVN_ERR(svn_config_walk_auth_data(config_path, list_credentials, opt_state,
+  SVN_ERR(svn_config_walk_auth_data(config_path, walk_credentials, &b,
                                     pool));
+
+  if (b.matches == 0)
+    {
+      if (b.patterns->nelts == 0)
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("Credentials cache in '%s' is empty\n"),
+                                   svn_dirent_local_style(config_path, pool)));
+      else 
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
+                                 _("Credentials cache in '%s' contains "
+                                   "no matching credentials"),
+                                 svn_dirent_local_style(config_path, pool));
+    }
+  else
+    {
+      if (b.patterns->nelts == 0)
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("Credentials cache in '%s' contains %d "
+                                     "credentials\n"),
+                                   svn_dirent_local_style(config_path, pool),
+                                   b.matches));
+      else
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   _("Credentials cache in '%s' contains %d "
+                                     "matching credentials\n"),
+                                   svn_dirent_local_style(config_path, pool),
+                                   b.matches));
+    }
   return SVN_NO_ERROR;
 }
 
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_delete(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnauth_opt_state *opt_state = baton;
+  const char *config_path;
+  struct walk_credentials_baton_t b;
+
+  b.matches = 0;
+  b.show_passwords = opt_state->show_passwords;
+  b.list = FALSE;
+  b.delete = TRUE;
+  SVN_ERR(parse_args(&b.patterns, os, 1, -1, pool));
+
+  SVN_ERR(svn_config_get_user_config_path(&config_path,
+                                          opt_state->config_dir, NULL,
+                                          pool));
 
-/* Report and clear the error ERR, and return EXIT_FAILURE. */
-#define EXIT_ERROR(err)                                                 \
-  svn_cmdline_handle_exit_error(err, NULL, "svnauth: ")
-
-/* 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 'svnauth' 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);                          \
-  } while (0)
+  SVN_ERR(svn_config_walk_auth_data(config_path, walk_credentials, &b, pool));
 
+  if (b.matches == 0)
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
+                             _("Credentials cache in '%s' contains "
+                               "no matching credentials"),
+                             svn_dirent_local_style(config_path, pool));
+  else
+    SVN_ERR(svn_cmdline_printf(pool, _("Deleted %d matching credentials "
+                               "from '%s'\n"), b.matches,
+                               svn_dirent_local_style(config_path, pool)));
 
-static int
-sub_main(int argc, const char *argv[], apr_pool_t *pool)
+  return SVN_NO_ERROR;
+}
+
+
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err;
   const svn_opt_subcommand_desc2_t *subcommand = NULL;
@@ -245,12 +887,13 @@ sub_main(int argc, const char *argv[], a
 
   if (argc <= 1)
     {
-      SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-      return EXIT_FAILURE;
+      SVN_ERR(subcommand_help(NULL, NULL, pool));
+      *exit_code = EXIT_FAILURE;
+      return SVN_NO_ERROR;
     }
 
   /* Parse options. */
-  SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
   os->interleave = 1;
 
   while (1)
@@ -266,8 +909,9 @@ sub_main(int argc, const char *argv[], a
         break;
       else if (apr_err)
         {
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
 
       switch (opt_id) {
@@ -276,7 +920,7 @@ sub_main(int argc, const char *argv[], a
         opt_state.help = TRUE;
         break;
       case opt_config_dir:
-        SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
         opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool);
         break;
       case opt_show_passwords:
@@ -287,8 +931,9 @@ sub_main(int argc, const char *argv[], a
         break;
       default:
         {
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
       }
     }
@@ -317,8 +962,9 @@ sub_main(int argc, const char *argv[], a
             {
               svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                                         _("subcommand argument required\n")));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-              return EXIT_FAILURE;
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
       else
@@ -328,19 +974,20 @@ sub_main(int argc, const char *argv[], a
           if (subcommand == NULL)
             {
               const char *first_arg_utf8;
-              SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
-                                                  first_arg, pool));
+              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
+                                              first_arg, pool));
               svn_error_clear(
                 svn_cmdline_fprintf(stderr, pool,
                                     _("Unknown subcommand: '%s'\n"),
                                     first_arg_utf8));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-              return EXIT_FAILURE;
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
     }
 
-  SVN_INT_ERR(svn_config_ensure(opt_state.config_dir, pool));
+  SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
 
   /* Run the subcommand. */
   err = (*subcommand->cmd_func)(os, &opt_state, pool);
@@ -354,28 +1001,18 @@ sub_main(int argc, const char *argv[], a
           err = svn_error_quick_wrap(err,
                                      _("Try 'svnauth help' for more info"));
         }
-      return EXIT_ERROR(err);
-    }
-  else
-    {
-      /* 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);
-        }
-      return EXIT_SUCCESS;
+      return err;
     }
 
-  return EXIT_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
 int
 main(int argc, const char *argv[])
 {
   apr_pool_t *pool;
-  int exit_code;
+  int exit_code = EXIT_SUCCESS;
+  svn_error_t *err;
 
   /* Initialize the app. */
   if (svn_cmdline_init("svnauth", stderr) != EXIT_SUCCESS)
@@ -386,7 +1023,17 @@ main(int argc, const char *argv[])
    */
   pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
 
-  exit_code = sub_main(argc, argv, pool);
+  err = sub_main(&exit_code, argc, argv, pool);
+
+  /* Flush stdout and report if it fails. It would be flushed on exit anyway
+     but this makes sure that output is not silently lost if it fails. */
+  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+  if (err)
+    {
+      exit_code = EXIT_FAILURE;
+      svn_cmdline_handle_exit_error(err, NULL, "svnauth: ");
+    }
 
   svn_pool_destroy(pool);
   return exit_code;

Modified: subversion/branches/verify-keep-going/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/svndumpfilter/svndumpfilter.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/verify-keep-going/subversion/svndumpfilter/svndumpfilter.c Wed Nov 27 11:52:35 2013
@@ -550,9 +550,9 @@ new_node_record(void **node_baton,
 
   /* Ensure that paths start with a leading '/'. */
   if (node_path[0] != '/')
-    node_path = apr_pstrcat(pool, "/", node_path, (char *)NULL);
+    node_path = apr_pstrcat(pool, "/", node_path, SVN_VA_NULL);
   if (copyfrom_path && copyfrom_path[0] != '/')
-    copyfrom_path = apr_pstrcat(pool, "/", copyfrom_path, (char *)NULL);
+    copyfrom_path = apr_pstrcat(pool, "/", copyfrom_path, SVN_VA_NULL);
 
   nb->do_skip = skip_path(node_path, pb->prefixes,
                           pb->do_exclude, pb->glob);
@@ -1146,6 +1146,7 @@ subcommand_help(apr_getopt_t *os, void *
   struct svndumpfilter_opt_state *opt_state = baton;
   const char *header =
     _("general usage: svndumpfilter SUBCOMMAND [ARGS & OPTIONS ...]\n"
+      "Subversion repository dump filtering tool.\n"
       "Type 'svndumpfilter help <subcommand>' for help on a "
       "specific subcommand.\n"
       "Type 'svndumpfilter --version' to see the program version.\n"
@@ -1176,7 +1177,7 @@ check_lib_versions(void)
     };
   SVN_VERSION_DEFINE(my_version);
 
-  return svn_ver_check_list(&my_version, checklist);
+  return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
 }
 
 
@@ -1354,12 +1355,16 @@ subcommand_include(apr_getopt_t *os, voi
 
 /** Main. **/
 
-int
-main(int argc, const char *argv[])
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err;
   apr_status_t apr_err;
-  apr_pool_t *pool;
 
   const svn_opt_subcommand_desc2_t *subcommand = NULL;
   struct svndumpfilter_opt_state opt_state;
@@ -1368,33 +1373,19 @@ main(int argc, const char *argv[])
   apr_array_header_t *received_opts;
   int i;
 
-
-  /* Initialize the app. */
-  if (svn_cmdline_init("svndumpfilter", stderr) != EXIT_SUCCESS)
-    return EXIT_FAILURE;
-
-  /* Create our top-level pool.  Use a separate mutexless allocator,
-   * given this application is single threaded.
-   */
-  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
   /* Check library versions */
-  err = check_lib_versions();
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+  SVN_ERR(check_lib_versions());
 
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
   /* Initialize the FS library. */
-  err = svn_fs_initialize(pool);
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+  SVN_ERR(svn_fs_initialize(pool));
 
   if (argc <= 1)
     {
-      SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-      svn_pool_destroy(pool);
-      return EXIT_FAILURE;
+      SVN_ERR(subcommand_help(NULL, NULL, pool));
+      *exit_code = EXIT_FAILURE;
+      return SVN_NO_ERROR;
     }
 
   /* Initialize opt_state. */
@@ -1403,9 +1394,7 @@ main(int argc, const char *argv[])
   opt_state.end_revision.kind = svn_opt_revision_unspecified;
 
   /* Parse options. */
-  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
   os->interleave = 1;
   while (1)
@@ -1418,9 +1407,9 @@ main(int argc, const char *argv[])
         break;
       else if (apr_err)
         {
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
 
       /* Stash the option code in an array before parsing it. */
@@ -1461,9 +1450,9 @@ main(int argc, const char *argv[])
           break;
         default:
           {
-            SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-            svn_pool_destroy(pool);
-            return EXIT_FAILURE;
+            SVN_ERR(subcommand_help(NULL, NULL, pool));
+            *exit_code = EXIT_FAILURE;
+            return SVN_NO_ERROR;
           }
         }  /* close `switch' */
     }  /* close `while' */
@@ -1472,10 +1461,10 @@ main(int argc, const char *argv[])
      --drop-all-empty-revs. */
   if (opt_state.drop_empty_revs && opt_state.drop_all_empty_revs)
     {
-      err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
-                             _("--drop-empty-revs cannot be used with "
-                               "--drop-all-empty-revs"));
-      return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+      return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS,
+                              NULL,
+                              _("--drop-empty-revs cannot be used with "
+                                "--drop-all-empty-revs"));
     }
 
   /* If the user asked for help, then the rest of the arguments are
@@ -1507,9 +1496,9 @@ main(int argc, const char *argv[])
               svn_error_clear(svn_cmdline_fprintf
                               (stderr, pool,
                                _("Subcommand argument required\n")));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-              svn_pool_destroy(pool);
-              return EXIT_FAILURE;
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
       else
@@ -1519,18 +1508,16 @@ main(int argc, const char *argv[])
           if (subcommand == NULL)
             {
               const char* first_arg_utf8;
-              if ((err = svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
-                                                 pool)))
-                return svn_cmdline_handle_exit_error(err, pool,
-                                                     "svndumpfilter: ");
+              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
+                                              pool));
 
               svn_error_clear(
                 svn_cmdline_fprintf(stderr, pool,
                                     _("Unknown subcommand: '%s'\n"),
                                     first_arg_utf8));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-              svn_pool_destroy(pool);
-              return EXIT_FAILURE;
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
     }
@@ -1550,10 +1537,10 @@ main(int argc, const char *argv[])
 
           /* Ensure that each prefix is UTF8-encoded, in internal
              style, and absolute. */
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&prefix, os->argv[i], pool));
+          SVN_ERR(svn_utf_cstring_to_utf8(&prefix, os->argv[i], pool));
           prefix = svn_relpath__internal_style(prefix, pool);
           if (prefix[0] != '/')
-            prefix = apr_pstrcat(pool, "/", prefix, (char *)NULL);
+            prefix = apr_pstrcat(pool, "/", prefix, SVN_VA_NULL);
           APR_ARRAY_PUSH(opt_state.prefixes, const char *) = prefix;
         }
 
@@ -1568,12 +1555,12 @@ main(int argc, const char *argv[])
              the targets into an array, because otherwise we wouldn't
              know what delimiter to use for svn_cstring_split().  */
 
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_targets_file,
-                                              opt_state.targets_file, pool));
+          SVN_ERR(svn_utf_cstring_to_utf8(&utf8_targets_file,
+                                          opt_state.targets_file, pool));
 
-          SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_targets_file,
-                                               pool));
-          SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
+          SVN_ERR(svn_stringbuf_from_file2(&buffer, utf8_targets_file,
+                                           pool));
+          SVN_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
 
           targets = apr_array_append(pool,
                          svn_cstring_split(buffer_utf8->data, "\n\r",
@@ -1584,7 +1571,7 @@ main(int argc, const char *argv[])
             {
               const char *prefix = APR_ARRAY_IDX(targets, i, const char *);
               if (prefix[0] != '/')
-                prefix = apr_pstrcat(pool, "/", prefix, (char *)NULL);
+                prefix = apr_pstrcat(pool, "/", prefix, SVN_VA_NULL);
               APR_ARRAY_PUSH(opt_state.prefixes, const char *) = prefix;
             }
         }
@@ -1594,8 +1581,8 @@ main(int argc, const char *argv[])
           svn_error_clear(svn_cmdline_fprintf
                           (stderr, pool,
                            _("\nError: no prefixes supplied.\n")));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
     }
 
@@ -1620,15 +1607,15 @@ main(int argc, const char *argv[])
                                           pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')
-            SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+            SVN_ERR(subcommand_help(NULL, NULL, pool));
           else
             svn_error_clear(svn_cmdline_fprintf
                             (stderr, pool,
                              _("Subcommand '%s' doesn't accept option '%s'\n"
                                "Type 'svndumpfilter help %s' for usage.\n"),
                              subcommand->name, optstr, subcommand->name));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
     }
 
@@ -1645,14 +1632,40 @@ main(int argc, const char *argv[])
                                      _("Try 'svndumpfilter help' for more "
                                        "info"));
         }
-      return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+      return err;
     }
-  else
-    {
-      svn_pool_destroy(pool);
 
-      /* Flush stdout, making sure the user will see any print errors. */
-      SVN_INT_ERR(svn_cmdline_fflush(stdout));
-      return EXIT_SUCCESS;
+  return SVN_NO_ERROR;
+}
+
+int
+main(int argc, const char *argv[])
+{
+  apr_pool_t *pool;
+  int exit_code = EXIT_SUCCESS;
+  svn_error_t *err;
+
+  /* Initialize the app. */
+  if (svn_cmdline_init("svndumpfilter", stderr) != EXIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  /* Create our top-level pool.  Use a separate mutexless allocator,
+   * given this application is single threaded.
+   */
+  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+  err = sub_main(&exit_code, argc, argv, pool);
+
+  /* Flush stdout and report if it fails. It would be flushed on exit anyway
+     but this makes sure that output is not silently lost if it fails. */
+  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+  if (err)
+    {
+      exit_code = EXIT_FAILURE;
+      svn_cmdline_handle_exit_error(err, NULL, "svndumpfilter: ");
     }
+
+  svn_pool_destroy(pool);
+  return exit_code;
 }

Modified: subversion/branches/verify-keep-going/subversion/svnlook/svnlook.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/svnlook/svnlook.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/svnlook/svnlook.c (original)
+++ subversion/branches/verify-keep-going/subversion/svnlook/svnlook.c Wed Nov 27 11:52:35 2013
@@ -34,6 +34,7 @@
 #define APR_WANT_STRFUNC
 #include <apr_want.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_cmdline.h"
 #include "svn_types.h"
@@ -59,8 +60,6 @@
 #include "private/svn_fspath.h"
 #include "private/svn_io_private.h"
 
-#include "svn_private_config.h"
-
 
 /*** Some convenience macros and types. ***/
 
@@ -397,7 +396,7 @@ check_lib_versions(void)
     };
   SVN_VERSION_DEFINE(my_version);
 
-  return svn_ver_check_list(&my_version, checklist);
+  return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
 }
 
 
@@ -1876,7 +1875,8 @@ do_plist(svnlook_ctxt_t *c,
       svn_xml_make_header2(&sb, "UTF-8", pool);
 
       /* "<properties>" */
-      svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "properties", NULL);
+      svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "properties",
+                            SVN_VA_NULL);
     }
 
   if (inherited_props)
@@ -1895,7 +1895,7 @@ do_plist(svnlook_ctxt_t *c,
               svn_xml_make_open_tag(
                 &sb, pool, svn_xml_normal, "target", "path",
                 svn_fspath__canonicalize(elt->path_or_url, pool),
-                NULL);
+                SVN_VA_NULL);
               SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, elt->prop_hash,
                                                        !verbose, TRUE,
                                                        pool));
@@ -1922,19 +1922,19 @@ do_plist(svnlook_ctxt_t *c,
               char *revstr = apr_psprintf(pool, "%ld", c->rev_id);
 
               svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops",
-                                    "rev", revstr, NULL);
+                                    "rev", revstr, SVN_VA_NULL);
             }
           else
             {
               svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops",
-                                    "txn", c->txn_name, NULL);
+                                    "txn", c->txn_name, SVN_VA_NULL);
             }
         }
       else
         {
           /* "<target ...>" */
           svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "target",
-                                "path", path, NULL);
+                                "path", path, SVN_VA_NULL);
         }
     }
 
@@ -1981,7 +1981,7 @@ do_plist(svnlook_ctxt_t *c,
         }
       else if (xml)
         svn_xml_make_open_tag(&sb, pool, svn_xml_self_closing, "property",
-                              "name", pname, NULL);
+                              "name", pname, SVN_VA_NULL);
       else
         printf("  %s\n", pname);
     }
@@ -2213,11 +2213,12 @@ subcommand_help(apr_getopt_t *os, void *
   struct svnlook_opt_state *opt_state = baton;
   const char *header =
     _("general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]\n"
+      "Subversion repository inspection tool.\n"
+      "Type 'svnlook help <subcommand>' for help on a specific subcommand.\n"
+      "Type 'svnlook --version' to see the program version and FS modules.\n"
       "Note: any subcommand which takes the '--revision' and '--transaction'\n"
       "      options will, if invoked without one of those options, act on\n"
       "      the repository's youngest revision.\n"
-      "Type 'svnlook help <subcommand>' for help on a specific subcommand.\n"
-      "Type 'svnlook --version' to see the program version and FS modules.\n"
       "\n"
       "Available subcommands:\n");
 
@@ -2432,12 +2433,16 @@ subcommand_uuid(apr_getopt_t *os, void *
 
 /*** Main. ***/
 
-int
-main(int argc, const char *argv[])
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err;
   apr_status_t apr_err;
-  apr_pool_t *pool;
 
   const svn_opt_subcommand_desc2_t *subcommand = NULL;
   struct svnlook_opt_state opt_state;
@@ -2446,32 +2451,19 @@ main(int argc, const char *argv[])
   apr_array_header_t *received_opts;
   int i;
 
-  /* Initialize the app. */
-  if (svn_cmdline_init("svnlook", stderr) != EXIT_SUCCESS)
-    return EXIT_FAILURE;
-
-  /* Create our top-level pool.  Use a separate mutexless allocator,
-   * given this application is single threaded.
-   */
-  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
   /* Check library versions */
-  err = check_lib_versions();
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+  SVN_ERR(check_lib_versions());
 
   /* Initialize the FS library. */
-  err = svn_fs_initialize(pool);
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+  SVN_ERR(svn_fs_initialize(pool));
 
   if (argc <= 1)
     {
-      SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-      svn_pool_destroy(pool);
-      return EXIT_FAILURE;
+      SVN_ERR(subcommand_help(NULL, NULL, pool));
+      *exit_code = EXIT_FAILURE;
+      return SVN_NO_ERROR;
     }
 
   /* Initialize opt_state. */
@@ -2479,9 +2471,7 @@ main(int argc, const char *argv[])
   opt_state.rev = SVN_INVALID_REVNUM;
 
   /* Parse options. */
-  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
-  if (err)
-    return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
   os->interleave = 1;
   while (1)
@@ -2494,9 +2484,9 @@ main(int argc, const char *argv[])
         break;
       else if (apr_err)
         {
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
 
       /* Stash the option code in an array before parsing it. */
@@ -2511,9 +2501,8 @@ main(int argc, const char *argv[])
             if ((! SVN_IS_VALID_REVNUM(opt_state.rev))
                 || (! digits_end)
                 || *digits_end)
-              SVN_INT_ERR(svn_error_create
-                          (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                           _("Invalid revision number supplied")));
+              return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                      _("Invalid revision number supplied"));
           }
           break;
 
@@ -2560,15 +2549,13 @@ main(int argc, const char *argv[])
             opt_state.limit = strtol(opt_arg, &end, 10);
             if (end == opt_arg || *end != '\0')
               {
-                err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                       _("Non-numeric limit argument given"));
-                return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+                return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                        _("Non-numeric limit argument given"));
               }
             if (opt_state.limit <= 0)
               {
-                err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
                                     _("Argument to --limit must be positive"));
-                return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
               }
           }
           break;
@@ -2614,26 +2601,26 @@ main(int argc, const char *argv[])
           break;
 
         default:
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
 
         }
     }
 
   /* The --transaction and --revision options may not co-exist. */
   if ((opt_state.rev != SVN_INVALID_REVNUM) && opt_state.txn)
-    SVN_INT_ERR(svn_error_create
+    return svn_error_create
                 (SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
                  _("The '--transaction' (-t) and '--revision' (-r) arguments "
-                   "cannot co-exist")));
+                   "cannot co-exist"));
 
   /* The --show-inherited-props and --revprop options may not co-exist. */
   if (opt_state.show_inherited_props && opt_state.revprop)
-    SVN_INT_ERR(svn_error_create
+    return svn_error_create
                 (SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
                  _("Cannot use the '--show-inherited-props' option with the "
-                   "'--revprop' option")));
+                   "'--revprop' option"));
 
   /* 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
@@ -2664,9 +2651,9 @@ main(int argc, const char *argv[])
               svn_error_clear
                 (svn_cmdline_fprintf(stderr, pool,
                                      _("Subcommand argument required\n")));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-              svn_pool_destroy(pool);
-              return EXIT_FAILURE;
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
       else
@@ -2676,15 +2663,13 @@ main(int argc, const char *argv[])
           if (subcommand == NULL)
             {
               const char *first_arg_utf8;
-              err = svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
-                                            pool);
-              if (err)
-                return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
+                                              pool));
               svn_error_clear(
                 svn_cmdline_fprintf(stderr, pool,
                                     _("Unknown subcommand: '%s'\n"),
                                     first_arg_utf8));
-              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+              SVN_ERR(subcommand_help(NULL, NULL, pool));
 
               /* Be kind to people who try 'svnlook verify'. */
               if (strcmp(first_arg_utf8, "verify") == 0)
@@ -2694,9 +2679,8 @@ main(int argc, const char *argv[])
                                         _("Try 'svnadmin verify' instead.\n")));
                 }
 
-
-              svn_pool_destroy(pool);
-              return EXIT_FAILURE;
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
             }
         }
     }
@@ -2715,9 +2699,9 @@ main(int argc, const char *argv[])
       /* Get the repository. */
       if (os->ind < os->argc)
         {
-          SVN_INT_ERR(svn_utf_cstring_to_utf8(&repos_path,
-                                              os->argv[os->ind++],
-                                              pool));
+          SVN_ERR(svn_utf_cstring_to_utf8(&repos_path,
+                                          os->argv[os->ind++],
+                                          pool));
           repos_path = svn_dirent_internal_style(repos_path, pool);
         }
 
@@ -2726,9 +2710,9 @@ main(int argc, const char *argv[])
           svn_error_clear
             (svn_cmdline_fprintf(stderr, pool,
                                  _("Repository argument required\n")));
-          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          SVN_ERR(subcommand_help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
       else if (svn_path_is_url(repos_path))
         {
@@ -2736,8 +2720,8 @@ main(int argc, const char *argv[])
             (svn_cmdline_fprintf(stderr, pool,
                                  _("'%s' is a URL when it should be a path\n"),
                                  repos_path));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
 
       opt_state.repos_path = repos_path;
@@ -2745,8 +2729,7 @@ main(int argc, const char *argv[])
       /* Get next arg (arg1), if any. */
       if (os->ind < os->argc)
         {
-          SVN_INT_ERR(svn_utf_cstring_to_utf8
-                      (&arg1, os->argv[os->ind++], pool));
+          SVN_ERR(svn_utf_cstring_to_utf8(&arg1, os->argv[os->ind++], pool));
           arg1 = svn_dirent_internal_style(arg1, pool);
         }
       opt_state.arg1 = arg1;
@@ -2754,8 +2737,7 @@ main(int argc, const char *argv[])
       /* Get next arg (arg2), if any. */
       if (os->ind < os->argc)
         {
-          SVN_INT_ERR(svn_utf_cstring_to_utf8
-                      (&arg2, os->argv[os->ind++], pool));
+          SVN_ERR(svn_utf_cstring_to_utf8(&arg2, os->argv[os->ind++], pool));
           arg2 = svn_dirent_internal_style(arg2, pool);
         }
       opt_state.arg2 = arg2;
@@ -2781,7 +2763,7 @@ main(int argc, const char *argv[])
                                           pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')
-            SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+            SVN_ERR(subcommand_help(NULL, NULL, pool));
           else
             svn_error_clear
               (svn_cmdline_fprintf
@@ -2789,8 +2771,8 @@ main(int argc, const char *argv[])
                 _("Subcommand '%s' doesn't accept option '%s'\n"
                   "Type 'svnlook help %s' for usage.\n"),
                 subcommand->name, optstr, subcommand->name));
-          svn_pool_destroy(pool);
-          return EXIT_FAILURE;
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
         }
     }
 
@@ -2831,14 +2813,40 @@ main(int argc, const char *argv[])
           err = svn_error_quick_wrap(err,
                                      _("Try 'svnlook help' for more info"));
         }
-      return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
+      return err;
     }
-  else
+
+  return SVN_NO_ERROR;
+}
+
+int
+main(int argc, const char *argv[])
+{
+  apr_pool_t *pool;
+  int exit_code = EXIT_SUCCESS;
+  svn_error_t *err;
+
+  /* Initialize the app. */
+  if (svn_cmdline_init("svnlook", stderr) != EXIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  /* Create our top-level pool.  Use a separate mutexless allocator,
+   * given this application is single threaded.
+   */
+  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+  err = sub_main(&exit_code, argc, argv, pool);
+
+  /* Flush stdout and report if it fails. It would be flushed on exit anyway
+     but this makes sure that output is not silently lost if it fails. */
+  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+  if (err)
     {
-      svn_pool_destroy(pool);
-      /* Ensure everything is printed on stdout, so the user sees any
-         print errors. */
-      SVN_INT_ERR(svn_cmdline_fflush(stdout));
-      return EXIT_SUCCESS;
+      exit_code = EXIT_FAILURE;
+      svn_cmdline_handle_exit_error(err, NULL, "svnlook: ");
     }
+
+  svn_pool_destroy(pool);
+  return exit_code;
 }

Modified: subversion/branches/verify-keep-going/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/svnmucc/svnmucc.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/verify-keep-going/subversion/svnmucc/svnmucc.c Wed Nov 27 11:52:35 2013
@@ -40,6 +40,7 @@
 
 #include <apr_lib.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_client.h"
 #include "svn_cmdline.h"
@@ -58,38 +59,20 @@
 #include "private/svn_ra_private.h"
 #include "private/svn_string_private.h"
 
-#include "svn_private_config.h"
-
-static void handle_error(svn_error_t *err, apr_pool_t *pool)
-{
-  if (err)
-    svn_handle_error2(err, stderr, FALSE, "svnmucc: ");
-  svn_error_clear(err);
-  if (pool)
-    svn_pool_destroy(pool);
-  exit(EXIT_FAILURE);
-}
-
-static apr_pool_t *
-init(const char *application)
+/* Version compatibility check */
+static svn_error_t *
+check_lib_versions(void)
 {
-  svn_error_t *err;
-  const svn_version_checklist_t checklist[] = {
-    {"svn_client", svn_client_version},
-    {"svn_subr", svn_subr_version},
-    {"svn_ra", svn_ra_version},
-    {NULL, NULL}
-  };
+  static const svn_version_checklist_t checklist[] =
+    {
+      { "svn_client", svn_client_version },
+      { "svn_subr",   svn_subr_version },
+      { "svn_ra",     svn_ra_version },
+      { NULL, NULL }
+    };
   SVN_VERSION_DEFINE(my_version);
 
-  if (svn_cmdline_init(application, stderr))
-    exit(EXIT_FAILURE);
-
-  err = svn_ver_check_list(&my_version, checklist);
-  if (err)
-    handle_error(err, NULL);
-
-  return apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+  return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
 }
 
 static svn_error_t *
@@ -175,8 +158,8 @@ struct operation {
 };
 
 
-/* An iterator (for use via apr_table_do) which sets node properties.
-   REC is a pointer to a struct driver_state. */
+/* Set node properties.
+   ... */
 static svn_error_t *
 change_props(const svn_delta_editor_t *editor,
              void *baton,
@@ -918,13 +901,14 @@ sanitize_url(const char *url,
   return svn_uri_canonicalize(url, pool);
 }
 
+/* Print a usage message on STREAM. */
 static void
-usage(apr_pool_t *pool, int exit_val)
+usage(FILE *stream, apr_pool_t *pool)
 {
-  FILE *stream = exit_val == EXIT_SUCCESS ? stdout : stderr;
   svn_error_clear(svn_cmdline_fputs(
-    _("Subversion multiple URL command client\n"
-      "usage: svnmucc ACTION...\n"
+    _("usage: svnmucc ACTION...\n"
+      "Subversion multiple URL command client.\n"
+      "Type 'svnmucc --version' to see the program version.\n"
       "\n"
       "  Perform one or more Subversion repository URL-based ACTIONs, committing\n"
       "  the result as a (single) new revision.\n"
@@ -964,16 +948,13 @@ usage(apr_pool_t *pool, int exit_val)
       "  --no-auth-cache        : do not cache authentication tokens\n"
       "  --version              : print version information\n"),
                   stream, pool));
-  svn_pool_destroy(pool);
-  exit(exit_val);
 }
 
-static void
-insufficient(apr_pool_t *pool)
+static svn_error_t *
+insufficient(void)
 {
-  handle_error(svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
-                                "insufficient arguments"),
-               pool);
+  return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                          "insufficient arguments");
 }
 
 static svn_error_t *
@@ -1040,10 +1021,14 @@ sanitize_log_sources(apr_hash_t *revprop
   return SVN_NO_ERROR;
 }
 
-int
-main(int argc, const char **argv)
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
-  apr_pool_t *pool = init("svnmucc");
   apr_array_header_t *actions = apr_array_make(pool, 1,
                                                sizeof(struct action *));
   const char *anchor = NULL;
@@ -1094,6 +1079,9 @@ main(int argc, const char **argv)
   apr_hash_t *revprops = apr_hash_make(pool);
   int i;
 
+  /* Check library versions */
+  SVN_ERR(check_lib_versions());
+
   config_options = apr_array_make(pool, 0,
                                   sizeof(svn_cmdline__config_argument_t*));
 
@@ -1109,22 +1097,17 @@ main(int argc, const char **argv)
       if (APR_STATUS_IS_EOF(status))
         break;
       if (status != APR_SUCCESS)
-        handle_error(svn_error_wrap_apr(status, "getopt failure"), pool);
+        return svn_error_wrap_apr(status, "getopt failure");
       switch(opt)
         {
         case 'm':
-          err = svn_utf_cstring_to_utf8(&message, arg, pool);
-          if (err)
-            handle_error(err, pool);
+          SVN_ERR(svn_utf_cstring_to_utf8(&message, arg, pool));
           break;
         case 'F':
           {
             const char *arg_utf8;
-            err = svn_utf_cstring_to_utf8(&arg_utf8, arg, pool);
-            if (! err)
-              err = svn_stringbuf_from_file2(&filedata, arg, pool);
-            if (err)
-              handle_error(err, pool);
+            SVN_ERR(svn_utf_cstring_to_utf8(&arg_utf8, arg, pool));
+            SVN_ERR(svn_stringbuf_from_file2(&filedata, arg, pool));
           }
           break;
         case 'u':
@@ -1134,31 +1117,29 @@ main(int argc, const char **argv)
           password = apr_pstrdup(pool, arg);
           break;
         case 'U':
-          err = svn_utf_cstring_to_utf8(&root_url, arg, pool);
-          if (err)
-            handle_error(err, pool);
+          SVN_ERR(svn_utf_cstring_to_utf8(&root_url, arg, pool));
           if (! svn_path_is_url(root_url))
-            handle_error(svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
-                                           "'%s' is not a URL\n", root_url),
-                         pool);
+            return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                     "'%s' is not a URL\n", root_url);
           root_url = sanitize_url(root_url, pool);
           break;
         case 'r':
           {
+            const char *saved_arg = arg;
             char *digits_end = NULL;
+            while (*arg == 'r')
+              arg++;
             base_revision = strtol(arg, &digits_end, 10);
             if ((! SVN_IS_VALID_REVNUM(base_revision))
                 || (! digits_end)
                 || *digits_end)
-              handle_error(svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                            NULL, "Invalid revision number"),
-                           pool);
+              return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                       _("Invalid revision number '%s'"),
+                                       saved_arg);
           }
           break;
         case with_revprop_opt:
-          err = svn_opt_parse_revprop(&revprops, arg, pool);
-          if (err != SVN_NO_ERROR)
-            handle_error(err, pool);
+          SVN_ERR(svn_opt_parse_revprop(&revprops, arg, pool));
           break;
         case 'X':
           extra_args_file = apr_pstrdup(pool, arg);
@@ -1173,40 +1154,31 @@ main(int argc, const char **argv)
           trust_server_cert = TRUE;
           break;
         case config_dir_opt:
-          err = svn_utf_cstring_to_utf8(&config_dir, arg, pool);
-          if (err)
-            handle_error(err, pool);
+          SVN_ERR(svn_utf_cstring_to_utf8(&config_dir, arg, pool));
           break;
         case config_inline_opt:
-          err = svn_utf_cstring_to_utf8(&opt_arg, arg, pool);
-          if (err)
-            handle_error(err, pool);
-
-          err = svn_cmdline__parse_config_option(config_options, opt_arg,
-                                                 pool);
-          if (err)
-            handle_error(err, pool);
+          SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, arg, pool));
+          SVN_ERR(svn_cmdline__parse_config_option(config_options, opt_arg,
+                                                   pool));
           break;
         case no_auth_cache_opt:
           no_auth_cache = TRUE;
           break;
         case version_opt:
-          SVN_INT_ERR(display_version(opts, pool));
-          exit(EXIT_SUCCESS);
-          break;
+          SVN_ERR(display_version(opts, pool));
+          return SVN_NO_ERROR;
         case 'h':
         case '?':
-          usage(pool, EXIT_SUCCESS);
-          break;
+          usage(stdout, pool);
+          return SVN_NO_ERROR;
         }
     }
 
   if (non_interactive && force_interactive)
     {
-      err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                             _("--non-interactive and --force-interactive "
-                               "are mutually exclusive"));
-      return svn_cmdline_handle_exit_error(err, pool, "svnmucc: ");
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--non-interactive and --force-interactive "
+                                "are mutually exclusive"));
     }
   else
     non_interactive = !svn_cmdline__be_interactive(non_interactive,
@@ -1214,16 +1186,13 @@ main(int argc, const char **argv)
 
   if (trust_server_cert && !non_interactive)
     {
-      err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                             _("--trust-server-cert requires "
-                               "--non-interactive"));
-      return svn_cmdline_handle_exit_error(err, pool, "svnmucc: ");
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--trust-server-cert requires "
+                                "--non-interactive"));
     }
 
   /* Make sure we have a log message to use. */
-  err = sanitize_log_sources(revprops, message, filedata);
-  if (err)
-    handle_error(err, pool);
+  SVN_ERR(sanitize_log_sources(revprops, message, filedata));
 
   /* Copy the rest of our command-line arguments to an array,
      UTF-8-ing them along the way. */
@@ -1231,10 +1200,9 @@ main(int argc, const char **argv)
   while (opts->ind < opts->argc)
     {
       const char *arg = opts->argv[opts->ind++];
-      if ((err = svn_utf_cstring_to_utf8(&(APR_ARRAY_PUSH(action_args,
-                                                          const char *)),
-                                         arg, pool)))
-        handle_error(err, pool);
+      SVN_ERR(svn_utf_cstring_to_utf8(&APR_ARRAY_PUSH(action_args,
+                                                      const char *),
+                                      arg, pool));
     }
 
   /* If there are extra arguments in a supplementary file, tack those
@@ -1244,14 +1212,10 @@ main(int argc, const char **argv)
       const char *extra_args_file_utf8;
       svn_stringbuf_t *contents, *contents_utf8;
 
-      err = svn_utf_cstring_to_utf8(&extra_args_file_utf8,
-                                    extra_args_file, pool);
-      if (! err)
-        err = svn_stringbuf_from_file2(&contents, extra_args_file_utf8, pool);
-      if (! err)
-        err = svn_utf_stringbuf_to_utf8(&contents_utf8, contents, pool);
-      if (err)
-        handle_error(err, pool);
+      SVN_ERR(svn_utf_cstring_to_utf8(&extra_args_file_utf8,
+                                      extra_args_file, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&contents, extra_args_file_utf8, pool));
+      SVN_ERR(svn_utf_stringbuf_to_utf8(&contents_utf8, contents, pool));
       svn_cstring_split_append(action_args, contents_utf8->data, "\n\r",
                                FALSE, pool);
     }
@@ -1282,13 +1246,16 @@ main(int argc, const char **argv)
         action->action = ACTION_PROPDEL;
       else if (! strcmp(action_string, "?") || ! strcmp(action_string, "h")
                || ! strcmp(action_string, "help"))
-        usage(pool, EXIT_SUCCESS);
+        {
+          usage(stdout, pool);
+          return SVN_NO_ERROR;
+        }
       else
-        handle_error(svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
-                                       "'%s' is not an action\n",
-                                       action_string), pool);
+        return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                 "'%s' is not an action\n",
+                                 action_string);
       if (++i == action_args->nelts)
-        insufficient(pool);
+        return insufficient();
 
       /* For copies, there should be a revision number next. */
       if (action->action == ACTION_CP)
@@ -1307,12 +1274,12 @@ main(int argc, const char **argv)
 
               action->rev = strtol(rev_str, &end, 0);
               if (*end)
-                handle_error(svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
-                                               "'%s' is not a revision\n",
-                                               rev_str), pool);
+                return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                         "'%s' is not a revision\n",
+                                         rev_str);
             }
           if (++i == action_args->nelts)
-            insufficient(pool);
+            return insufficient();
         }
       else
         {
@@ -1326,7 +1293,7 @@ main(int argc, const char **argv)
             svn_dirent_internal_style(APR_ARRAY_IDX(action_args, i,
                                                     const char *), pool);
           if (++i == action_args->nelts)
-            insufficient(pool);
+            return insufficient();
         }
 
       /* For propset, propsetf, and propdel, a property name (and
@@ -1337,7 +1304,7 @@ main(int argc, const char **argv)
         {
           action->prop_name = APR_ARRAY_IDX(action_args, i, const char *);
           if (++i == action_args->nelts)
-            insufficient(pool);
+            return insufficient();
 
           if (action->action == ACTION_PROPDEL)
             {
@@ -1349,7 +1316,7 @@ main(int argc, const char **argv)
                 svn_string_create(APR_ARRAY_IDX(action_args, i,
                                                 const char *), pool);
               if (++i == action_args->nelts)
-                insufficient(pool);
+                return insufficient();
             }
           else
             {
@@ -1358,12 +1325,10 @@ main(int argc, const char **argv)
                                                         const char *), pool);
 
               if (++i == action_args->nelts)
-                insufficient(pool);
+                return insufficient();
 
-              err = read_propvalue_file(&(action->prop_value),
-                                        propval_file, pool);
-              if (err)
-                handle_error(err, pool);
+              SVN_ERR(read_propvalue_file(&(action->prop_value),
+                                          propval_file, pool));
 
               action->action = ACTION_PROPSET;
             }
@@ -1372,14 +1337,10 @@ main(int argc, const char **argv)
               && svn_prop_needs_translation(action->prop_name))
             {
               svn_string_t *translated_value;
-              err = svn_subst_translate_string2(&translated_value, NULL,
-                                                NULL, action->prop_value, NULL,
-                                                FALSE, pool, pool);
-              if (err)
-                handle_error(
-                    svn_error_quick_wrap(err,
-                                         "Error normalizing property value"),
-                    pool);
+              SVN_ERR_W(svn_subst_translate_string2(&translated_value, NULL,
+                                                    NULL, action->prop_value,
+                                                    NULL, FALSE, pool, pool),
+                        "Error normalizing property value");
               action->prop_value = translated_value;
             }
         }
@@ -1407,14 +1368,14 @@ main(int argc, const char **argv)
           if (! svn_path_is_url(url))
             {
               if (! root_url)
-                handle_error(svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
-                                               "'%s' is not a URL, and "
-                                               "--root-url (-U) not provided\n",
-                                               url), pool);
+                return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                         "'%s' is not a URL, and "
+                                         "--root-url (-U) not provided\n",
+                                         url);
               /* ### These relpaths are already URI-encoded. */
               url = apr_pstrcat(pool, root_url, "/",
                                 svn_relpath_canonicalize(url, pool),
-                                (char *)NULL);
+                                SVN_VA_NULL);
             }
           url = sanitize_url(url, pool);
           action->path[j] = url;
@@ -1429,16 +1390,26 @@ main(int argc, const char **argv)
           if (! anchor)
             anchor = url;
           else
-            anchor = svn_uri_get_longest_ancestor(anchor, url, pool);
+            {
+              anchor = svn_uri_get_longest_ancestor(anchor, url, pool);
+              if (!anchor || !anchor[0])
+                return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                                         "URLs in the action list do not "
+                                         "share a common ancestor");
+            }
 
           if ((++i == action_args->nelts) && (j + 1 < num_url_args))
-            insufficient(pool);
+            return insufficient();
         }
       APR_ARRAY_PUSH(actions, struct action *) = action;
     }
 
   if (! actions->nelts)
-    usage(pool, EXIT_FAILURE);
+    {
+      *exit_code = EXIT_FAILURE;
+      usage(stderr, pool);
+      return SVN_NO_ERROR;
+    }
 
   if ((err = execute(actions, anchor, revprops, username, password,
                      config_dir, config_options, non_interactive,
@@ -1449,12 +1420,40 @@ main(int argc, const char **argv)
                                    _("Authentication failed and interactive"
                                      " prompting is disabled; see the"
                                      " --force-interactive option"));
-      handle_error(err, pool);
+      return err;
     }
 
-  /* Ensure that stdout is flushed, so the user will see all results. */
-  svn_error_clear(svn_cmdline_fflush(stdout));
+  return SVN_NO_ERROR;
+}
+
+int
+main(int argc, const char *argv[])
+{
+  apr_pool_t *pool;
+  int exit_code = EXIT_SUCCESS;
+  svn_error_t *err;
+
+  /* Initialize the app. */
+  if (svn_cmdline_init("svnmucc", stderr) != EXIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  /* Create our top-level pool.  Use a separate mutexless allocator,
+   * given this application is single threaded.
+   */
+  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+  err = sub_main(&exit_code, argc, argv, pool);
+
+  /* Flush stdout and report if it fails. It would be flushed on exit anyway
+     but this makes sure that output is not silently lost if it fails. */
+  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+  if (err)
+    {
+      exit_code = EXIT_FAILURE;
+      svn_cmdline_handle_exit_error(err, NULL, "svnmucc: ");
+    }
 
   svn_pool_destroy(pool);
-  return EXIT_SUCCESS;
+  return exit_code;
 }

Modified: subversion/branches/verify-keep-going/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/svnrdump/dump_editor.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/verify-keep-going/subversion/svnrdump/dump_editor.c Wed Nov 27 11:52:35 2013
@@ -22,6 +22,7 @@
  * ====================================================================
  */
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_pools.h"
 #include "svn_repos.h"