~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/svnadmin/svnadmin.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
#include "svn_cache_config.h"
40
40
#include "svn_version.h"
41
41
#include "svn_props.h"
 
42
#include "svn_sorts.h"
42
43
#include "svn_time.h"
43
44
#include "svn_user.h"
44
45
#include "svn_xml.h"
45
46
 
 
47
#include "private/svn_cmdline_private.h"
46
48
#include "private/svn_opt_private.h"
 
49
#include "private/svn_sorts_private.h"
47
50
#include "private/svn_subr_private.h"
48
 
#include "private/svn_cmdline_private.h"
49
51
 
50
52
#include "svn_private_config.h"
51
53
 
52
54
 
53
55
/*** Code. ***/
54
56
 
 
57
/* FSFS format 7's "block-read" feature performs poorly with small caches.
 
58
 * Enable it only if caches above this threshold have been configured.
 
59
 * The current threshold is 64MB. */
 
60
#define BLOCK_READ_CACHE_THRESHOLD (0x40 * 0x100000)
 
61
 
55
62
/* A flag to see if we've been cancelled by the client or not. */
56
63
static volatile sig_atomic_t cancelled = FALSE;
57
64
 
100
107
{
101
108
  if (! err)
102
109
    return;
103
 
  svn_handle_error2(err, stderr, FALSE, "svnadmin: ");
 
110
  svn_handle_warning2(stderr, err, "svnadmin: ");
104
111
}
105
112
 
106
113
 
111
118
           const char *path,
112
119
           apr_pool_t *pool)
113
120
{
 
121
  /* Enable the "block-read" feature (where it applies)? */
 
122
  svn_boolean_t use_block_read
 
123
    = svn_cache_config_get()->cache_size > BLOCK_READ_CACHE_THRESHOLD;
 
124
 
114
125
  /* construct FS configuration parameters: enable caches for r/o data */
115
126
  apr_hash_t *fs_config = apr_hash_make(pool);
116
127
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS, "1");
118
129
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "2");
119
130
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NS,
120
131
                           svn_uuid_generate(pool));
 
132
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
 
133
                           use_block_read ? "1" : "0");
121
134
 
122
135
  /* now, open the requested repository */
123
 
  SVN_ERR(svn_repos_open2(repos, path, fs_config, pool));
 
136
  SVN_ERR(svn_repos_open3(repos, path, fs_config, pool, pool));
124
137
  svn_fs_set_warning_func(svn_repos_fs(*repos), warning_func, NULL);
125
138
  return SVN_NO_ERROR;
126
139
}
150
163
static svn_opt_subcommand_t
151
164
  subcommand_crashtest,
152
165
  subcommand_create,
 
166
  subcommand_delrevprop,
153
167
  subcommand_deltify,
154
168
  subcommand_dump,
155
169
  subcommand_freeze,
156
170
  subcommand_help,
157
171
  subcommand_hotcopy,
 
172
  subcommand_info,
158
173
  subcommand_load,
159
174
  subcommand_list_dblogs,
160
175
  subcommand_list_unused_dblogs,
176
191
  {
177
192
    svnadmin__version = SVN_OPT_FIRST_LONGOPT_ID,
178
193
    svnadmin__incremental,
 
194
    svnadmin__keep_going,
179
195
    svnadmin__deltas,
180
196
    svnadmin__ignore_uuid,
181
197
    svnadmin__force_uuid,
186
202
    svnadmin__config_dir,
187
203
    svnadmin__bypass_hooks,
188
204
    svnadmin__bypass_prop_validation,
 
205
    svnadmin__ignore_dates,
189
206
    svnadmin__use_pre_commit_hook,
190
207
    svnadmin__use_post_commit_hook,
191
208
    svnadmin__use_pre_revprop_change_hook,
195
212
    svnadmin__pre_1_4_compatible,
196
213
    svnadmin__pre_1_5_compatible,
197
214
    svnadmin__pre_1_6_compatible,
198
 
    svnadmin__compatible_version
 
215
    svnadmin__compatible_version,
 
216
    svnadmin__check_normalization,
 
217
    svnadmin__metadata_only
199
218
  };
200
219
 
201
220
/* Option codes and descriptions.
231
250
    {"bypass-prop-validation",  svnadmin__bypass_prop_validation, 0,
232
251
     N_("bypass property validation logic")},
233
252
 
 
253
    {"ignore-dates",  svnadmin__ignore_dates, 0,
 
254
     N_("ignore revision datestamps found in the stream")},
 
255
 
234
256
    {"quiet",         'q', 0,
235
 
     N_("no progress (only errors) to stderr")},
 
257
     N_("no progress (only errors to stderr)")},
236
258
 
237
259
    {"ignore-uuid",   svnadmin__ignore_uuid, 0,
238
260
     N_("ignore any repos UUID found in the stream")},
241
263
     N_("set repos UUID to that found in stream, if any")},
242
264
 
243
265
    {"fs-type",       svnadmin__fs_type, 1,
244
 
     N_("type of repository: 'fsfs' (default) or 'bdb'")},
 
266
     N_("type of repository:\n"
 
267
        "                             'fsfs' (default), 'bdb' or 'fsx'\n"
 
268
        "                             CAUTION: FSX is for EXPERIMENTAL use only!")},
245
269
 
246
270
    {"parent-dir",    svnadmin__parent_dir, 1,
247
271
     N_("load at specified directory in repository")},
284
308
    {"pre-1.6-compatible",     svnadmin__pre_1_6_compatible, 0,
285
309
     N_("deprecated; see --compatible-version")},
286
310
 
 
311
    {"keep-going",    svnadmin__keep_going, 0,
 
312
     N_("continue verification after detecting a corruption")},
 
313
 
287
314
    {"memory-cache-size",     'M', 1,
288
315
     N_("size of the extra in-memory cache in MB used to\n"
289
316
        "                             minimize redundant operations. Default: 16.\n"
295
322
 
296
323
    {"file", 'F', 1, N_("read repository paths from file ARG")},
297
324
 
 
325
    {"check-normalization", svnadmin__check_normalization, 0,
 
326
     N_("report any names within the same directory or\n"
 
327
        "                             svn:mergeinfo property value that differ only\n"
 
328
        "                             in character representation, but are otherwise\n"
 
329
        "                             identical")},
 
330
 
 
331
    {"metadata-only", svnadmin__metadata_only, 0,
 
332
     N_("verify metadata only (ignored for BDB),\n"
 
333
        "                             checking against external corruption in\n"
 
334
        "                             Subversion 1.9+ format repositories.\n")},
 
335
 
298
336
    {NULL}
299
337
  };
300
338
 
319
357
    svnadmin__pre_1_6_compatible
320
358
    } },
321
359
 
 
360
  {"delrevprop", subcommand_delrevprop, {0}, N_
 
361
   ("usage: 1. svnadmin delrevprop REPOS_PATH -r REVISION NAME\n"
 
362
    "                   2. svnadmin delrevprop REPO_PATH -t TXN NAME\n\n"
 
363
    "1. Delete the property NAME on revision REVISION.\n\n"
 
364
    "Use --use-pre-revprop-change-hook/--use-post-revprop-change-hook to\n"
 
365
    "trigger the revision property-related hooks (for example, if you want\n"
 
366
    "an email notification sent from your post-revprop-change hook).\n\n"
 
367
    "NOTE: Revision properties are not versioned, so this command will\n"
 
368
    "irreversibly destroy the previous value of the property.\n\n"
 
369
    "2. Delete the property NAME on transaction TXN.\n"),
 
370
   {'r', 't', svnadmin__use_pre_revprop_change_hook,
 
371
    svnadmin__use_post_revprop_change_hook} },
 
372
 
322
373
  {"deltify", subcommand_deltify, {0}, N_
323
374
   ("usage: svnadmin deltify [-r LOWER[:UPPER]] REPOS_PATH\n\n"
324
375
    "Run over the requested revision range, performing predecessor delti-\n"
361
412
    "Make a hot copy of a repository.\n"
362
413
    "If --incremental is passed, data which already exists at the destination\n"
363
414
    "is not copied again.  Incremental mode is implemented for FSFS repositories.\n"),
364
 
   {svnadmin__clean_logs, svnadmin__incremental} },
 
415
   {svnadmin__clean_logs, svnadmin__incremental, 'q'} },
 
416
 
 
417
  {"info", subcommand_info, {0}, N_
 
418
   ("usage: svnadmin info REPOS_PATH\n\n"
 
419
    "Print information about the repository at REPOS_PATH.\n"),
 
420
   {0} },
365
421
 
366
422
  {"list-dblogs", subcommand_list_dblogs, {0}, N_
367
423
   ("usage: svnadmin list-dblogs REPOS_PATH\n\n"
384
440
    "If --revision is specified, limit the loaded revisions to only those\n"
385
441
    "in the dump stream whose revision numbers match the specified range.\n"),
386
442
   {'q', 'r', svnadmin__ignore_uuid, svnadmin__force_uuid,
 
443
    svnadmin__ignore_dates,
387
444
    svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook,
388
445
    svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} },
389
446
 
409
466
   ("usage: svnadmin pack REPOS_PATH\n\n"
410
467
    "Possibly compact the repository into a more efficient storage model.\n"
411
468
    "This may not apply to all repositories, in which case, exit.\n"),
412
 
   {'q'} },
 
469
   {'q', 'M'} },
413
470
 
414
471
  {"recover", subcommand_recover, {0}, N_
415
472
   ("usage: svnadmin recover REPOS_PATH\n\n"
442
499
   {'r', svnadmin__bypass_hooks} },
443
500
 
444
501
  {"setrevprop", subcommand_setrevprop, {0}, N_
445
 
   ("usage: svnadmin setrevprop REPOS_PATH -r REVISION NAME FILE\n\n"
446
 
    "Set the property NAME on revision REVISION to the contents of FILE. Use\n"
447
 
    "--use-pre-revprop-change-hook/--use-post-revprop-change-hook to trigger\n"
448
 
    "the revision property-related hooks (for example, if you want an email\n"
449
 
    "notification sent from your post-revprop-change hook).\n\n"
 
502
   ("usage: 1. svnadmin setrevprop REPOS_PATH -r REVISION NAME FILE\n"
 
503
    "                   2. svnadmin setrevprop REPOS_PATH -t TXN NAME FILE\n\n"
 
504
    "1. Set the property NAME on revision REVISION to the contents of FILE.\n\n"
 
505
    "Use --use-pre-revprop-change-hook/--use-post-revprop-change-hook to\n"
 
506
    "trigger the revision property-related hooks (for example, if you want\n"
 
507
    "an email notification sent from your post-revprop-change hook).\n\n"
450
508
    "NOTE: Revision properties are not versioned, so this command will\n"
451
 
    "overwrite the previous value of the property.\n"),
452
 
   {'r', svnadmin__use_pre_revprop_change_hook,
 
509
    "overwrite the previous value of the property.\n\n"
 
510
    "2. Set the property NAME on transaction TXN to the contents of FILE.\n"),
 
511
   {'r', 't', svnadmin__use_pre_revprop_change_hook,
453
512
    svnadmin__use_post_revprop_change_hook} },
454
513
 
455
514
  {"setuuid", subcommand_setuuid, {0}, N_
482
541
  {"verify", subcommand_verify, {0}, N_
483
542
   ("usage: svnadmin verify REPOS_PATH\n\n"
484
543
    "Verify the data stored in the repository.\n"),
485
 
  {'t', 'r', 'q', 'M'} },
 
544
   {'t', 'r', 'q', svnadmin__keep_going, 'M',
 
545
    svnadmin__check_normalization, svnadmin__metadata_only} },
486
546
 
487
547
  { NULL, NULL, {0}, NULL, {0} }
488
548
};
493
553
{
494
554
  const char *repository_path;
495
555
  const char *fs_type;                              /* --fs-type */
496
 
  svn_boolean_t pre_1_4_compatible;                 /* --pre-1.4-compatible */
497
 
  svn_boolean_t pre_1_5_compatible;                 /* --pre-1.5-compatible */
498
 
  svn_boolean_t pre_1_6_compatible;                 /* --pre-1.6-compatible */
499
556
  svn_version_t *compatible_version;                /* --compatible-version */
500
557
  svn_opt_revision_t start_revision, end_revision;  /* -r X[:Y] */
501
558
  const char *txn_id;                               /* -t TXN */
513
570
  svn_boolean_t clean_logs;                         /* --clean-logs */
514
571
  svn_boolean_t bypass_hooks;                       /* --bypass-hooks */
515
572
  svn_boolean_t wait;                               /* --wait */
 
573
  svn_boolean_t keep_going;                         /* --keep-going */
 
574
  svn_boolean_t check_normalization;                /* --check-normalization */
 
575
  svn_boolean_t metadata_only;                      /* --metadata-only */
516
576
  svn_boolean_t bypass_prop_validation;             /* --bypass-prop-validation */
 
577
  svn_boolean_t ignore_dates;                       /* --ignore-dates */
517
578
  enum svn_repos_load_uuid uuid_action;             /* --ignore-uuid,
518
579
                                                       --force-uuid */
519
580
  apr_uint64_t memory_cache_size;                   /* --memory-cache-size M */
520
 
  const char *parent_dir;
 
581
  const char *parent_dir;                           /* --parent-dir */
521
582
  svn_stringbuf_t *filedata;                        /* --file */
522
583
 
523
584
  const char *config_dir;    /* Overriding Configuration Directory */
564
625
  SVN_ERR(svn_utf_cstring_to_utf8(&path, arg, pool));
565
626
  if (svn_path_is_url(path))
566
627
    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
567
 
                             "Path '%s' is not a local path", path);
 
628
                             _("Path '%s' is not a local path"), path);
568
629
  *dirent = svn_dirent_internal_style(path, pool);
569
630
  return SVN_NO_ERROR;
570
631
}
593
654
 
594
655
  if ((min_expected >= 0) && (num_args < min_expected))
595
656
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0,
596
 
                            "Not enough arguments");
 
657
                            _("Not enough arguments"));
597
658
  if ((max_expected >= 0) && (num_args > max_expected))
598
659
    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
599
 
                            "Too many arguments");
 
660
                            _("Too many arguments"));
600
661
  if (args)
601
662
    {
602
663
      *args = apr_array_make(pool, num_args, sizeof(const char *));
611
672
}
612
673
 
613
674
 
 
675
/* This implements 'svn_error_malfunction_handler_t. */
 
676
static svn_error_t *
 
677
crashtest_malfunction_handler(svn_boolean_t can_return,
 
678
                              const char *file,
 
679
                              int line,
 
680
                              const char *expr)
 
681
{
 
682
  abort();
 
683
  return SVN_NO_ERROR; /* Not reached. */
 
684
}
 
685
 
614
686
/* This implements `svn_opt_subcommand_t'. */
615
687
static svn_error_t *
616
688
subcommand_crashtest(apr_getopt_t *os, void *baton, apr_pool_t *pool)
618
690
  struct svnadmin_opt_state *opt_state = baton;
619
691
  svn_repos_t *repos;
620
692
 
 
693
  (void)svn_error_set_malfunction_handler(crashtest_malfunction_handler);
621
694
  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
 
695
  SVN_ERR(svn_cmdline_printf(pool,
 
696
                             _("Successfully opened repository '%s'.\n"
 
697
                               "Will now crash to simulate a crashing "
 
698
                               "server process.\n"),
 
699
                             svn_dirent_local_style(opt_state->repository_path,
 
700
                                                    pool)));
622
701
  SVN_ERR_MALFUNCTION();
623
702
 
624
703
  /* merely silence a compiler warning (this will never be executed) */
662
741
      svn_hash_sets(fs_config, SVN_FS_CONFIG_FS_TYPE, opt_state->fs_type);
663
742
    }
664
743
 
665
 
  /* Prior to 1.8, we had explicit options to specify compatibility
666
 
     with a handful of prior Subversion releases. */
667
 
  if (opt_state->pre_1_4_compatible)
668
 
    svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE, "1");
669
 
  if (opt_state->pre_1_5_compatible)
670
 
    svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE, "1");
671
 
  if (opt_state->pre_1_6_compatible)
672
 
    svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_6_COMPATIBLE, "1");
673
 
 
674
 
  /* In 1.8, we figured out that we didn't have to keep extending this
675
 
     madness indefinitely. */
676
744
  if (opt_state->compatible_version)
677
745
    {
678
746
      if (! svn_version__at_least(opt_state->compatible_version, 1, 4, 0))
683
751
        svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_6_COMPATIBLE, "1");
684
752
      if (! svn_version__at_least(opt_state->compatible_version, 1, 8, 0))
685
753
        svn_hash_sets(fs_config, SVN_FS_CONFIG_PRE_1_8_COMPATIBLE, "1");
 
754
      /* In 1.9, we figured out that we didn't have to keep extending this
 
755
         madness indefinitely. */
 
756
      svn_hash_sets(fs_config, SVN_FS_CONFIG_COMPATIBLE_VERSION,
 
757
                    apr_psprintf(pool, "%d.%d.%d%s%s",
 
758
                                 opt_state->compatible_version->major,
 
759
                                 opt_state->compatible_version->minor,
 
760
                                 opt_state->compatible_version->patch,
 
761
                                 opt_state->compatible_version->tag
 
762
                                 ? "-" : "",
 
763
                                 opt_state->compatible_version->tag
 
764
                                 ? opt_state->compatible_version->tag : ""));
686
765
    }
687
766
 
688
 
  if (opt_state->compatible_version
689
 
      && ! svn_version__at_least(opt_state->compatible_version, 1, 1, 0)
690
 
      /* ### TODO: this NULL check hard-codes knowledge of the library's
691
 
                   default fs-type value */
692
 
      && (opt_state->fs_type == NULL
693
 
          || !strcmp(opt_state->fs_type, SVN_FS_TYPE_FSFS)))
 
767
  if (opt_state->compatible_version)
694
768
    {
695
 
      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
696
 
                              _("Repositories compatible with 1.0.x must use "
697
 
                                "--fs-type=bdb"));
 
769
      if (! svn_version__at_least(opt_state->compatible_version, 1, 1, 0)
 
770
          /* ### TODO: this NULL check hard-codes knowledge of the library's
 
771
                       default fs-type value */
 
772
          && (opt_state->fs_type == NULL
 
773
              || !strcmp(opt_state->fs_type, SVN_FS_TYPE_FSFS)))
 
774
        {
 
775
          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
776
                                  _("Repositories compatible with 1.0.x must "
 
777
                                    "use --fs-type=bdb"));
 
778
        }
 
779
 
 
780
      if (! svn_version__at_least(opt_state->compatible_version, 1, 9, 0)
 
781
          && opt_state->fs_type && !strcmp(opt_state->fs_type, SVN_FS_TYPE_FSX))
 
782
        {
 
783
          return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
784
                                   _("Repositories compatible with 1.8.x or "
 
785
                                     "earlier cannot use --fs-type=%s"),
 
786
                                   SVN_FS_TYPE_FSX);
 
787
        }
698
788
    }
699
789
 
700
790
  SVN_ERR(svn_repos_create(&repos, opt_state->repository_path,
756
846
  return SVN_NO_ERROR;
757
847
}
758
848
 
 
849
/* Structure for errors encountered during 'svnadmin verify --keep-going'. */
 
850
struct verification_error
 
851
{
 
852
  svn_revnum_t rev;
 
853
  svn_error_t *err;
 
854
};
 
855
 
 
856
/* Pool cleanup function to clear an svn_error_t *. */
 
857
static apr_status_t
 
858
err_cleanup(void *data)
 
859
{
 
860
  svn_error_t *err = data;
 
861
 
 
862
  svn_error_clear(err);
 
863
 
 
864
  return APR_SUCCESS;
 
865
}
 
866
 
 
867
struct repos_verify_callback_baton
 
868
{
 
869
  /* Should we continue after receiving a first verification error? */
 
870
  svn_boolean_t keep_going;
 
871
 
 
872
  /* List of errors encountered during 'svnadmin verify --keep-going'. */
 
873
  apr_array_header_t *error_summary;
 
874
 
 
875
  /* Pool for data collected during callback invocations. */
 
876
  apr_pool_t *result_pool;
 
877
};
 
878
 
 
879
/* Implementation of svn_repos_verify_callback_t to handle errors coming
 
880
   from svn_repos_verify_fs3(). */
 
881
static svn_error_t *
 
882
repos_verify_callback(void *baton,
 
883
                      svn_revnum_t revision,
 
884
                      svn_error_t *verify_err,
 
885
                      apr_pool_t *scratch_pool)
 
886
{
 
887
  struct repos_verify_callback_baton *b = baton;
 
888
 
 
889
  if (revision == SVN_INVALID_REVNUM)
 
890
    {
 
891
      SVN_ERR(svn_cmdline_fputs(_("* Error verifying repository metadata.\n"),
 
892
                                stderr, scratch_pool));
 
893
    }
 
894
  else
 
895
    {
 
896
      SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
 
897
                                  _("* Error verifying revision %ld.\n"),
 
898
                                  revision));
 
899
    }
 
900
 
 
901
  if (b->keep_going)
 
902
    {
 
903
      struct verification_error *verr;
 
904
 
 
905
      svn_handle_error2(verify_err, stderr, FALSE, "svnadmin: ");
 
906
 
 
907
      /* Remember the error in B->ERROR_SUMMARY. */
 
908
      verr = apr_palloc(b->result_pool, sizeof(*verr));
 
909
      verr->rev = revision;
 
910
      verr->err = svn_error_dup(verify_err);
 
911
      apr_pool_cleanup_register(b->result_pool, verr->err, err_cleanup,
 
912
                                apr_pool_cleanup_null);
 
913
      APR_ARRAY_PUSH(b->error_summary, struct verification_error *) = verr;
 
914
 
 
915
      return SVN_NO_ERROR;
 
916
    }
 
917
  else
 
918
    return svn_error_trace(svn_error_dup(verify_err));
 
919
}
759
920
 
760
921
/* Implementation of svn_repos_notify_func_t to wrap the output to a
761
 
   response stream for svn_repos_dump_fs2() and svn_repos_verify_fs() */
 
922
   response stream for svn_repos_dump_fs2(), svn_repos_verify_fs(),
 
923
   svn_repos_hotcopy3() and others. */
762
924
static void
763
925
repos_notify_handler(void *baton,
764
926
                     const svn_repos_notify_t *notify,
765
927
                     apr_pool_t *scratch_pool)
766
928
{
767
929
  svn_stream_t *feedback_stream = baton;
768
 
  apr_size_t len;
769
930
 
770
931
  switch (notify->action)
771
932
  {
789
950
 
790
951
    case svn_repos_notify_verify_rev_structure:
791
952
      if (notify->revision == SVN_INVALID_REVNUM)
792
 
        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
953
        svn_error_clear(svn_stream_puts(feedback_stream,
793
954
                                _("* Verifying repository metadata ...\n")));
794
955
      else
795
956
        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
877
1038
      return;
878
1039
 
879
1040
    case svn_repos_notify_load_node_done:
880
 
      svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
881
 
                                        "%s", _(" done.\n")));
 
1041
      svn_error_clear(svn_stream_puts(feedback_stream, _(" done.\n")));
882
1042
      return;
883
1043
 
884
1044
    case svn_repos_notify_load_copied_node:
885
 
      len = 9;
886
 
      svn_error_clear(svn_stream_write(feedback_stream, "COPIED...", &len));
 
1045
      svn_error_clear(svn_stream_puts(feedback_stream, "COPIED..."));
887
1046
      return;
888
1047
 
889
1048
    case svn_repos_notify_load_txn_start:
911
1070
      return;
912
1071
 
913
1072
    case svn_repos_notify_recover_start:
914
 
      svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1073
      svn_error_clear(svn_stream_puts(feedback_stream,
915
1074
                             _("Repository lock acquired.\n"
916
1075
                               "Please wait; recovering the"
917
1076
                               " repository may take some time...\n")));
924
1083
                               " repository may take some time...\n")));
925
1084
      return;
926
1085
 
 
1086
    case svn_repos_notify_pack_revprops:
 
1087
      {
 
1088
        const char *shardstr = apr_psprintf(scratch_pool,
 
1089
                                            "%" APR_INT64_T_FMT,
 
1090
                                            notify->shard);
 
1091
        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1092
                              _("Packing revision properties"
 
1093
                                " in shard %s..."),
 
1094
                              shardstr));
 
1095
        return;
 
1096
      }
 
1097
 
 
1098
    case svn_repos_notify_cleanup_revprops:
 
1099
      {
 
1100
        const char *shardstr = apr_psprintf(scratch_pool,
 
1101
                                            "%" APR_INT64_T_FMT,
 
1102
                                            notify->shard);
 
1103
        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1104
                              _("Removing non-packed revision properties"
 
1105
                                " in shard %s..."),
 
1106
                              shardstr));
 
1107
        return;
 
1108
      }
 
1109
 
 
1110
    case svn_repos_notify_format_bumped:
 
1111
      svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1112
                            _("Bumped repository format to %ld\n"),
 
1113
                            notify->revision));
 
1114
      return;
 
1115
 
 
1116
    case svn_repos_notify_hotcopy_rev_range:
 
1117
      if (notify->start_revision == notify->end_revision)
 
1118
        {
 
1119
          svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1120
                                            _("* Copied revision %ld.\n"),
 
1121
                                            notify->start_revision));
 
1122
        }
 
1123
      else
 
1124
        {
 
1125
          svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
 
1126
                               _("* Copied revisions from %ld to %ld.\n"),
 
1127
                               notify->start_revision, notify->end_revision));
 
1128
        }
 
1129
 
927
1130
    default:
928
1131
      return;
929
1132
  }
980
1183
  svn_stream_t *stdout_stream;
981
1184
  svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
982
1185
  svn_revnum_t youngest;
983
 
  svn_stream_t *progress_stream = NULL;
 
1186
  svn_stream_t *feedback_stream = NULL;
984
1187
 
985
1188
  /* Expect no more arguments. */
986
1189
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1014
1217
 
1015
1218
  /* Progress feedback goes to STDERR, unless they asked to suppress it. */
1016
1219
  if (! opt_state->quiet)
1017
 
    progress_stream = recode_stream_create(stderr, pool);
 
1220
    feedback_stream = recode_stream_create(stderr, pool);
1018
1221
 
1019
1222
  SVN_ERR(svn_repos_dump_fs3(repos, stdout_stream, lower, upper,
1020
1223
                             opt_state->incremental, opt_state->use_deltas,
1021
1224
                             !opt_state->quiet ? repos_notify_handler : NULL,
1022
 
                             progress_stream, check_cancel, NULL, pool));
 
1225
                             feedback_stream, check_cancel, NULL, pool));
1023
1226
 
1024
1227
  return SVN_NO_ERROR;
1025
1228
}
1079
1282
    }
1080
1283
  else
1081
1284
    {
 
1285
      const char *utf8;
1082
1286
      /* All repositories in filedata. */
1083
 
      paths = svn_cstring_split(opt_state->filedata->data, "\n", FALSE, pool);
 
1287
      SVN_ERR(svn_utf_cstring_to_utf8(&utf8, opt_state->filedata->data, pool));
 
1288
      paths = svn_cstring_split(utf8, "\r\n", FALSE, pool);
1084
1289
    }
1085
1290
 
1086
1291
  b.command = APR_ARRAY_IDX(args, 0, const char *);
1106
1311
  struct svnadmin_opt_state *opt_state = baton;
1107
1312
  const char *header =
1108
1313
    _("general usage: svnadmin SUBCOMMAND REPOS_PATH  [ARGS & OPTIONS ...]\n"
 
1314
      "Subversion repository administration tool.\n"
1109
1315
      "Type 'svnadmin help <subcommand>' for help on a specific subcommand.\n"
1110
1316
      "Type 'svnadmin --version' to see the program version and FS modules.\n"
1111
1317
      "\n"
1165
1371
  struct svnadmin_opt_state *opt_state = baton;
1166
1372
  svn_repos_t *repos;
1167
1373
  svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
1168
 
  svn_stream_t *stdin_stream, *stdout_stream = NULL;
 
1374
  svn_stream_t *stdin_stream;
 
1375
  svn_stream_t *feedback_stream = NULL;
1169
1376
 
1170
1377
  /* Expect no more arguments. */
1171
1378
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1199
1406
 
1200
1407
  /* Progress feedback goes to STDOUT, unless they asked to suppress it. */
1201
1408
  if (! opt_state->quiet)
1202
 
    stdout_stream = recode_stream_create(stdout, pool);
 
1409
    feedback_stream = recode_stream_create(stdout, pool);
1203
1410
 
1204
 
  err = svn_repos_load_fs4(repos, stdin_stream, lower, upper,
 
1411
  err = svn_repos_load_fs5(repos, stdin_stream, lower, upper,
1205
1412
                           opt_state->uuid_action, opt_state->parent_dir,
1206
1413
                           opt_state->use_pre_commit_hook,
1207
1414
                           opt_state->use_post_commit_hook,
1208
1415
                           !opt_state->bypass_prop_validation,
 
1416
                           opt_state->ignore_dates,
1209
1417
                           opt_state->quiet ? NULL : repos_notify_handler,
1210
 
                           stdout_stream, check_cancel, NULL, pool);
 
1418
                           feedback_stream, check_cancel, NULL, pool);
1211
1419
  if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
1212
1420
    return svn_error_quick_wrap(err,
1213
1421
                                _("Invalid property value found in "
1254
1462
  svn_repos_t *repos;
1255
1463
  svn_error_t *err;
1256
1464
  struct svnadmin_opt_state *opt_state = baton;
1257
 
  svn_stream_t *stdout_stream;
 
1465
  svn_stream_t *feedback_stream = NULL;
1258
1466
 
1259
1467
  /* Expect no more arguments. */
1260
1468
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1261
1469
 
1262
 
  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
 
1470
  SVN_ERR(svn_stream_for_stdout(&feedback_stream, pool));
1263
1471
 
1264
1472
  /* Restore default signal handlers until after we have acquired the
1265
1473
   * exclusive lock so that the user interrupt before we actually
1267
1475
  setup_cancellation_signals(SIG_DFL);
1268
1476
 
1269
1477
  err = svn_repos_recover4(opt_state->repository_path, TRUE,
1270
 
                           repos_notify_handler, stdout_stream,
 
1478
                           repos_notify_handler, feedback_stream,
1271
1479
                           check_cancel, NULL, pool);
1272
1480
  if (err)
1273
1481
    {
1285
1493
                                   " another process has it open?\n")));
1286
1494
      SVN_ERR(svn_cmdline_fflush(stdout));
1287
1495
      SVN_ERR(svn_repos_recover4(opt_state->repository_path, FALSE,
1288
 
                                 repos_notify_handler, stdout_stream,
 
1496
                                 repos_notify_handler, feedback_stream,
1289
1497
                                 check_cancel, NULL, pool));
1290
1498
    }
1291
1499
 
1423
1631
 
1424
1632
 
1425
1633
/* A helper for the 'setrevprop' and 'setlog' commands.  Expects
1426
 
   OPT_STATE->use_pre_revprop_change_hook and
1427
 
   OPT_STATE->use_post_revprop_change_hook to be set appropriately. */
 
1634
   OPT_STATE->txn_id, OPT_STATE->use_pre_revprop_change_hook and
 
1635
   OPT_STATE->use_post_revprop_change_hook to be set appropriately.
 
1636
   If FILENAME is NULL, delete property PROP_NAME.  */
1428
1637
static svn_error_t *
1429
1638
set_revprop(const char *prop_name, const char *filename,
1430
1639
            struct svnadmin_opt_state *opt_state, apr_pool_t *pool)
1431
1640
{
1432
1641
  svn_repos_t *repos;
1433
 
  svn_string_t *prop_value = svn_string_create_empty(pool);
1434
 
  svn_stringbuf_t *file_contents;
1435
 
 
1436
 
  SVN_ERR(svn_stringbuf_from_file2(&file_contents, filename, pool));
1437
 
 
1438
 
  prop_value->data = file_contents->data;
1439
 
  prop_value->len = file_contents->len;
1440
 
 
1441
 
  SVN_ERR(svn_subst_translate_string2(&prop_value, NULL, NULL, prop_value,
1442
 
                                      NULL, FALSE, pool, pool));
 
1642
  svn_string_t *prop_value;
 
1643
 
 
1644
  if (filename)
 
1645
    {
 
1646
      svn_stringbuf_t *file_contents;
 
1647
 
 
1648
      SVN_ERR(svn_stringbuf_from_file2(&file_contents, filename, pool));
 
1649
 
 
1650
      prop_value = svn_string_create_empty(pool);
 
1651
      prop_value->data = file_contents->data;
 
1652
      prop_value->len = file_contents->len;
 
1653
 
 
1654
      SVN_ERR(svn_subst_translate_string2(&prop_value, NULL, NULL, prop_value,
 
1655
                                          NULL, FALSE, pool, pool));
 
1656
    }
 
1657
  else
 
1658
    {
 
1659
      prop_value = NULL;
 
1660
    }
1443
1661
 
1444
1662
  /* Open the filesystem  */
1445
1663
  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
1446
1664
 
1447
 
  /* If we are bypassing the hooks system, we just hit the filesystem
1448
 
     directly. */
1449
 
  SVN_ERR(svn_repos_fs_change_rev_prop4(
 
1665
  if (opt_state->txn_id)
 
1666
    {
 
1667
      svn_fs_t *fs = svn_repos_fs(repos);
 
1668
      svn_fs_txn_t *txn;
 
1669
 
 
1670
      SVN_ERR(svn_fs_open_txn(&txn, fs, opt_state->txn_id, pool));
 
1671
      SVN_ERR(svn_fs_change_txn_prop(txn, prop_name, prop_value, pool));
 
1672
    }
 
1673
  else
 
1674
    SVN_ERR(svn_repos_fs_change_rev_prop4(
1450
1675
              repos, opt_state->start_revision.value.number,
1451
1676
              NULL, prop_name, NULL, prop_value,
1452
1677
              opt_state->use_pre_revprop_change_hook,
1471
1696
  filename = APR_ARRAY_IDX(args, 1, const char *);
1472
1697
  SVN_ERR(target_arg_to_dirent(&filename, filename, pool));
1473
1698
 
1474
 
  if (opt_state->start_revision.kind != svn_opt_revision_number)
 
1699
  if (opt_state->txn_id)
 
1700
    {
 
1701
      if (opt_state->start_revision.kind != svn_opt_revision_unspecified
 
1702
          || opt_state->end_revision.kind != svn_opt_revision_unspecified)
 
1703
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
1704
                                 _("--revision (-r) and --transaction (-t) "
 
1705
                                   "are mutually exclusive"));
 
1706
 
 
1707
      if (opt_state->use_pre_revprop_change_hook
 
1708
          || opt_state->use_post_revprop_change_hook)
 
1709
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
1710
                                 _("Calling hooks is incompatible with "
 
1711
                                   "--transaction (-t)"));
 
1712
    }
 
1713
  else if (opt_state->start_revision.kind != svn_opt_revision_number)
1475
1714
    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
1476
1715
                             _("Missing revision"));
1477
1716
  else if (opt_state->end_revision.kind != svn_opt_revision_unspecified)
1540
1779
{
1541
1780
  struct svnadmin_opt_state *opt_state = baton;
1542
1781
  svn_repos_t *repos;
1543
 
  svn_stream_t *progress_stream = NULL;
 
1782
  svn_stream_t *feedback_stream = NULL;
1544
1783
 
1545
1784
  /* Expect no more arguments. */
1546
1785
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1549
1788
 
1550
1789
  /* Progress feedback goes to STDOUT, unless they asked to suppress it. */
1551
1790
  if (! opt_state->quiet)
1552
 
    progress_stream = recode_stream_create(stdout, pool);
 
1791
    feedback_stream = recode_stream_create(stdout, pool);
1553
1792
 
1554
1793
  return svn_error_trace(
1555
1794
    svn_repos_fs_pack2(repos, !opt_state->quiet ? repos_notify_handler : NULL,
1556
 
                       progress_stream, check_cancel, NULL, pool));
 
1795
                       feedback_stream, check_cancel, NULL, pool));
1557
1796
}
1558
1797
 
1559
1798
 
1565
1804
  svn_repos_t *repos;
1566
1805
  svn_fs_t *fs;
1567
1806
  svn_revnum_t youngest, lower, upper;
1568
 
  svn_stream_t *progress_stream = NULL;
 
1807
  svn_stream_t *feedback_stream = NULL;
 
1808
  struct repos_verify_callback_baton verify_baton = { 0 };
1569
1809
 
1570
1810
  /* Expect no more arguments. */
1571
1811
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1609
1849
      upper = lower;
1610
1850
    }
1611
1851
 
1612
 
  if (! opt_state->quiet)
1613
 
    progress_stream = recode_stream_create(stderr, pool);
1614
 
 
1615
 
  return svn_repos_verify_fs2(repos, lower, upper,
1616
 
                              !opt_state->quiet
1617
 
                                ? repos_notify_handler : NULL,
1618
 
                              progress_stream, check_cancel, NULL, pool);
 
1852
  if (!opt_state->quiet)
 
1853
    feedback_stream = recode_stream_create(stdout, pool);
 
1854
 
 
1855
  verify_baton.keep_going = opt_state->keep_going;
 
1856
  verify_baton.error_summary =
 
1857
    apr_array_make(pool, 0, sizeof(struct verification_error *));
 
1858
  verify_baton.result_pool = pool;
 
1859
 
 
1860
  SVN_ERR(svn_repos_verify_fs3(repos, lower, upper,
 
1861
                               opt_state->check_normalization,
 
1862
                               opt_state->metadata_only,
 
1863
                               !opt_state->quiet
 
1864
                                 ? repos_notify_handler : NULL,
 
1865
                               feedback_stream,
 
1866
                               repos_verify_callback, &verify_baton,
 
1867
                               check_cancel, NULL, pool));
 
1868
 
 
1869
  /* Show the --keep-going error summary. */
 
1870
  if (!opt_state->quiet
 
1871
      && opt_state->keep_going
 
1872
      && verify_baton.error_summary->nelts > 0)
 
1873
    {
 
1874
      int rev_maxlength;
 
1875
      svn_revnum_t end_revnum;
 
1876
      apr_pool_t *iterpool;
 
1877
      int i;
 
1878
 
 
1879
      svn_error_clear(
 
1880
        svn_stream_puts(feedback_stream,
 
1881
                          _("\n-----Summary of corrupt revisions-----\n")));
 
1882
 
 
1883
      /* The standard column width for the revision number is 6 characters.
 
1884
         If the revision number can potentially be larger (i.e. if end_revnum
 
1885
         is larger than 1000000), we increase the column width as needed. */
 
1886
      rev_maxlength = 6;
 
1887
      end_revnum = APR_ARRAY_IDX(verify_baton.error_summary,
 
1888
                                 verify_baton.error_summary->nelts - 1,
 
1889
                                 struct verification_error *)->rev;
 
1890
      while (end_revnum >= 1000000)
 
1891
        {
 
1892
          rev_maxlength++;
 
1893
          end_revnum = end_revnum / 10;
 
1894
        }
 
1895
 
 
1896
      iterpool = svn_pool_create(pool);
 
1897
      for (i = 0; i < verify_baton.error_summary->nelts; i++)
 
1898
        {
 
1899
          struct verification_error *verr;
 
1900
          svn_error_t *err;
 
1901
          const char *rev_str;
 
1902
 
 
1903
          svn_pool_clear(iterpool);
 
1904
 
 
1905
          verr = APR_ARRAY_IDX(verify_baton.error_summary, i,
 
1906
                               struct verification_error *);
 
1907
 
 
1908
          if (verr->rev != SVN_INVALID_REVNUM)
 
1909
            {
 
1910
              rev_str = apr_psprintf(iterpool, "r%ld", verr->rev);
 
1911
              rev_str = apr_psprintf(iterpool, "%*s", rev_maxlength, rev_str);
 
1912
              for (err = svn_error_purge_tracing(verr->err);
 
1913
                   err != SVN_NO_ERROR; err = err->child)
 
1914
                {
 
1915
                  char buf[512];
 
1916
                  const char *message;
 
1917
 
 
1918
                  message = svn_err_best_message(err, buf, sizeof(buf));
 
1919
                  svn_error_clear(svn_stream_printf(feedback_stream, iterpool,
 
1920
                                                    "%s: E%06d: %s\n",
 
1921
                                                    rev_str, err->apr_err,
 
1922
                                                    message));
 
1923
                }
 
1924
            }
 
1925
        }
 
1926
 
 
1927
       svn_pool_destroy(iterpool);
 
1928
    }
 
1929
 
 
1930
  if (verify_baton.error_summary->nelts > 0)
 
1931
    {
 
1932
      return svn_error_createf(SVN_ERR_CL_REPOS_VERIFY_FAILED, NULL,
 
1933
                               _("Failed to verify repository '%s'"),
 
1934
                               svn_dirent_local_style(
 
1935
                                 opt_state->repository_path, pool));
 
1936
    }
 
1937
 
 
1938
  return SVN_NO_ERROR;
1619
1939
}
1620
1940
 
1621
1941
/* This implements `svn_opt_subcommand_t'. */
1623
1943
subcommand_hotcopy(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1624
1944
{
1625
1945
  struct svnadmin_opt_state *opt_state = baton;
 
1946
  svn_stream_t *feedback_stream = NULL;
1626
1947
  apr_array_header_t *targets;
1627
1948
  const char *new_repos_path;
1628
1949
 
1631
1952
  new_repos_path = APR_ARRAY_IDX(targets, 0, const char *);
1632
1953
  SVN_ERR(target_arg_to_dirent(&new_repos_path, new_repos_path, pool));
1633
1954
 
1634
 
  return svn_repos_hotcopy2(opt_state->repository_path, new_repos_path,
 
1955
  /* Progress feedback goes to STDOUT, unless they asked to suppress it. */
 
1956
  if (! opt_state->quiet)
 
1957
    feedback_stream = recode_stream_create(stdout, pool);
 
1958
 
 
1959
  return svn_repos_hotcopy3(opt_state->repository_path, new_repos_path,
1635
1960
                            opt_state->clean_logs, opt_state->incremental,
1636
 
                            check_cancel, NULL, pool);
 
1961
                            !opt_state->quiet ? repos_notify_handler : NULL,
 
1962
                            feedback_stream, check_cancel, NULL, pool);
 
1963
}
 
1964
 
 
1965
svn_error_t *
 
1966
subcommand_info(apr_getopt_t *os, void *baton, apr_pool_t *pool)
 
1967
{
 
1968
  struct svnadmin_opt_state *opt_state = baton;
 
1969
  svn_repos_t *repos;
 
1970
  svn_fs_t *fs;
 
1971
  int fs_format;
 
1972
  const char *uuid;
 
1973
 
 
1974
  /* Expect no more arguments. */
 
1975
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
 
1976
 
 
1977
  SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
 
1978
  fs = svn_repos_fs(repos);
 
1979
  SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"),
 
1980
                             svn_dirent_local_style(svn_repos_path(repos, pool),
 
1981
                                                    pool)));
 
1982
 
 
1983
  SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));
 
1984
  SVN_ERR(svn_cmdline_printf(pool, _("UUID: %s\n"), uuid));
 
1985
  {
 
1986
    int repos_format, minor;
 
1987
    svn_version_t *repos_version, *fs_version;
 
1988
    SVN_ERR(svn_repos_info_format(&repos_format, &repos_version,
 
1989
                                  repos, pool, pool));
 
1990
    SVN_ERR(svn_cmdline_printf(pool, _("Repository Format: %d\n"),
 
1991
                               repos_format));
 
1992
 
 
1993
    SVN_ERR(svn_fs_info_format(&fs_format, &fs_version,
 
1994
                               fs, pool, pool));
 
1995
    /* fs_format will be printed later. */
 
1996
 
 
1997
    SVN_ERR_ASSERT(repos_version->major == SVN_VER_MAJOR);
 
1998
    SVN_ERR_ASSERT(fs_version->major == SVN_VER_MAJOR);
 
1999
    SVN_ERR_ASSERT(repos_version->patch == 0);
 
2000
    SVN_ERR_ASSERT(fs_version->patch == 0);
 
2001
 
 
2002
    minor = (repos_version->minor > fs_version->minor)
 
2003
            ? repos_version->minor : fs_version->minor;
 
2004
    SVN_ERR(svn_cmdline_printf(pool, _("Compatible With Version: %d.%d.0\n"),
 
2005
                               SVN_VER_MAJOR, minor));
 
2006
  }
 
2007
 
 
2008
  {
 
2009
    apr_hash_t *capabilities_set;
 
2010
    apr_array_header_t *capabilities;
 
2011
    int i;
 
2012
 
 
2013
    SVN_ERR(svn_repos_capabilities(&capabilities_set, repos, pool, pool));
 
2014
    capabilities = svn_sort__hash(capabilities_set,
 
2015
                                  svn_sort_compare_items_lexically,
 
2016
                                  pool);
 
2017
 
 
2018
    for (i = 0; i < capabilities->nelts; i++)
 
2019
      {
 
2020
        svn_sort__item_t *item = &APR_ARRAY_IDX(capabilities, i,
 
2021
                                                svn_sort__item_t);
 
2022
        const char *capability = item->key;
 
2023
        SVN_ERR(svn_cmdline_printf(pool, _("Repository Capability: %s\n"),
 
2024
                                   capability));
 
2025
      }
 
2026
  }
 
2027
 
 
2028
  {
 
2029
    const svn_fs_info_placeholder_t *info;
 
2030
 
 
2031
    SVN_ERR(svn_fs_info(&info, fs, pool, pool));
 
2032
    SVN_ERR(svn_cmdline_printf(pool, _("Filesystem Type: %s\n"),
 
2033
                               info->fs_type));
 
2034
    SVN_ERR(svn_cmdline_printf(pool, _("Filesystem Format: %d\n"),
 
2035
                               fs_format));
 
2036
    if (!strcmp(info->fs_type, SVN_FS_TYPE_FSFS))
 
2037
      {
 
2038
        const svn_fs_fsfs_info_t *fsfs_info = (const void *)info;
 
2039
        svn_revnum_t youngest;
 
2040
        SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
 
2041
 
 
2042
        if (fsfs_info->shard_size)
 
2043
          SVN_ERR(svn_cmdline_printf(pool, _("FSFS Sharded: yes\n")));
 
2044
        else
 
2045
          SVN_ERR(svn_cmdline_printf(pool, _("FSFS Sharded: no\n")));
 
2046
 
 
2047
        if (fsfs_info->shard_size)
 
2048
          SVN_ERR(svn_cmdline_printf(pool, _("FSFS Shard Size: %d\n"),
 
2049
                                     fsfs_info->shard_size));
 
2050
 
 
2051
        /* Print packing statistics, if enabled on the FS. */
 
2052
        if (fsfs_info->shard_size)
 
2053
          {
 
2054
            const int shard_size = fsfs_info->shard_size;
 
2055
            const long shards_packed = fsfs_info->min_unpacked_rev / shard_size;
 
2056
            const long shards_full = (youngest + 1) / shard_size;
 
2057
            SVN_ERR(svn_cmdline_printf(pool, _("FSFS Shards Packed: %ld/%ld\n"),
 
2058
                                       shards_packed, shards_full));
 
2059
          }
 
2060
 
 
2061
        if (fsfs_info->log_addressing)
 
2062
          SVN_ERR(svn_cmdline_printf(pool, _("FSFS Logical Addressing: yes\n")));
 
2063
        else
 
2064
          SVN_ERR(svn_cmdline_printf(pool, _("FSFS Logical Addressing: no\n")));
 
2065
      }
 
2066
  }
 
2067
 
 
2068
  {
 
2069
    apr_array_header_t *files;
 
2070
    int i;
 
2071
 
 
2072
    SVN_ERR(svn_fs_info_config_files(&files, fs, pool, pool));
 
2073
    for (i = 0; i < files->nelts; i++)
 
2074
      SVN_ERR(svn_cmdline_printf(pool, _("Configuration File: %s\n"),
 
2075
                                 svn_dirent_local_style(
 
2076
                                   APR_ARRAY_IDX(files, i, const char *),
 
2077
                                   pool)));
 
2078
  }
 
2079
 
 
2080
  /* 'svn info' prints an extra newline here, to support multiple targets.
 
2081
     We'll do the same. */
 
2082
  SVN_ERR(svn_cmdline_printf(pool, "\n"));
 
2083
 
 
2084
  return SVN_NO_ERROR;
1637
2085
}
1638
2086
 
1639
2087
/* This implements `svn_opt_subcommand_t'. */
1709
2157
  const char *fs_path = "/";
1710
2158
  apr_hash_t *locks;
1711
2159
  apr_hash_index_t *hi;
 
2160
  apr_pool_t *iterpool = svn_pool_create(pool);
1712
2161
 
1713
2162
  SVN_ERR(svn_opt__args_to_target_array(&targets, os,
1714
2163
                                        apr_array_make(pool, 0,
1729
2178
  for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi))
1730
2179
    {
1731
2180
      const char *cr_date, *exp_date = "";
1732
 
      const char *path = svn__apr_hash_index_key(hi);
1733
 
      svn_lock_t *lock = svn__apr_hash_index_val(hi);
 
2181
      const char *path = apr_hash_this_key(hi);
 
2182
      svn_lock_t *lock = apr_hash_this_val(hi);
1734
2183
      int comment_lines = 0;
1735
2184
 
1736
 
      cr_date = svn_time_to_human_cstring(lock->creation_date, pool);
 
2185
      svn_pool_clear(iterpool);
 
2186
 
 
2187
      SVN_ERR(check_cancel(NULL));
 
2188
 
 
2189
      cr_date = svn_time_to_human_cstring(lock->creation_date, iterpool);
1737
2190
 
1738
2191
      if (lock->expiration_date)
1739
 
        exp_date = svn_time_to_human_cstring(lock->expiration_date, pool);
 
2192
        exp_date = svn_time_to_human_cstring(lock->expiration_date, iterpool);
1740
2193
 
1741
2194
      if (lock->comment)
1742
2195
        comment_lines = svn_cstring_count_newlines(lock->comment) + 1;
1743
2196
 
1744
 
      SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"), path));
1745
 
      SVN_ERR(svn_cmdline_printf(pool, _("UUID Token: %s\n"), lock->token));
1746
 
      SVN_ERR(svn_cmdline_printf(pool, _("Owner: %s\n"), lock->owner));
1747
 
      SVN_ERR(svn_cmdline_printf(pool, _("Created: %s\n"), cr_date));
1748
 
      SVN_ERR(svn_cmdline_printf(pool, _("Expires: %s\n"), exp_date));
1749
 
      SVN_ERR(svn_cmdline_printf(pool,
 
2197
      SVN_ERR(svn_cmdline_printf(iterpool, _("Path: %s\n"), path));
 
2198
      SVN_ERR(svn_cmdline_printf(iterpool, _("UUID Token: %s\n"), lock->token));
 
2199
      SVN_ERR(svn_cmdline_printf(iterpool, _("Owner: %s\n"), lock->owner));
 
2200
      SVN_ERR(svn_cmdline_printf(iterpool, _("Created: %s\n"), cr_date));
 
2201
      SVN_ERR(svn_cmdline_printf(iterpool, _("Expires: %s\n"), exp_date));
 
2202
      SVN_ERR(svn_cmdline_printf(iterpool,
1750
2203
                                 Q_("Comment (%i line):\n%s\n\n",
1751
2204
                                    "Comment (%i lines):\n%s\n\n",
1752
2205
                                    comment_lines),
1754
2207
                                 lock->comment ? lock->comment : ""));
1755
2208
    }
1756
2209
 
 
2210
  svn_pool_destroy(iterpool);
 
2211
 
1757
2212
  return SVN_NO_ERROR;
1758
2213
}
1759
2214
 
1888
2343
{
1889
2344
  svn_error_t *err;
1890
2345
  struct svnadmin_opt_state *opt_state = baton;
1891
 
  svn_stream_t *stdout_stream;
 
2346
  svn_stream_t *feedback_stream = NULL;
1892
2347
 
1893
2348
  /* Expect no more arguments. */
1894
2349
  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
1895
2350
 
1896
 
  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
 
2351
  SVN_ERR(svn_stream_for_stdout(&feedback_stream, pool));
1897
2352
 
1898
2353
  /* Restore default signal handlers. */
1899
2354
  setup_cancellation_signals(SIG_DFL);
1900
2355
 
1901
2356
  err = svn_repos_upgrade2(opt_state->repository_path, TRUE,
1902
 
                           repos_notify_handler, stdout_stream, pool);
 
2357
                           repos_notify_handler, feedback_stream, pool);
1903
2358
  if (err)
1904
2359
    {
1905
2360
      if (APR_STATUS_IS_EAGAIN(err->apr_err))
1917
2372
                                       " another process has it open?\n")));
1918
2373
          SVN_ERR(svn_cmdline_fflush(stdout));
1919
2374
          SVN_ERR(svn_repos_upgrade2(opt_state->repository_path, FALSE,
1920
 
                                     repos_notify_handler, stdout_stream,
 
2375
                                     repos_notify_handler, feedback_stream,
1921
2376
                                     pool));
1922
2377
        }
1923
2378
      else if (err->apr_err == SVN_ERR_FS_UNSUPPORTED_UPGRADE)
1941
2396
}
1942
2397
 
1943
2398
 
 
2399
/* This implements `svn_opt_subcommand_t'. */
 
2400
static svn_error_t *
 
2401
subcommand_delrevprop(apr_getopt_t *os, void *baton, apr_pool_t *pool)
 
2402
{
 
2403
  struct svnadmin_opt_state *opt_state = baton;
 
2404
  apr_array_header_t *args;
 
2405
  const char *prop_name;
 
2406
 
 
2407
  /* Expect one more argument: NAME */
 
2408
  SVN_ERR(parse_args(&args, os, 1, 1, pool));
 
2409
  prop_name = APR_ARRAY_IDX(args, 0, const char *);
 
2410
 
 
2411
  if (opt_state->txn_id)
 
2412
    {
 
2413
      if (opt_state->start_revision.kind != svn_opt_revision_unspecified
 
2414
          || opt_state->end_revision.kind != svn_opt_revision_unspecified)
 
2415
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2416
                                 _("--revision (-r) and --transaction (-t) "
 
2417
                                   "are mutually exclusive"));
 
2418
 
 
2419
      if (opt_state->use_pre_revprop_change_hook
 
2420
          || opt_state->use_post_revprop_change_hook)
 
2421
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2422
                                 _("Calling hooks is incompatible with "
 
2423
                                   "--transaction (-t)"));
 
2424
    }
 
2425
  else if (opt_state->start_revision.kind != svn_opt_revision_number)
 
2426
    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2427
                             _("Missing revision"));
 
2428
  else if (opt_state->end_revision.kind != svn_opt_revision_unspecified)
 
2429
    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2430
                             _("Only one revision allowed"));
 
2431
 
 
2432
  return set_revprop(prop_name, NULL, opt_state, pool);
 
2433
}
 
2434
 
 
2435
 
1944
2436
 
1945
2437
/** Main. **/
1946
2438
 
1947
 
/* Report and clear the error ERR, and return EXIT_FAILURE. */
1948
 
#define EXIT_ERROR(err)                                                 \
1949
 
  svn_cmdline_handle_exit_error(err, NULL, "svnadmin: ")
1950
 
 
1951
 
/* A redefinition of the public SVN_INT_ERR macro, that suppresses the
1952
 
 * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR, amd with the
1953
 
 * program name 'svnadmin' instead of 'svn'. */
1954
 
#undef SVN_INT_ERR
1955
 
#define SVN_INT_ERR(expr)                                        \
1956
 
  do {                                                           \
1957
 
    svn_error_t *svn_err__temp = (expr);                         \
1958
 
    if (svn_err__temp)                                           \
1959
 
      return EXIT_ERROR(svn_err__temp);                          \
1960
 
  } while (0)
1961
 
 
1962
 
static int
1963
 
sub_main(int argc, const char *argv[], apr_pool_t *pool)
 
2439
/*
 
2440
 * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
 
2441
 * either return an error to be displayed, or set *EXIT_CODE to non-zero and
 
2442
 * return SVN_NO_ERROR.
 
2443
 */
 
2444
static svn_error_t *
 
2445
sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
1964
2446
{
1965
2447
  svn_error_t *err;
1966
2448
  apr_status_t apr_err;
1976
2458
  received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
1977
2459
 
1978
2460
  /* Check library versions */
1979
 
  SVN_INT_ERR(check_lib_versions());
 
2461
  SVN_ERR(check_lib_versions());
1980
2462
 
1981
2463
  /* Initialize the FS library. */
1982
 
  SVN_INT_ERR(svn_fs_initialize(pool));
 
2464
  SVN_ERR(svn_fs_initialize(pool));
1983
2465
 
1984
2466
  if (argc <= 1)
1985
2467
    {
1986
 
      SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
1987
 
      return EXIT_FAILURE;
 
2468
      SVN_ERR(subcommand_help(NULL, NULL, pool));
 
2469
      *exit_code = EXIT_FAILURE;
 
2470
      return SVN_NO_ERROR;
1988
2471
    }
1989
2472
 
1990
2473
  /* Initialize opt_state. */
1993
2476
  opt_state.memory_cache_size = svn_cache_config_get()->cache_size;
1994
2477
 
1995
2478
  /* Parse options. */
1996
 
  SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
2479
  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
1997
2480
 
1998
2481
  os->interleave = 1;
1999
2482
 
2008
2491
        break;
2009
2492
      else if (apr_err)
2010
2493
        {
2011
 
          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
2012
 
          return EXIT_FAILURE;
 
2494
          SVN_ERR(subcommand_help(NULL, NULL, pool));
 
2495
          *exit_code = EXIT_FAILURE;
 
2496
          return SVN_NO_ERROR;
2013
2497
        }
2014
2498
 
2015
2499
      /* Stash the option code in an array before parsing it. */
2020
2504
        {
2021
2505
          if (opt_state.start_revision.kind != svn_opt_revision_unspecified)
2022
2506
            {
2023
 
              err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
2024
 
                 _("Multiple revision arguments encountered; "
2025
 
                   "try '-r N:M' instead of '-r N -r M'"));
2026
 
              return EXIT_ERROR(err);
 
2507
              return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2508
                        _("Multiple revision arguments encountered; "
 
2509
                          "try '-r N:M' instead of '-r N -r M'"));
2027
2510
            }
2028
2511
          if (svn_opt_parse_revision(&(opt_state.start_revision),
2029
2512
                                     &(opt_state.end_revision),
2030
2513
                                     opt_arg, pool) != 0)
2031
2514
            {
2032
 
              err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg,
2033
 
                                            pool);
 
2515
              SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
2034
2516
 
2035
 
              if (! err)
2036
 
                err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2517
              return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
2037
2518
                        _("Syntax error in revision argument '%s'"),
2038
2519
                        utf8_opt_arg);
2039
 
              return EXIT_ERROR(err);
2040
2520
            }
2041
2521
        }
2042
2522
        break;
2056
2536
            = 0x100000 * apr_strtoi64(opt_arg, NULL, 0);
2057
2537
        break;
2058
2538
      case 'F':
2059
 
        SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
2060
 
        SVN_INT_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
 
2539
        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
 
2540
        SVN_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
2061
2541
                                             utf8_opt_arg, pool));
2062
2542
        dash_F_arg = TRUE;
2063
2543
      case svnadmin__version:
2076
2556
        opt_state.uuid_action = svn_repos_load_uuid_force;
2077
2557
        break;
2078
2558
      case svnadmin__pre_1_4_compatible:
2079
 
        opt_state.pre_1_4_compatible = TRUE;
 
2559
        opt_state.compatible_version = apr_pcalloc(pool, sizeof(svn_version_t));
 
2560
        opt_state.compatible_version->major = 1;
 
2561
        opt_state.compatible_version->minor = 3;
2080
2562
        break;
2081
2563
      case svnadmin__pre_1_5_compatible:
2082
 
        opt_state.pre_1_5_compatible = TRUE;
 
2564
        opt_state.compatible_version = apr_pcalloc(pool, sizeof(svn_version_t));
 
2565
        opt_state.compatible_version->major = 1;
 
2566
        opt_state.compatible_version->minor = 4;
2083
2567
        break;
2084
2568
      case svnadmin__pre_1_6_compatible:
2085
 
        opt_state.pre_1_6_compatible = TRUE;
 
2569
        opt_state.compatible_version = apr_pcalloc(pool, sizeof(svn_version_t));
 
2570
        opt_state.compatible_version->major = 1;
 
2571
        opt_state.compatible_version->minor = 5;
2086
2572
        break;
2087
2573
      case svnadmin__compatible_version:
2088
2574
        {
2092
2578
 
2093
2579
          /* Parse the version string which carries our target
2094
2580
             compatibility. */
2095
 
          SVN_INT_ERR(svn_version__parse_version_string(&compatible_version,
 
2581
          SVN_ERR(svn_version__parse_version_string(&compatible_version,
2096
2582
                                                        opt_arg, pool));
2097
2583
 
2098
2584
          /* We can't create repository with a version older than 1.0.0.  */
2099
2585
          if (! svn_version__at_least(compatible_version, 1, 0, 0))
2100
2586
            {
2101
 
              err = svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
2102
 
                                      _("Cannot create pre-1.0-compatible "
2103
 
                                        "repositories"));
2104
 
              return EXIT_ERROR(err);
 
2587
              return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
2588
                                       _("Cannot create pre-1.0-compatible "
 
2589
                                         "repositories"));
2105
2590
            }
2106
2591
 
2107
2592
          /* We can't create repository with a version newer than what
2111
2596
                                      compatible_version->minor,
2112
2597
                                      compatible_version->patch))
2113
2598
            {
2114
 
              err = svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
2115
 
                                      _("Cannot guarantee compatibility "
2116
 
                                        "beyond the current running version "
2117
 
                                        "(%s)"),
2118
 
                                      SVN_VER_NUM );
2119
 
              return EXIT_ERROR(err);
 
2599
              return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
 
2600
                                       _("Cannot guarantee compatibility "
 
2601
                                         "beyond the current running version "
 
2602
                                         "(%s)"),
 
2603
                                       SVN_VER_NUM);
2120
2604
            }
2121
2605
 
2122
2606
          opt_state.compatible_version = compatible_version;
2123
2607
        }
2124
2608
        break;
 
2609
      case svnadmin__keep_going:
 
2610
        opt_state.keep_going = TRUE;
 
2611
        break;
 
2612
      case svnadmin__check_normalization:
 
2613
        opt_state.check_normalization = TRUE;
 
2614
        break;
 
2615
      case svnadmin__metadata_only:
 
2616
        opt_state.metadata_only = TRUE;
 
2617
        break;
2125
2618
      case svnadmin__fs_type:
2126
 
        SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.fs_type, opt_arg, pool));
 
2619
        SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.fs_type, opt_arg, pool));
2127
2620
        break;
2128
2621
      case svnadmin__parent_dir:
2129
 
        SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.parent_dir, opt_arg,
 
2622
        SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.parent_dir, opt_arg,
2130
2623
                                            pool));
2131
2624
        opt_state.parent_dir
2132
2625
          = svn_dirent_internal_style(opt_state.parent_dir, pool);
2155
2648
      case svnadmin__bypass_prop_validation:
2156
2649
        opt_state.bypass_prop_validation = TRUE;
2157
2650
        break;
 
2651
      case svnadmin__ignore_dates:
 
2652
        opt_state.ignore_dates = TRUE;
 
2653
        break;
2158
2654
      case svnadmin__clean_logs:
2159
2655
        opt_state.clean_logs = TRUE;
2160
2656
        break;
2161
2657
      case svnadmin__config_dir:
2162
 
        SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
 
2658
        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
2163
2659
        opt_state.config_dir =
2164
2660
            apr_pstrdup(pool, svn_dirent_canonicalize(utf8_opt_arg, pool));
2165
2661
        break;
2168
2664
        break;
2169
2665
      default:
2170
2666
        {
2171
 
          SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
2172
 
          return EXIT_FAILURE;
 
2667
          SVN_ERR(subcommand_help(NULL, NULL, pool));
 
2668
          *exit_code = EXIT_FAILURE;
 
2669
          return SVN_NO_ERROR;
2173
2670
        }
2174
2671
      }  /* close `switch' */
2175
2672
    }  /* close `while' */
2202
2699
            {
2203
2700
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
2204
2701
                                        _("subcommand argument required\n")));
2205
 
              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
2206
 
              return EXIT_FAILURE;
 
2702
              SVN_ERR(subcommand_help(NULL, NULL, pool));
 
2703
              *exit_code = EXIT_FAILURE;
 
2704
              return SVN_NO_ERROR;
2207
2705
            }
2208
2706
        }
2209
2707
      else
2213
2711
          if (subcommand == NULL)
2214
2712
            {
2215
2713
              const char *first_arg_utf8;
2216
 
              SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
 
2714
              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
2217
2715
                                                  first_arg, pool));
2218
2716
              svn_error_clear(
2219
2717
                svn_cmdline_fprintf(stderr, pool,
2220
2718
                                    _("Unknown subcommand: '%s'\n"),
2221
2719
                                    first_arg_utf8));
2222
 
              SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
2223
 
              return EXIT_FAILURE;
 
2720
              SVN_ERR(subcommand_help(NULL, NULL, pool));
 
2721
              *exit_code = EXIT_FAILURE;
 
2722
              return SVN_NO_ERROR;
2224
2723
            }
2225
2724
        }
2226
2725
    }
2235
2734
 
2236
2735
      if (os->ind >= os->argc)
2237
2736
        {
2238
 
          err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
2239
 
                                 _("Repository argument required"));
2240
 
          return EXIT_ERROR(err);
 
2737
          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2738
                                  _("Repository argument required"));
2241
2739
        }
2242
2740
 
2243
 
      if ((err = svn_utf_cstring_to_utf8(&repos_path,
2244
 
                                         os->argv[os->ind++], pool)))
2245
 
        {
2246
 
          return EXIT_ERROR(err);
2247
 
        }
 
2741
      SVN_ERR(svn_utf_cstring_to_utf8(&repos_path, os->argv[os->ind++], pool));
2248
2742
 
2249
2743
      if (svn_path_is_url(repos_path))
2250
2744
        {
2251
 
          err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
2252
 
                                  _("'%s' is a URL when it should be a "
2253
 
                                    "local path"), repos_path);
2254
 
          return EXIT_ERROR(err);
 
2745
          return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
 
2746
                                   _("'%s' is a URL when it should be a "
 
2747
                                     "local path"), repos_path);
2255
2748
        }
2256
2749
 
2257
2750
      opt_state.repository_path = svn_dirent_internal_style(repos_path, pool);
2277
2770
                                          pool);
2278
2771
          svn_opt_format_option(&optstr, badopt, FALSE, pool);
2279
2772
          if (subcommand->name[0] == '-')
2280
 
            SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
 
2773
            SVN_ERR(subcommand_help(NULL, NULL, pool));
2281
2774
          else
2282
2775
            svn_error_clear(svn_cmdline_fprintf(stderr, pool
2283
2776
                            , _("Subcommand '%s' doesn't accept option '%s'\n"
2284
2777
                                "Type 'svnadmin help %s' for usage.\n"),
2285
2778
                subcommand->name, optstr, subcommand->name));
2286
 
          return EXIT_FAILURE;
 
2779
          *exit_code = EXIT_FAILURE;
 
2780
          return SVN_NO_ERROR;
2287
2781
        }
2288
2782
    }
2289
2783
 
2325
2819
          err = svn_error_quick_wrap(err,
2326
2820
                                     _("Try 'svnadmin help' for more info"));
2327
2821
        }
2328
 
      return EXIT_ERROR(err);
2329
 
    }
2330
 
  else
2331
 
    {
2332
 
      /* Ensure that everything is written to stdout, so the user will
2333
 
         see any print errors. */
2334
 
      err = svn_cmdline_fflush(stdout);
2335
 
      if (err)
2336
 
        {
2337
 
          return EXIT_ERROR(err);
2338
 
        }
2339
 
      return EXIT_SUCCESS;
2340
 
    }
 
2822
      return err;
 
2823
    }
 
2824
 
 
2825
  return SVN_NO_ERROR;
2341
2826
}
2342
2827
 
2343
2828
int
2344
2829
main(int argc, const char *argv[])
2345
2830
{
2346
2831
  apr_pool_t *pool;
2347
 
  int exit_code;
 
2832
  int exit_code = EXIT_SUCCESS;
 
2833
  svn_error_t *err;
2348
2834
 
2349
2835
  /* Initialize the app. */
2350
2836
  if (svn_cmdline_init("svnadmin", stderr) != EXIT_SUCCESS)
2355
2841
   */
2356
2842
  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
2357
2843
 
2358
 
  exit_code = sub_main(argc, argv, pool);
 
2844
  err = sub_main(&exit_code, argc, argv, pool);
 
2845
 
 
2846
  /* Flush stdout and report if it fails. It would be flushed on exit anyway
 
2847
     but this makes sure that output is not silently lost if it fails. */
 
2848
  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
 
2849
 
 
2850
  if (err)
 
2851
    {
 
2852
      exit_code = EXIT_FAILURE;
 
2853
      svn_cmdline_handle_exit_error(err, NULL, "svnadmin: ");
 
2854
    }
2359
2855
 
2360
2856
  svn_pool_destroy(pool);
2361
2857
  return exit_code;