Beispiel #1
0
/*
 * 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_getopt_t *os;
  const apr_getopt_option_t options[] =
    {
      {"help", 'h', 0, N_("display this help")},
      {"version", OPT_VERSION, 0,
       N_("show program version information")},
      {0,             0,  0,  0}
    };
  apr_array_header_t *remaining_argv;

  /* Check library versions */
  SVN_ERR(check_lib_versions());

#if defined(WIN32) || defined(__CYGWIN__)
  /* Set the working copy administrative directory name. */
  if (getenv("SVN_ASP_DOT_NET_HACK"))
    {
      SVN_ERR(svn_wc_set_adm_dir("_svn", pool));
    }
#endif

  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

  os->interleave = 1;
  while (1)
    {
      int opt;
      const char *arg;
      apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(pool);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }

      switch (opt)
        {
        case 'h':
          help(options, pool);
          return SVN_NO_ERROR;
        case OPT_VERSION:
          SVN_ERR(version(pool));
          return SVN_NO_ERROR;
        default:
          usage(pool);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
    }

  /* Convert the remaining arguments to UTF-8. */
  remaining_argv = apr_array_make(pool, 0, sizeof(const char *));
  while (os->ind < argc)
    {
      const char *s;

      SVN_ERR(svn_utf_cstring_to_utf8(&s, os->argv[os->ind++], pool));
      APR_ARRAY_PUSH(remaining_argv, const char *) = s;
    }

  if (remaining_argv->nelts < 1)
    {
      usage(pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  /* Do the main task */
  SVN_ERR(raise_tree_conflict(remaining_argv->nelts,
                              (const char **)remaining_argv->elts,
                              pool));

  return SVN_NO_ERROR;
}
Beispiel #2
0
/* Standard svn test program */
int
main(int argc, const char *argv[])
{
  const char *prog_name;
  int i;
  svn_boolean_t got_error = FALSE;
  apr_pool_t *pool, *test_pool;
  svn_boolean_t ran_a_test = FALSE;
  svn_boolean_t list_mode = FALSE;
  int opt_id;
  apr_status_t apr_err;
  apr_getopt_t *os;
  svn_error_t *err;
  char errmsg[200];
  /* How many tests are there? */
  int array_size = get_array_size();

  svn_test_opts_t opts = { NULL };

  opts.fs_type = DEFAULT_FS_TYPE;

  /* Initialize APR (Apache pools) */
  if (apr_initialize() != APR_SUCCESS)
    {
      printf("apr_initialize() failed.\n");
      exit(1);
    }

  /* set up the global pool.  Use a separate allocator to limit memory
   * usage but make it thread-safe to allow for multi-threaded tests.
   */
  pool = apr_allocator_owner_get(svn_pool_create_allocator(TRUE));

  /* Remember the command line */
  test_argc = argc;
  test_argv = argv;

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);

  os->interleave = TRUE; /* Let options and arguments be interleaved */

  /* Strip off any leading path components from the program name.  */
  prog_name = strrchr(argv[0], '/');
  if (prog_name)
    prog_name++;
  else
    {
      /* Just check if this is that weird platform that uses \ instead
         of / for the path separator. */
      prog_name = strrchr(argv[0], '\\');
      if (prog_name)
        prog_name++;
      else
        prog_name = argv[0];
    }

  if (err)
    return svn_cmdline_handle_exit_error(err, pool, prog_name);
  while (1)
    {
      const char *opt_arg;

      /* Parse the next option. */
      apr_err = apr_getopt_long(os, cl_options, &opt_id, &opt_arg);
      if (APR_STATUS_IS_EOF(apr_err))
        break;
      else if (apr_err && (apr_err != APR_BADCH))
        {
          /* Ignore invalid option error to allow passing arbitary options */
          fprintf(stderr, "apr_getopt_long failed : [%d] %s\n",
                  apr_err, apr_strerror(apr_err, errmsg, sizeof(errmsg)));
          exit(1);
        }

      switch (opt_id) {
        case cleanup_opt:
          cleanup_mode = TRUE;
          break;
        case config_opt:
          opts.config_file = apr_pstrdup(pool, opt_arg);
          break;
        case fstype_opt:
          opts.fs_type = apr_pstrdup(pool, opt_arg);
          break;
        case list_opt:
          list_mode = TRUE;
          break;
        case mode_filter_opt:
          if (svn_cstring_casecmp(opt_arg, "PASS") == 0)
            mode_filter = svn_test_pass;
          else if (svn_cstring_casecmp(opt_arg, "XFAIL") == 0)
            mode_filter = svn_test_xfail;
          else if (svn_cstring_casecmp(opt_arg, "SKIP") == 0)
            mode_filter = svn_test_skip;
          else if (svn_cstring_casecmp(opt_arg, "ALL") == 0)
            mode_filter = svn_test_all;
          else
            {
              fprintf(stderr, "FAIL: Invalid --mode-filter option.  Try ");
              fprintf(stderr, " PASS, XFAIL, SKIP or ALL.\n");
              exit(1);
            }
          break;
        case verbose_opt:
          verbose_mode = TRUE;
          break;
        case quiet_opt:
          quiet_mode = TRUE;
          break;
        case allow_segfault_opt:
          allow_segfaults = TRUE;
          break;
        case server_minor_version_opt:
          {
            char *end;
            opts.server_minor_version = (int) strtol(opt_arg, &end, 10);
            if (end == opt_arg || *end != '\0')
              {
                fprintf(stderr, "FAIL: Non-numeric minor version given\n");
                exit(1);
              }
            if ((opts.server_minor_version < 3)
                || (opts.server_minor_version > 6))
              {
                fprintf(stderr, "FAIL: Invalid minor version given\n");
                exit(1);
              }
          }
      }
    }

  /* Disable sleeping for timestamps, to speed up the tests. */
  apr_env_set(
         "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS",
         "yes", pool);

  /* You can't be both quiet and verbose. */
  if (quiet_mode && verbose_mode)
    {
      fprintf(stderr, "FAIL: --verbose and --quiet are mutually exclusive\n");
      exit(1);
    }

  /* Create an iteration pool for the tests */
  cleanup_pool = svn_pool_create(pool);
  test_pool = svn_pool_create(pool);

  if (!allow_segfaults)
    svn_error_set_malfunction_handler(svn_error_raise_on_malfunction);

  if (argc >= 2)  /* notice command-line arguments */
    {
      if (! strcmp(argv[1], "list") || list_mode)
        {
          const char *header_msg;
          ran_a_test = TRUE;

          /* run all tests with MSG_ONLY set to TRUE */
          header_msg = "Test #  Mode   Test Description\n"
                       "------  -----  ----------------\n";
          for (i = 1; i <= array_size; i++)
            {
              if (do_test_num(prog_name, i, TRUE, &opts, &header_msg,
                              test_pool))
                got_error = TRUE;

              /* Clear the per-function pool */
              svn_pool_clear(test_pool);
              svn_pool_clear(cleanup_pool);
            }
        }
      else
        {
          for (i = 1; i < argc; i++)
            {
              if (svn_ctype_isdigit(argv[i][0]) || argv[i][0] == '-')
                {
                  int test_num = atoi(argv[i]);
                  if (test_num == 0)
                    /* A --option argument, most likely. */
                    continue;

                  ran_a_test = TRUE;
                  if (do_test_num(prog_name, test_num, FALSE, &opts, NULL,
                                  test_pool))
                    got_error = TRUE;

                  /* Clear the per-function pool */
                  svn_pool_clear(test_pool);
                  svn_pool_clear(cleanup_pool);
                }
            }
        }
    }

  if (! ran_a_test)
    {
      /* just run all tests */
      for (i = 1; i <= array_size; i++)
        {
          if (do_test_num(prog_name, i, FALSE, &opts, NULL, test_pool))
            got_error = TRUE;

          /* Clear the per-function pool */
          svn_pool_clear(test_pool);
          svn_pool_clear(cleanup_pool);
        }
    }

  /* Clean up APR */
  svn_pool_destroy(pool);      /* takes test_pool with it */
  apr_terminate();

  return got_error;
}
Beispiel #3
0
/*
 * Why is this not an svn subcommand?  I have this vague idea that it could
 * be run as part of the build process, with the output embedded in the svn
 * program.  Obviously we don't want to have to run svn when building svn.
 */
int
main(int argc, const char *argv[])
{
  const char *wc_path, *trail_url;
  apr_allocator_t *allocator;
  apr_pool_t *pool;
  int wc_format;
  svn_wc_revision_status_t *res;
  svn_boolean_t no_newline = FALSE, committed = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  const apr_getopt_option_t options[] =
    {
      {"no-newline", 'n', 0, N_("do not output the trailing newline")},
      {"committed",  'c', 0, N_("last changed rather than current revisions")},
      {"help", 'h', 0, N_("display this help")},
      {"version", SVNVERSION_OPT_VERSION, 0,
       N_("show program version information")},
      {0,             0,  0,  0}
    };

  /* Initialize the app. */
  if (svn_cmdline_init("svnversion", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool.  Use a separate mutexless allocator,
   * given this application is single threaded.
   */
  if (apr_allocator_create(&allocator))
    return EXIT_FAILURE;

  apr_allocator_max_free_set(allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);

  pool = svn_pool_create_ex(NULL, allocator);
  apr_allocator_owner_set(allocator, pool);

  /* Check library versions */
  err = check_lib_versions();
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

#if defined(WIN32) || defined(__CYGWIN__)
  /* Set the working copy administrative directory name. */
  if (getenv("SVN_ASP_DOT_NET_HACK"))
    {
      err = svn_wc_set_adm_dir("_svn", pool);
      if (err)
        return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");
    }
#endif

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svnversion: ");

  os->interleave = 1;
  while (1)
    {
      int opt;
      const char *arg;
      apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(pool);
          return EXIT_FAILURE;
        }
      switch (opt)
        {
        case 'n':
          no_newline = TRUE;
          break;
        case 'c':
          committed = TRUE;
          break;
        case 'h':
          help(options, pool);
          break;
        case SVNVERSION_OPT_VERSION:
          SVN_INT_ERR(version(pool));
          exit(0);
          break;
        default:
          usage(pool);
          return EXIT_FAILURE;
        }
    }

  if (os->ind > argc || os->ind < argc - 2)
    {
      usage(pool);
      return EXIT_FAILURE;
    }

  SVN_INT_ERR(svn_utf_cstring_to_utf8
              (&wc_path, (os->ind < argc) ? os->argv[os->ind] : ".",
               pool));
  wc_path = svn_path_internal_style(wc_path, pool);

  if (os->ind+1 < argc)
    SVN_INT_ERR(svn_utf_cstring_to_utf8
                (&trail_url, os->argv[os->ind+1], pool));
  else
    trail_url = NULL;

  SVN_INT_ERR(svn_wc_check_wc(wc_path, &wc_format, pool));
  if (! wc_format)
    {
      svn_node_kind_t kind;
      SVN_INT_ERR(svn_io_check_path(wc_path, &kind, pool));
      if (kind == svn_node_dir)
        {
          SVN_INT_ERR(svn_cmdline_printf(pool, _("exported%s"),
                                         no_newline ? "" : "\n"));
          svn_pool_destroy(pool);
          return EXIT_SUCCESS;
        }
      else
        {
          svn_error_clear
            (svn_cmdline_fprintf(stderr, pool,
                                 _("'%s' not versioned, and not exported\n"),
                                 wc_path));
          svn_pool_destroy(pool);
          return EXIT_FAILURE;
        }
    }


  SVN_INT_ERR(svn_wc_revision_status(&res, wc_path, trail_url, committed,
                                     NULL, NULL, pool));

  /* Build compact '123[:456]M?S?' string. */
  SVN_INT_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
  if (res->min_rev != res->max_rev)
    SVN_INT_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
  if (res->modified)
    SVN_INT_ERR(svn_cmdline_fputs("M", stdout, pool));
  if (res->switched)
    SVN_INT_ERR(svn_cmdline_fputs("S", stdout, pool));
  if (res->sparse_checkout)
    SVN_INT_ERR(svn_cmdline_fputs("P", stdout, pool));

  if (! no_newline)
    SVN_INT_ERR(svn_cmdline_fputs("\n", stdout, pool));

  svn_pool_destroy(pool);

  /* Flush stdout to make sure that the user will see any printing errors. */
  SVN_INT_ERR(svn_cmdline_fflush(stdout));

  return EXIT_SUCCESS;
}
Beispiel #4
0
int
main(int argc, const char **argv)
{
    svn_error_t *err = SVN_NO_ERROR;
    const svn_opt_subcommand_desc2_t *subcommand = NULL;
    opt_baton_t *opt_baton;
    svn_revnum_t latest_revision = SVN_INVALID_REVNUM;
    apr_pool_t *pool = NULL;
    const char *config_dir = NULL;
    const char *username = NULL;
    const char *password = NULL;
    svn_boolean_t no_auth_cache = FALSE;
    svn_boolean_t trust_server_cert = FALSE;
    svn_boolean_t non_interactive = FALSE;
    apr_array_header_t *config_options = NULL;
    apr_getopt_t *os;
    const char *first_arg;
    apr_array_header_t *received_opts;
    apr_allocator_t *allocator;
    int i;

    if (svn_cmdline_init ("svnrdump", stderr) != EXIT_SUCCESS)
        return EXIT_FAILURE;

    /* Create our top-level pool.  Use a separate mutexless allocator,
     * given this application is single threaded.
     */
    if (apr_allocator_create(&allocator))
        return EXIT_FAILURE;

    apr_allocator_max_free_set(allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);

    pool = svn_pool_create_ex(NULL, allocator);
    apr_allocator_owner_set(allocator, pool);

    opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
    opt_baton->start_revision.kind = svn_opt_revision_unspecified;
    opt_baton->end_revision.kind = svn_opt_revision_unspecified;
    opt_baton->url = NULL;

    SVNRDUMP_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

    os->interleave = TRUE; /* Options and arguments can be interleaved */

    /* Set up our cancellation support. */
    apr_signal(SIGINT, signal_handler);
#ifdef SIGBREAK
    /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
    apr_signal(SIGBREAK, signal_handler);
#endif
#ifdef SIGHUP
    apr_signal(SIGHUP, signal_handler);
#endif
#ifdef SIGTERM
    apr_signal(SIGTERM, signal_handler);
#endif
#ifdef SIGPIPE
    /* Disable SIGPIPE generation for the platforms that have it. */
    apr_signal(SIGPIPE, SIG_IGN);
#endif
#ifdef SIGXFSZ
    /* Disable SIGXFSZ generation for the platforms that have it, otherwise
     * working with large files when compiled against an APR that doesn't have
     * large file support will crash the program, which is uncool. */
    apr_signal(SIGXFSZ, SIG_IGN);
#endif

    received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));

    while (1)
    {
        int opt;
        const char *opt_arg;
        apr_status_t status = apr_getopt_long(os, svnrdump__options, &opt,
                                              &opt_arg);

        if (APR_STATUS_IS_EOF(status))
            break;
        if (status != APR_SUCCESS)
        {
            SVNRDUMP_ERR(usage(argv[0], pool));
            exit(EXIT_FAILURE);
        }

        /* Stash the option code in an array before parsing it. */
        APR_ARRAY_PUSH(received_opts, int) = opt;

        switch(opt)
        {
        case 'r':
        {
            /* Make sure we've not seen -r already. */
            if (opt_baton->start_revision.kind != svn_opt_revision_unspecified)
            {
                err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                       _("Multiple revision arguments "
                                         "encountered; try '-r N:M' instead "
                                         "of '-r N -r M'"));
                return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
            }
            /* Parse the -r argument. */
            if (svn_opt_parse_revision(&(opt_baton->start_revision),
                                       &(opt_baton->end_revision),
                                       opt_arg, pool) != 0)
            {
                const char *utf8_opt_arg;
                err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
                if (! err)
                    err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                            _("Syntax error in revision "
                                              "argument '%s'"), utf8_opt_arg);
                return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
            }
        }
        break;
        case 'q':
            opt_baton->quiet = TRUE;
            break;
        case opt_config_dir:
            config_dir = opt_arg;
            break;
        case opt_version:
            opt_baton->version = TRUE;
            break;
        case 'h':
            opt_baton->help = TRUE;
            break;
        case opt_auth_username:
            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
            break;
        case opt_auth_password:
            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
            break;
        case opt_auth_nocache:
            no_auth_cache = TRUE;
            break;
        case opt_non_interactive:
            non_interactive = TRUE;
            break;
        case opt_incremental:
            opt_baton->incremental = TRUE;
            break;
        case opt_trust_server_cert:
            trust_server_cert = TRUE;
            break;
        case opt_config_option:
            if (!config_options)
                config_options =
                    apr_array_make(pool, 1,
                                   sizeof(svn_cmdline__config_argument_t*));

            SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
            SVNRDUMP_ERR(svn_cmdline__parse_config_option(config_options,
                         opt_arg, pool));
        }
    }

    if (opt_baton->help)
    {
        subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
                     "help");
    }
    if (subcommand == NULL)
    {
        if (os->ind >= os->argc)
        {
            if (opt_baton->version)
            {
                /* Use the "help" subcommand to handle the "--version" option. */
                static const svn_opt_subcommand_desc2_t pseudo_cmd =
                {   "--version", help_cmd, {0}, "",
                    {   opt_version,  /* must accept its own option */
                        'q',  /* --quiet */
                    }
                };
                subcommand = &pseudo_cmd;
            }

            else
            {
                SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
                svn_pool_destroy(pool);
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            first_arg = os->argv[os->ind++];
            subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
                         first_arg);

            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, "svnrdump: ");
                svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                                                    _("Unknown command: '%s'\n"),
                                                    first_arg_utf8));
                SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
                svn_pool_destroy(pool);
                exit(EXIT_FAILURE);
            }
        }
    }

    /* Check that the subcommand wasn't passed any inappropriate options. */
    for (i = 0; i < received_opts->nelts; i++)
    {
        int opt_id = APR_ARRAY_IDX(received_opts, i, int);

        /* All commands implicitly accept --help, so just skip over this
           when we see it. Note that we don't want to include this option
           in their "accepted options" list because it would be awfully
           redundant to display it in every commands' help text. */
        if (opt_id == 'h' || opt_id == '?')
            continue;

        if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
        {
            const char *optstr;
            const apr_getopt_option_t *badopt =
                svn_opt_get_option_from_code2(opt_id, svnrdump__options,
                                              subcommand, pool);
            svn_opt_format_option(&optstr, badopt, FALSE, pool);
            if (subcommand->name[0] == '-')
                SVN_INT_ERR(help_cmd(NULL, NULL, pool));
            else
                svn_error_clear(svn_cmdline_fprintf(
                                    stderr, pool,
                                    _("Subcommand '%s' doesn't accept option '%s'\n"
                                      "Type 'svnrdump help %s' for usage.\n"),
                                    subcommand->name, optstr, subcommand->name));
            svn_pool_destroy(pool);
            return EXIT_FAILURE;
        }
    }

    if (subcommand && strcmp(subcommand->name, "--version") == 0)
    {
        SVNRDUMP_ERR(version(argv[0], opt_baton->quiet, pool));
        svn_pool_destroy(pool);
        exit(EXIT_SUCCESS);
    }

    if (subcommand && strcmp(subcommand->name, "help") == 0)
    {
        SVNRDUMP_ERR(help_cmd(os, opt_baton, pool));
        svn_pool_destroy(pool);
        exit(EXIT_SUCCESS);
    }

    /* --trust-server-cert can only be used with --non-interactive */
    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, "svnrdump: ");
    }

    /* Expect one more non-option argument:  the repository URL. */
    if (os->ind != os->argc - 1)
    {
        SVNRDUMP_ERR(usage(argv[0], pool));
        svn_pool_destroy(pool);
        exit(EXIT_FAILURE);
    }
    else
    {
        const char *repos_url;

        SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&repos_url,
                                             os->argv[os->ind], pool));
        if (! svn_path_is_url(repos_url))
        {
            err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
                                    "Target '%s' is not a URL",
                                    repos_url);
            SVNRDUMP_ERR(err);
            svn_pool_destroy(pool);
            exit(EXIT_FAILURE);
        }
        opt_baton->url = svn_uri_canonicalize(repos_url, pool);
    }

    SVNRDUMP_ERR(init_client_context(&(opt_baton->ctx),
                                     non_interactive,
                                     username,
                                     password,
                                     config_dir,
                                     no_auth_cache,
                                     trust_server_cert,
                                     config_options,
                                     pool));

    SVNRDUMP_ERR(svn_client_open_ra_session(&(opt_baton->session),
                                            opt_baton->url,
                                            opt_baton->ctx, pool));

    /* Have sane opt_baton->start_revision and end_revision defaults if
       unspecified.  */
    SVNRDUMP_ERR(svn_ra_get_latest_revnum(opt_baton->session,
                                          &latest_revision, pool));

    /* Make sure any provided revisions make sense. */
    SVNRDUMP_ERR(validate_and_resolve_revisions(opt_baton,
                 latest_revision, pool));

    /* Dispatch the subcommand */
    SVNRDUMP_ERR((*subcommand->cmd_func)(os, opt_baton, pool));

    svn_pool_destroy(pool);

    return EXIT_SUCCESS;
}
Beispiel #5
0
int
main(int argc, const char *argv[])
{
  const char *repos_path;
  apr_pool_t *pool;
  svn_boolean_t prop = FALSE, data = FALSE;
  svn_boolean_t quiet = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  const apr_getopt_option_t options[] =
    {
      {"data", OPT_DATA, 0, N_("display data reps stats")},
      {"prop", OPT_PROP, 0, N_("display prop reps stats")},
      {"both", OPT_BOTH, 0, N_("display combined (data+prop) reps stats")},
      {"quiet", 'q', 0, N_("no progress (only errors) to stderr")},
      {"help", 'h', 0, N_("display this help")},
      {"version", OPT_VERSION, 0,
       N_("show program version information")},
      {0,             0,  0,  0}
    };

  /* Initialize the app. */
  if (svn_cmdline_init("svn-rep-sharing-stats", 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, "svn-rep-sharing-stats: ");

  err = svn_cmdline__getopt_init(&os, argc, argv, pool);
  if (err)
    return svn_cmdline_handle_exit_error(err, pool, "svn-rep-sharing-stats: ");

  SVN_INT_ERR(check_experimental());

  os->interleave = 1;
  while (1)
    {
      int opt;
      const char *arg;
      apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(pool);
          return EXIT_FAILURE;
        }
      switch (opt)
        {
        case OPT_DATA:
          data = TRUE;
          break;
        /* It seems we don't actually rep-share props yet. */
        case OPT_PROP:
          prop = TRUE;
          break;
        case OPT_BOTH:
          data = TRUE;
          prop = TRUE;
          break;
        case 'q':
          quiet = TRUE;
          break;
        case 'h':
          help(options, pool);
          break;
        case OPT_VERSION:
          SVN_INT_ERR(version(pool));
          exit(0);
          break;
        default:
          usage(pool);
          return EXIT_FAILURE;
        }
    }

  /* Exactly 1 non-option argument,
   * and at least one of "--data"/"--prop"/"--both".
   */
  if (os->ind + 1 != argc || (!data && !prop))
    {
      usage(pool);
      return EXIT_FAILURE;
    }

  /* Grab REPOS_PATH from argv. */
  SVN_INT_ERR(svn_utf_cstring_to_utf8(&repos_path, os->argv[os->ind], pool));
  repos_path = svn_dirent_internal_style(repos_path, pool);

  set_up_cancellation();

  /* Do something. */
  SVN_INT_ERR(process(repos_path, prop, data, quiet, pool));

  /* We're done. */

  svn_pool_destroy(pool);
  /* Flush stdout to make sure that the user will see any printing errors. */
  SVN_INT_ERR(svn_cmdline_fflush(stdout));

  return EXIT_SUCCESS;
}
Beispiel #6
0
/*
 * 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)
{
  enum run_mode run_mode = run_mode_unspecified;
  svn_boolean_t foreground = FALSE;
  apr_socket_t *sock;
  apr_sockaddr_t *sa;
  svn_error_t *err;
  apr_getopt_t *os;
  int opt;
  serve_params_t params;
  const char *arg;
  apr_status_t status;
#ifndef WIN32
  apr_proc_t proc;
#endif
  svn_boolean_t is_multi_threaded;
  enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
  svn_boolean_t cache_fulltexts = TRUE;
  svn_boolean_t cache_txdeltas = TRUE;
  svn_boolean_t cache_revprops = FALSE;
  svn_boolean_t use_block_read = FALSE;
  apr_uint16_t port = SVN_RA_SVN_PORT;
  const char *host = NULL;
  int family = APR_INET;
  apr_int32_t sockaddr_info_flags = 0;
#if APR_HAVE_IPV6
  svn_boolean_t prefer_v6 = FALSE;
#endif
  svn_boolean_t quiet = FALSE;
  svn_boolean_t is_version = FALSE;
  int mode_opt_count = 0;
  int handling_opt_count = 0;
  const char *config_filename = NULL;
  const char *pid_filename = NULL;
  const char *log_filename = NULL;
  svn_node_kind_t kind;
  apr_size_t min_thread_count = THREADPOOL_MIN_SIZE;
  apr_size_t max_thread_count = THREADPOOL_MAX_SIZE;
#ifdef SVN_HAVE_SASL
  SVN_ERR(cyrus_init(pool));
#endif

  /* Check library versions */
  SVN_ERR(check_lib_versions());

  /* Initialize the FS library. */
  SVN_ERR(svn_fs_initialize(pool));

  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

  params.root = "/";
  params.tunnel = FALSE;
  params.tunnel_user = NULL;
  params.read_only = FALSE;
  params.base = NULL;
  params.cfg = NULL;
  params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
  params.logger = NULL;
  params.config_pool = NULL;
  params.authz_pool = NULL;
  params.fs_config = NULL;
  params.vhost = FALSE;
  params.username_case = CASE_ASIS;
  params.memory_cache_size = (apr_uint64_t)-1;
  params.zero_copy_limit = 0;
  params.error_check_interval = 4096;

  while (1)
    {
      status = apr_getopt_long(os, svnserve__options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(argv[0], pool);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
      switch (opt)
        {
        case '6':
#if APR_HAVE_IPV6
          prefer_v6 = TRUE;
#endif
          /* ### Maybe error here if we don't have IPV6 support? */
          break;

        case 'h':
          help(pool);
          return SVN_NO_ERROR;

        case 'q':
          quiet = TRUE;
          break;

        case SVNSERVE_OPT_VERSION:
          is_version = TRUE;
          break;

        case 'd':
          if (run_mode != run_mode_daemon)
            {
              run_mode = run_mode_daemon;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_FOREGROUND:
          foreground = TRUE;
          break;

        case SVNSERVE_OPT_SINGLE_CONN:
          handling_mode = connection_mode_single;
          handling_opt_count++;
          break;

        case 'i':
          if (run_mode != run_mode_inetd)
            {
              run_mode = run_mode_inetd;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_LISTEN_PORT:
          {
            apr_uint64_t val;

            err = svn_cstring_strtoui64(&val, arg, 0, APR_UINT16_MAX, 10);
            if (err)
              return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
                                       _("Invalid port '%s'"), arg);
            port = (apr_uint16_t)val;
          }
          break;

        case SVNSERVE_OPT_LISTEN_HOST:
          host = arg;
          break;

        case 't':
          if (run_mode != run_mode_tunnel)
            {
              run_mode = run_mode_tunnel;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_TUNNEL_USER:
          params.tunnel_user = arg;
          break;

        case 'X':
          if (run_mode != run_mode_listen_once)
            {
              run_mode = run_mode_listen_once;
              mode_opt_count++;
            }
          break;

        case 'r':
          SVN_ERR(svn_utf_cstring_to_utf8(&params.root, arg, pool));

          SVN_ERR(svn_io_check_resolved_path(params.root, &kind, pool));
          if (kind != svn_node_dir)
            {
              return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                       _("Root path '%s' does not exist "
                         "or is not a directory"), params.root);
            }

          params.root = svn_dirent_internal_style(params.root, pool);
          SVN_ERR(svn_dirent_get_absolute(&params.root, params.root, pool));
          break;

        case 'R':
          params.read_only = TRUE;
          break;

        case 'T':
          handling_mode = connection_mode_thread;
          handling_opt_count++;
          break;

        case 'c':
          params.compression_level = atoi(arg);
          if (params.compression_level < SVN_DELTA_COMPRESSION_LEVEL_NONE)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
          if (params.compression_level > SVN_DELTA_COMPRESSION_LEVEL_MAX)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_MAX;
          break;

        case 'M':
          params.memory_cache_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_CACHE_TXDELTAS:
          cache_txdeltas = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_FULLTEXTS:
          cache_fulltexts = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_REVPROPS:
          cache_revprops = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_BLOCK_READ:
          use_block_read = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CLIENT_SPEED:
          {
            apr_size_t bandwidth = (apr_size_t)apr_strtoi64(arg, NULL, 0);

            /* for slower clients, don't try anything fancy */
            if (bandwidth >= 1000)
              {
                /* block other clients for at most 1 ms (at full bandwidth).
                   Note that the send buffer is 16kB anyways. */
                params.zero_copy_limit = bandwidth * 120;

                /* check for aborted connections at the same rate */
                params.error_check_interval = bandwidth * 120;
              }
          }
          break;

        case SVNSERVE_OPT_MIN_THREADS:
          min_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_MAX_THREADS:
          max_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

#ifdef WIN32
        case SVNSERVE_OPT_SERVICE:
          if (run_mode != run_mode_service)
            {
              run_mode = run_mode_service;
              mode_opt_count++;
            }
          break;
#endif

        case SVNSERVE_OPT_CONFIG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&config_filename, arg, pool));
          config_filename = svn_dirent_internal_style(config_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&config_filename, config_filename,
                                          pool));
          break;

        case SVNSERVE_OPT_PID_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&pid_filename, arg, pool));
          pid_filename = svn_dirent_internal_style(pid_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&pid_filename, pid_filename, pool));
          break;

         case SVNSERVE_OPT_VIRTUAL_HOST:
           params.vhost = TRUE;
           break;

         case SVNSERVE_OPT_LOG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
          log_filename = svn_dirent_internal_style(log_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&log_filename, log_filename, pool));
          break;

        }
    }

  if (is_version)
    {
      SVN_ERR(version(quiet, pool));
      return SVN_NO_ERROR;
    }

  if (os->ind != argc)
    {
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (mode_opt_count != 1)
    {
      svn_error_clear(svn_cmdline_fputs(
#ifdef WIN32
                      _("You must specify exactly one of -d, -i, -t, "
                        "--service or -X.\n"),
#else
                      _("You must specify exactly one of -d, -i, -t or -X.\n"),
#endif
                       stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (handling_opt_count > 1)
    {
      svn_error_clear(svn_cmdline_fputs(
                      _("You may only specify one of -T or --single-thread\n"),
                      stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  /* construct object pools */
  is_multi_threaded = handling_mode == connection_mode_thread;
  params.fs_config = apr_hash_make(pool);
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
                cache_txdeltas ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                cache_fulltexts ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
                cache_revprops ? "2" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
                use_block_read ? "1" :"0");

  SVN_ERR(svn_repos__config_pool_create(&params.config_pool,
                                        is_multi_threaded,
                                        pool));
  SVN_ERR(svn_repos__authz_pool_create(&params.authz_pool,
                                       params.config_pool,
                                       is_multi_threaded,
                                       pool));

  /* If a configuration file is specified, load it and any referenced
   * password and authorization files. */
  if (config_filename)
    {
      params.base = svn_dirent_dirname(config_filename, pool);

      SVN_ERR(svn_repos__config_pool_get(&params.cfg, NULL,
                                         params.config_pool,
                                         config_filename,
                                         TRUE, /* must_exist */
                                         FALSE, /* names_case_sensitive */
                                         NULL,
                                         pool));
    }

  if (log_filename)
    SVN_ERR(logger__create(&params.logger, log_filename, pool));
  else if (run_mode == run_mode_listen_once)
    SVN_ERR(logger__create_for_stderr(&params.logger, pool));

  if (params.tunnel_user && run_mode != run_mode_tunnel)
    {
      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
               _("Option --tunnel-user is only valid in tunnel mode"));
    }

  if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
    {
      apr_pool_t *connection_pool;
      svn_ra_svn_conn_t *conn;
      svn_stream_t *stdin_stream;
      svn_stream_t *stdout_stream;

      params.tunnel = (run_mode == run_mode_tunnel);
      apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
                                redirect_stdout);

      SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
      SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));

      /* Use a subpool for the connection to ensure that if SASL is used
       * the pool cleanup handlers that call sasl_dispose() (connection_pool)
       * and sasl_done() (pool) are run in the right order. See issue #3664. */
      connection_pool = svn_pool_create(pool);
      conn = svn_ra_svn_create_conn4(NULL, stdin_stream, stdout_stream,
                                     params.compression_level,
                                     params.zero_copy_limit,
                                     params.error_check_interval,
                                     connection_pool);
      err = serve(conn, &params, connection_pool);
      svn_pool_destroy(connection_pool);

      return err;
    }

#ifdef WIN32
  /* If svnserve needs to run as a Win32 service, then we need to
     coordinate with the Service Control Manager (SCM) before
     continuing.  This function call registers the svnserve.exe
     process with the SCM, waits for the "start" command from the SCM
     (which will come very quickly), and confirms that those steps
     succeeded.

     After this call succeeds, the service is free to run.  At some
     point in the future, the SCM will send a message to the service,
     requesting that it stop.  This is translated into a call to
     winservice_notify_stop().  The service is then responsible for
     cleanly terminating.

     We need to do this before actually starting the service logic
     (opening files, sockets, etc.) because the SCM wants you to
     connect *first*, then do your service-specific logic.  If the
     service process takes too long to connect to the SCM, then the
     SCM will decide that the service is busted, and will give up on
     it.
     */
  if (run_mode == run_mode_service)
    {
      err = winservice_start();
      if (err)
        {
          svn_handle_error2(err, stderr, FALSE, "svnserve: ");

          /* This is the most common error.  It means the user started
             svnserve from a shell, and specified the --service
             argument.  svnserve cannot be started, as a service, in
             this way.  The --service argument is valid only valid if
             svnserve is started by the SCM. */
          if (err->apr_err ==
              APR_FROM_OS_ERROR(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT))
            {
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                  _("svnserve: The --service flag is only valid if the"
                    " process is started by the Service Control Manager.\n")));
            }

          svn_error_clear(err);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }

      /* The service is now in the "starting" state.  Before the SCM will
         consider the service "started", this thread must call the
         winservice_running() function. */
    }
#endif /* WIN32 */

  /* Make sure we have IPV6 support first before giving apr_sockaddr_info_get
     APR_UNSPEC, because it may give us back an IPV6 address even if we can't
     create IPV6 sockets. */

#if APR_HAVE_IPV6
#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status == 0)
    {
      apr_socket_close(sock);
      family = APR_UNSPEC;

      if (prefer_v6)
        {
          if (host == NULL)
            host = "::";
          sockaddr_info_flags = APR_IPV6_ADDR_OK;
        }
      else
        {
          if (host == NULL)
            host = "0.0.0.0";
          sockaddr_info_flags = APR_IPV4_ADDR_OK;
        }
    }
#endif

  status = apr_sockaddr_info_get(&sa, host, family, port,
                                 sockaddr_info_flags, pool);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't get address info"));
    }


#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't create server socket"));
    }

  /* Prevents "socket in use" errors when server is killed and quickly
   * restarted. */
  status = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't set options on server socket"));
    }

  status = apr_socket_bind(sock, sa);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't bind server socket"));
    }

  status = apr_socket_listen(sock, ACCEPT_BACKLOG);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't listen on server socket"));
    }

#if APR_HAS_FORK
  if (run_mode != run_mode_listen_once && !foreground)
    /* ### ignoring errors... */
    apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);

  apr_signal(SIGCHLD, sigchld_handler);
#endif

#ifdef SIGPIPE
  /* Disable SIGPIPE generation for the platforms that have it. */
  apr_signal(SIGPIPE, SIG_IGN);
#endif

#ifdef SIGXFSZ
  /* Disable SIGXFSZ generation for the platforms that have it, otherwise
   * working with large files when compiled against an APR that doesn't have
   * large file support will crash the program, which is uncool. */
  apr_signal(SIGXFSZ, SIG_IGN);
#endif

  if (pid_filename)
    SVN_ERR(write_pid_file(pid_filename, pool));

#ifdef WIN32
  status = apr_os_sock_get(&winservice_svnserve_accept_socket, sock);
  if (status)
    winservice_svnserve_accept_socket = INVALID_SOCKET;

  /* At this point, the service is "running".  Notify the SCM. */
  if (run_mode == run_mode_service)
    winservice_running();
#endif

  /* Configure FS caches for maximum efficiency with svnserve.
   * For pre-forked (i.e. multi-processed) mode of operation,
   * keep the per-process caches smaller than the default.
   * Also, apply the respective command line parameters, if given. */
  {
    svn_cache_config_t settings = *svn_cache_config_get();

    if (params.memory_cache_size != -1)
      settings.cache_size = params.memory_cache_size;

    settings.single_threaded = TRUE;
    if (handling_mode == connection_mode_thread)
      {
#if APR_HAS_THREADS
        settings.single_threaded = FALSE;
#else
        /* No requests will be processed at all
         * (see "switch (handling_mode)" code further down).
         * But if they were, some other synchronization code
         * would need to take care of securing integrity of
         * APR-based structures. That would include our caches.
         */
#endif
      }

    svn_cache_config_set(&settings);
  }

#if APR_HAS_THREADS
  SVN_ERR(svn_root_pools__create(&connection_pools));

  if (handling_mode == connection_mode_thread)
    {
      /* create the thread pool with a valid range of threads */
      if (max_thread_count < 1)
        max_thread_count = 1;
      if (min_thread_count > max_thread_count)
        min_thread_count = max_thread_count;

      status = apr_thread_pool_create(&threads,
                                      min_thread_count,
                                      max_thread_count,
                                      pool);
      if (status)
        {
          return svn_error_wrap_apr(status, _("Can't create thread pool"));
        }

      /* let idle threads linger for a while in case more requests are
         coming in */
      apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);

      /* don't queue requests unless we reached the worker thread limit */
      apr_thread_pool_threshold_set(threads, 0);
    }
  else
    {
      threads = NULL;
    }
#endif

  while (1)
    {
      connection_t *connection = NULL;
      SVN_ERR(accept_connection(&connection, sock, &params, handling_mode,
                                pool));
      if (run_mode == run_mode_listen_once)
        {
          err = serve_socket(connection, connection->pool);
          close_connection(connection);
          return err;
        }

      switch (handling_mode)
        {
        case connection_mode_fork:
#if APR_HAS_FORK
          status = apr_proc_fork(&proc, connection->pool);
          if (status == APR_INCHILD)
            {
              /* the child would't listen to the main server's socket */
              apr_socket_close(sock);

              /* serve_socket() logs any error it returns, so ignore it. */
              svn_error_clear(serve_socket(connection, connection->pool));
              close_connection(connection);
              return SVN_NO_ERROR;
            }
          else if (status != APR_INPARENT)
            {
              err = svn_error_wrap_apr(status, "apr_proc_fork");
              logger__log_error(params.logger, err, NULL, NULL);
              svn_error_clear(err);
            }
#endif
          break;

        case connection_mode_thread:
          /* Create a detached thread for each connection.  That's not a
             particularly sophisticated strategy for a threaded server, it's
             little different from forking one process per connection. */
#if APR_HAS_THREADS
          attach_connection(connection);

          status = apr_thread_pool_push(threads, serve_thread, connection,
                                        0, NULL);
          if (status)
            {
              return svn_error_wrap_apr(status, _("Can't push task"));
            }
#endif
          break;

        case connection_mode_single:
          /* Serve one connection at a time. */
          /* serve_socket() logs any error it returns, so ignore it. */
          svn_error_clear(serve_socket(connection, connection->pool));
        }

      close_connection(connection);
    }

  /* NOTREACHED */
}
Beispiel #7
0
/*
 * 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;
  struct svnauthz_opt_state opt_state = { 0 };
  apr_getopt_t *os;
  apr_array_header_t *received_opts;
  int i;

  /* Initialize the FS library. */
  SVN_ERR(svn_fs_initialize(pool));

  received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));

  /* Initialize opt_state */
  opt_state.username = opt_state.fspath = opt_state.repos_name = NULL;
  opt_state.txn = opt_state.repos_path = opt_state.groups_file = NULL;

  /* Parse options. */
  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
  os->interleave = 1;

  if (!use_compat_mode(argv[0], pool))
    {
      while (1)
        {
          int opt;
          const char *arg;
          apr_status_t status = apr_getopt_long(os, options_table, &opt, &arg);

          if (APR_STATUS_IS_EOF(status))
            break;
          if (status != APR_SUCCESS)
            {
              SVN_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }

          /* Stash the option code in an array before parsing it. */
          APR_ARRAY_PUSH(received_opts, int) = opt;

          switch (opt)
            {
            case 'h':
            case '?':
              opt_state.help = TRUE;
              break;
            case 't':
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.txn, arg, pool));
              break;
            case 'R':
              opt_state.recursive = TRUE;
              break;
            case svnauthz__version:
              opt_state.version = TRUE;
              break;
            case svnauthz__username:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.username, arg, pool));
              break;
            case svnauthz__path:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.fspath, arg, pool));
              opt_state.fspath = svn_fspath__canonicalize(opt_state.fspath,
                                                          pool);
              break;
            case svnauthz__repos:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_name, arg, pool));
              break;
            case svnauthz__is:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.is, arg, pool));
              break;
            case svnauthz__groups_file:
              SVN_ERR(
                  svn_utf_cstring_to_utf8(&opt_state.groups_file,
                                          arg, pool));
              break;
            default:
                {
                  SVN_ERR(subcommand_help(NULL, NULL, pool));
                  *exit_code = EXIT_FAILURE;
                  return SVN_NO_ERROR;
                }
            }
        }
    }
  else
    {
      /* Pre 1.8 compatibility mode. */
      if (argc == 1) /* No path argument */
        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
      else
        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "validate");
    }

  /* If the user asked for help, then the rest of the arguments are
     the names of subcommands to get help on (if any), or else they're
     just typos/mistakes.  Whatever the case, the subcommand to
     actually run is subcommand_help(). */
  if (opt_state.help)
    subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");

  if (subcommand == NULL)
    {
      if (os->ind >= os->argc)
        {
          if (opt_state.version)
            {
              /* Use the "help" subcommand to handle the "--version" option. */
              static const svn_opt_subcommand_desc2_t pseudo_cmd =
                { "--version", subcommand_help, {0}, "",
                  {svnauthz__version /* must accept its own option */ } };

              subcommand = &pseudo_cmd;
            }
          else
            {
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                                        ("subcommand argument required\n")));
              SVN_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }
        }
      else
        {
          const char *first_arg = os->argv[os->ind++];
          subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg);
          if (subcommand == NULL)
            {
              const char *first_arg_utf8;

              os->ind++;
              SVN_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_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }
        }
    }

  /* Every subcommand except `help' requires one or two non-option arguments.
     Parse them and store them in opt_state.*/
  if (subcommand->cmd_func != subcommand_help)
    {
      /* Consume a non-option argument (repos_path) if --transaction */
      if (opt_state.txn)
        {
          if (os->ind +2 != argc)
            {
              return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                      ("Repository and authz file arguments "
                                       "required"));
            }

          SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_path, os->argv[os->ind],
                                              pool));
          os->ind++;

          opt_state.repos_path = svn_dirent_internal_style(opt_state.repos_path, pool);
        }

      /* Exactly 1 non-option argument */
      if (os->ind + 1 != argc)
        {
          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                  ("Authz file argument required"));
        }

      /* Grab AUTHZ_FILE from argv. */
      SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.authz_file, os->argv[os->ind],
                                          pool));

      /* Canonicalize opt_state.authz_file appropriately. */
      SVN_ERR(canonicalize_access_file(&opt_state.authz_file,
                                           opt_state.authz_file,
                                           opt_state.txn != NULL, pool));

      /* Same for opt_state.groups_file if it is present. */
      if (opt_state.groups_file)
        {
          SVN_ERR(canonicalize_access_file(&opt_state.groups_file,
                                               opt_state.groups_file,
                                               opt_state.txn != NULL, pool));
        }
    }

  /* Check that the subcommand wasn't passed any inappropriate options. */
  for (i = 0; i < received_opts->nelts; i++)
    {
      int opt_id = APR_ARRAY_IDX(received_opts, i, int);

      /* All commands implicitly accept --help, so just skip over this
         when we see it. Note that we don't want to include this option
         in their "accepted options" list because it would be awfully
         redundant to display it in every commands' help text. */
      if (opt_id == 'h' || opt_id == '?')
        continue;

      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
        {
          const char *optstr;
          const apr_getopt_option_t *badopt =
            svn_opt_get_option_from_code2(opt_id, options_table, subcommand,
                                          pool);
          svn_opt_format_option(&optstr, badopt, FALSE, pool);
          if (subcommand->name[0] == '-')
            SVN_ERR(subcommand_help(NULL, NULL, pool));
          else
            svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                            ("Subcommand '%s' doesn't accept option '%s'\n"
                             "Type 'svnauthz help %s' for usage.\n"),
                            subcommand->name, optstr, subcommand->name));
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
    }

  /* Run the subcommand. */
  err = (*subcommand->cmd_func)(os, &opt_state, pool);

  if (err)
    {
      if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS
          || err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
        {
          /* For argument-related problems, suggest using the 'help'
             subcommand. */
          err = svn_error_quick_wrap(err,
                                     ("Try 'svnauthz help' for more info"));
        }
      else if (err->apr_err == SVN_ERR_AUTHZ_INVALID_CONFIG
               || err->apr_err == SVN_ERR_MALFORMED_FILE)
        {
          /* Follow our contract that says we exit with 1 if the file does not
             validate. */
          *exit_code = 1;
          return err;
        }
      else if (err->apr_err == SVN_ERR_AUTHZ_UNREADABLE
               || err->apr_err == SVN_ERR_AUTHZ_UNWRITABLE
               || err->apr_err == SVN_ERR_AUTHZ_PARTIALLY_READABLE)
        {
          /* Follow our contract that says we exit with 3 if --is does not
           * match. */
          *exit_code = 3;
          return err;
        }

      return err;
    }

  return SVN_NO_ERROR;
}
Beispiel #8
0
/*
 * 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.
 *
 * Why is this not an svn subcommand?  I have this vague idea that it could
 * be run as part of the build process, with the output embedded in the svn
 * program.  Obviously we don't want to have to run svn when building svn.
 */
static svn_error_t *
sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
  const char *wc_path, *trail_url;
  const char *local_abspath;
  svn_wc_revision_status_t *res;
  svn_boolean_t no_newline = FALSE, committed = FALSE;
  svn_error_t *err;
  apr_getopt_t *os;
  svn_wc_context_t *wc_ctx;
  svn_boolean_t quiet = FALSE;
  svn_boolean_t is_version = FALSE;
  const apr_getopt_option_t options[] =
    {
      {"no-newline", 'n', 0, N_("do not output the trailing newline")},
      {"committed",  'c', 0, N_("last changed rather than current revisions")},
      {"help", 'h', 0, N_("display this help")},
      {"version", SVNVERSION_OPT_VERSION, 0,
       N_("show program version information")},
      {"quiet",         'q', 0,
       N_("no progress (only errors) to stderr")},
      {0,             0,  0,  0}
    };

  /* Check library versions */
  SVN_ERR(check_lib_versions());

#if defined(WIN32) || defined(__CYGWIN__)
  /* Set the working copy administrative directory name. */
  if (getenv("SVN_ASP_DOT_NET_HACK"))
    {
      SVN_ERR(svn_wc_set_adm_dir("_svn", pool));
    }
#endif

  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

  os->interleave = 1;
  while (1)
    {
      int opt;
      const char *arg;
      apr_status_t status = apr_getopt_long(os, options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          *exit_code = EXIT_FAILURE;
          usage(pool);
          return SVN_NO_ERROR;
        }

      switch (opt)
        {
        case 'n':
          no_newline = TRUE;
          break;
        case 'c':
          committed = TRUE;
          break;
        case 'q':
          quiet = TRUE;
          break;
        case 'h':
          help(options, pool);
          return SVN_NO_ERROR;
        case SVNVERSION_OPT_VERSION:
          is_version = TRUE;
          break;
        default:
          *exit_code = EXIT_FAILURE;
          usage(pool);
          return SVN_NO_ERROR;
        }
    }

  if (is_version)
    {
      SVN_ERR(version(quiet, pool));
      return SVN_NO_ERROR;
    }
  if (os->ind > argc || os->ind < argc - 2)
    {
      *exit_code = EXIT_FAILURE;
      usage(pool);
      return SVN_NO_ERROR;
    }

  SVN_ERR(svn_utf_cstring_to_utf8(&wc_path,
                                  (os->ind < argc) ? os->argv[os->ind] : ".",
                                  pool));

  SVN_ERR(svn_opt__arg_canonicalize_path(&wc_path, wc_path, pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));

  if (os->ind+1 < argc)
    SVN_ERR(svn_utf_cstring_to_utf8(&trail_url, os->argv[os->ind+1], pool));
  else
    trail_url = NULL;

  err = svn_wc_revision_status2(&res, wc_ctx, local_abspath, trail_url,
                                committed, NULL, NULL, pool, pool);

  if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
              || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY))
    {
      svn_node_kind_t kind;
      svn_boolean_t special;

      svn_error_clear(err);

      SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &special, pool));

      if (special)
        SVN_ERR(svn_cmdline_printf(pool, _("Unversioned symlink%s"),
                                   no_newline ? "" : "\n"));
      else if (kind == svn_node_dir)
        SVN_ERR(svn_cmdline_printf(pool, _("Unversioned directory%s"),
                                   no_newline ? "" : "\n"));
      else if (kind == svn_node_file)
        SVN_ERR(svn_cmdline_printf(pool, _("Unversioned file%s"),
                                   no_newline ? "" : "\n"));
      else
        {
          SVN_ERR(svn_cmdline_fprintf(stderr, pool,
                                      kind == svn_node_none
                                       ? _("'%s' doesn't exist\n")
                                       : _("'%s' is of unknown type\n"),
                                      svn_dirent_local_style(local_abspath,
                                                             pool)));
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
      return SVN_NO_ERROR;
    }

  SVN_ERR(err);

  if (! SVN_IS_VALID_REVNUM(res->min_rev))
    {
      /* Local uncommitted modifications, no revision info was found. */
      SVN_ERR(svn_cmdline_printf(pool, _("Uncommitted local addition, "
                                         "copy or move%s"),
                                 no_newline ? "" : "\n"));
      return SVN_NO_ERROR;
    }

  /* Build compact '123[:456]M?S?' string. */
  SVN_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev));
  if (res->min_rev != res->max_rev)
    SVN_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev));
  if (res->modified)
    SVN_ERR(svn_cmdline_fputs("M", stdout, pool));
  if (res->switched)
    SVN_ERR(svn_cmdline_fputs("S", stdout, pool));
  if (res->sparse_checkout)
    SVN_ERR(svn_cmdline_fputs("P", stdout, pool));

  if (! no_newline)
    SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));

  return SVN_NO_ERROR;
}