El 17/09/17 a las 02:08, Stefan Sperling escribió:
> On Sun, Sep 17, 2017 at 01:06:14AM -0700, William Orr wrote:
>> Hey,
>>
>> This is my first patch to subversion, so please bear with me.
>>
>> This looks to address a very commonly requested feature: providing an
>> alternative for automated tools to provide a password to svn via piping
>> it in over an fd (similar to gnupg).
> 
> Hi William,
> 
> This looks good to me in principle and I support the idea.
> 
> Will the implementation of read_pass_from_fd() compile and work on Win32?
> We usually defer such operations to APR to avoid portability concerns.
> However, APR does not seem to offer an API which wraps fdopen().
> Whenever we bypass APR and use system APIs directly we need to support
> at least Unix-like systems and Win32.
> 
> We cannot change the parameter list of svn_cmdline_create_auth_baton2().
> The function is already part of a release, so changing it breaks our
> ABI compatibility promise. Instead, we can add a new function called
> svn_cmdline_create_auth_baton3() which has the additional parameter.
> The svn_cmdline_create_auth_baton2() interface can be implemented
> as a wrapper around our new version of this function.
> 
> Given that this is feature intends to support non-interactive usage,
> I wonder if it should depend on the --non-interactive option as well?
> And maybe we could then reduce the new option to --password-from-stdin?
> 
> Some tools already use stdin for a different purpose, though.
> E.g. 'svnrdump load' reads a dump file from stdin. But if we also extended
> such tools with an option to read their normal input from a file, we could
> make this idea work. "svnadmin load" already supports the -F (--file)
> option for this purpose. Scripts would have to pass the right combination
> of options: --non-interactive --password-from-stdin -F /tmp/my-dump-file
> If --password-from-stdin is used without --non-interactive and without
> -F then the program should error out and complain.
> 
> This idea also solves the portability question, since svn_stream_for_stdin2()
> or apr_file_open_flags_stdin() could be used to read a password from stdin.
> And we wouldn't need a new revision of svn_cmdline_create_auth_baton2()
> either because the client could pass the password as a string, as it
> does for the --password option.
> 
>> One outstanding concern that I couldn't find addressed is clearing out
>> memory that once contained passwords (like with memset_s or
>> explicit_bzero). If I missed a technique for doing this that exists in
>> svn already, please let me know so I can update the diff.
> 
> I don't think we have an API for that either, unfortunately. However,
> the same portability concerns apply. In any case, it would be great to
> have such an API available in APR.
> 
> Regards,
> Stefan
> 
>> Tested on Fedora 25 x86_64 and OpenBSD 6.1 x86_64.
>>
>> Please CC me; I'm not on this list.
>>
>> [[[
>> Introduce global opt --password-fd to allow applications to provide a
>> password over an already-opened file descriptor.
>>
>> * subversion/include/svn_cmdline.h
>>   (svn_cmdline_create_auth_baton2): Add `auth_password_fd` argument
>> * subversion/include/svn_error_codes.h
>>   (SVN_ERR_IO_PIPE_READ_ERROR): Undeprecate, as now used
>> * subversion/libsvn_subr/cmdline.c
>>   (read_pass_from_fd): Add static function to get password from a file
>> descriptor
>>   (svn_cmdline_create_auth_baton2): Add `auth_password_fd` arg and
>> trigger read of fd if this arg is not -1
>> * subversion/libsvn_subr/deprecated.c:
>>   (svn_cmdline_create_auth_baton): Add default val of -1 when calling
>> `svn_cmdline_create_auth_baton2`
>> * subversion/svn/svn.c
>>   (svn_cl__longopt_t): Add `opt_auth_password_fd` longopt
>>   (svn_cl__global_options): Add `opt_auth_password_fd` to global options
>>   (sub_main): Process global option `opt_auth_password_fd` and pass it
>> to `svn_cmdline_create_auth_baton2`
>> * subversion/svnmucc/svnmucc.c
>>   (sub_main): Process global option `opt_auth_password_fd` and pass it
>> to `svn_cmdline_create_auth_baton2`
>> * subversion/svnrdump/svnrdump.c
>>   (svn_svnrdump__longopt_t): add `opt_auth_password_fd`
>>   (svnrdump__options): add help message for `--password-fd`
>>   (init_client_context): Pass `auth_password_fd` to
>> `svn_cmdline_create_auth_baton2`
>>   (sub_main): Process global option `opt_auth_password_fd` and pass it
>> to `init_client_context`
>> * subversion/svnsync/svnsync.c
>>   (svnsync__opt): Add `svnsync_opt_source_password_fd` and
>> `svnsync_opt_sync_password_fd`
>>   (svnsync_options): Add help messages for `--source-password-fd` and
>> `--sync-password-fd`
>>   (opt_baton_t): Add `source_password_fd` and `sync_password_fd`
>>   (sub_main): Process global option `--source-password-fd` and
>> `--sync-password-fd` and pass it to `svn_cmdline_create_auth_baton2`
>> invocations
>> * subversion/tests/cmdline/atomic-ra-revprop-change.c
>>   (construct_auth_baton): Pass -1 as the `auth_password_fd`
>> * subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
>>   (): Add new `--password-fd` option to expected output
>> * subversion/tests/libsvn_ra/ra-test.c
>>   (check_tunnel_callback_test): Pass -1 as the `auth_password_fd`
>>   (tunnel_callback_test): Pass -1 as the `auth_password_fd`
>>   (tunnel_run_checkout): Pass -1 as the `auth_password_fd`
>> * subversion/tests/svn_test_main.c
>>   (svn_test__init_auth_baton): Pass -1 as the `auth_password_fd`
>> * tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
>>   (svn_min__opt_state_t): Add `auth_password_fd`
>> * tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
>>   (svn_min__longopt_t) Add `opt_auth_password_fd`
>>   (sub_main) Process global option `--password-fd` and pass it to
>> `svn_cmdline_create_auth_baton2` invocations
>> * tools/client-side/svnconflict/svnconflict.c
>>   (svnconflict_opt_state_t): Add `auth_password_fd`
>>   (svnconflict_options): Add `--password-fd` documentation
>>   (svnconflict_global_options): Add `opt_auth_password_fd`
>>   (sub_main): Process global option `--password-fd` and pass it to
>> `svn_cmdline_create_auth_baton2` invocations
>> * tools/dev/svnmover/svnmover.c
>>   (sub_main): Process global option `--password-fd` and pass it to
>> `svn_cmdline_create_auth_baton2` invocations
>> ]]]
> 

Hey,

Thanks for the feedback. I've finally gotten the chance to update the
patch with the suggestions. Lemme know if this addresses your concerns,
and I can write up the changelog for it.

Thanks,
William Orr

Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h	(revisión: 1811402)
+++ subversion/include/svn_io.h	(copia de trabajo)
@@ -2633,6 +2633,14 @@ svn_io_file_readline(apr_file_t *file,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool);
 
+/** Reads a string from stdin until a newline or EOF is found
+ *
+ * @since New in 1.9.
+ */
+svn_error_t *
+svn_io_stdin_readline(const char **result,
+                      apr_pool_t *pool);
+
 /** @} */
 
 #ifdef __cplusplus
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c	(revisión: 1811402)
+++ subversion/libsvn_subr/io.c	(copia de trabajo)
@@ -5440,3 +5440,19 @@ svn_io_file_readline(apr_file_t *file,
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_io_stdin_readline(const char **result,
+                       apr_pool_t *pool)
+{
+  svn_stringbuf_t *buf = NULL;
+  svn_stream_t *stdin = NULL;
+  svn_boolean_t oob = FALSE;
+
+  SVN_ERR(svn_stream_for_stdin2(&stdin, TRUE, pool));
+  SVN_ERR(svn_stream_readline(stdin, &buf, APR_EOL_STR, &oob, pool));
+
+  *result = buf->data;
+
+  return SVN_NO_ERROR;
+}
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h	(revisión: 1811402)
+++ subversion/svn/cl.h	(copia de trabajo)
@@ -178,6 +178,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t help;            /* print usage message */
   const char *auth_username;     /* auth username */
   const char *auth_password;     /* auth password */
+  svn_boolean_t auth_password_from_stdin; /* fd to read password from */
   const char *extensions;        /* subprocess extension args */
   apr_array_header_t *targets;   /* target list from file */
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
Index: subversion/svn/svn.c
===================================================================
--- subversion/svn/svn.c	(revisión: 1811402)
+++ subversion/svn/svn.c	(copia de trabajo)
@@ -68,6 +68,7 @@
    use the short option letter as identifier.  */
 typedef enum svn_cl__longopt_t {
   opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+  opt_auth_password_from_stdin,
   opt_auth_username,
   opt_autoprops,
   opt_changelist,
@@ -200,6 +201,9 @@ const apr_getopt_option_t svn_cl__options[] =
                     N_("specify a password ARG (caution: on many operating\n"
                        "                             "
                        "systems, other users will be able to see this)")},
+  {"password-from-stdin",
+                    opt_auth_password_from_stdin, 0,
+                    N_("read password from stdin")},
   {"extensions",    'x', 1,
                     N_("Specify differencing options for external diff or\n"
                        "                             "
@@ -495,7 +499,8 @@ const apr_getopt_option_t svn_cl__options[] =
    command to take these arguments allows scripts to just pass them
    willy-nilly to every invocation of 'svn') . */
 const int svn_cl__global_options[] =
-{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
+{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin,
+  opt_no_auth_cache, opt_non_interactive,
   opt_force_interactive, opt_trust_server_cert,
   opt_trust_server_cert_failures,
   opt_config_dir, opt_config_options, 0
@@ -1959,6 +1964,7 @@ sub_main(int *exit_code, int argc, const char *arg
   apr_hash_t *changelists;
   apr_hash_t *cfg_hash;
   svn_membuf_t buf;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
@@ -2251,6 +2257,9 @@ sub_main(int *exit_code, int argc, const char *arg
         SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
                                         opt_arg, pool));
         break;
+      case opt_auth_password_from_stdin:
+        read_pass_from_stdin = TRUE;
+        break;
       case opt_encoding:
         opt_state.encoding = apr_pstrdup(pool, opt_arg);
         break;
@@ -2745,6 +2754,14 @@ sub_main(int *exit_code, int argc, const char *arg
                                   "--non-interactive"));
     }
 
+  /* --password-from-stdin can only be used with --non-interactive */
+  if (read_pass_from_stdin && !opt_state.non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
   /* Disallow simultaneous use of both --diff-cmd and
      --internal-diff.  */
   if (opt_state.diff.diff_cmd && opt_state.diff.internal_diff)
@@ -3034,6 +3051,12 @@ sub_main(int *exit_code, int argc, const char *arg
                                    conflict_stats, pool));
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&opt_state.auth_password, pool);
+    }
+
   /* Set up our cancellation support. */
   svn_cl__check_cancel = svn_cmdline__setup_cancellation_handler();
   ctx->cancel_func = svn_cl__check_cancel;
Index: subversion/svnbench/svnbench.c
===================================================================
--- subversion/svnbench/svnbench.c	(revisión: 1811402)
+++ subversion/svnbench/svnbench.c	(copia de trabajo)
@@ -53,6 +53,7 @@
    use the short option letter as identifier.  */
 typedef enum svn_cl__longopt_t {
   opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+  opt_auth_password_from_stdin,
   opt_auth_username,
   opt_config_dir,
   opt_config_options,
@@ -112,6 +113,8 @@ const apr_getopt_option_t svn_cl__options[] =
   {"verbose",       'v', 0, N_("print extra information")},
   {"username",      opt_auth_username, 1, N_("specify a username ARG")},
   {"password",      opt_auth_password, 1, N_("specify a password ARG")},
+  {"password-from-stdin",
+                    opt_auth_password_from_stdin, 0, N_("read password from stdin")},
   {"targets",       opt_targets, 1,
                     N_("pass contents of file ARG as additional args")},
   {"depth",         opt_depth, 1,
@@ -197,7 +200,8 @@ const apr_getopt_option_t svn_cl__options[] =
    command to take these arguments allows scripts to just pass them
    willy-nilly to every invocation of 'svn') . */
 const int svn_cl__global_options[] =
-{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
+{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin,
+  opt_no_auth_cache, opt_non_interactive,
   opt_trust_server_cert, opt_trust_server_cert_failures,
   opt_config_dir, opt_config_options, 0
 };
@@ -394,6 +398,7 @@ sub_main(int *exit_code, int argc, const char *arg
   apr_time_t start_time, time_taken;
   ra_progress_baton_t ra_progress_baton = {0};
   svn_membuf_t buf;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
@@ -625,6 +630,9 @@ sub_main(int *exit_code, int argc, const char *arg
         SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
                                             opt_arg, pool));
         break;
+      case opt_auth_password_from_stdin:
+        read_pass_from_stdin = TRUE;
+        break;
       case opt_stop_on_copy:
         opt_state.stop_on_copy = TRUE;
         break;
@@ -842,6 +850,14 @@ sub_main(int *exit_code, int argc, const char *arg
                                   "--non-interactive"));
     }
 
+  /* --password-from-stdin can only be used with --non-interactive */
+  if (read_pass_from_stdin && !opt_state.non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
   /* Ensure that 'revision_ranges' has at least one item, and make
      'start_revision' and 'end_revision' match that item. */
   if (opt_state.revision_ranges->nelts == 0)
@@ -919,6 +935,12 @@ sub_main(int *exit_code, int argc, const char *arg
                                        pool));
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&opt_state.auth_password, pool);
+    }
+
   /* Set up our cancellation support. */
   svn_cl__check_cancel = svn_cmdline__setup_cancellation_handler();
   ctx->cancel_func = svn_cl__check_cancel;
Index: subversion/svnmucc/svnmucc.c
===================================================================
--- subversion/svnmucc/svnmucc.c	(revisión: 1811402)
+++ subversion/svnmucc/svnmucc.c	(copia de trabajo)
@@ -297,6 +297,7 @@ help(FILE *stream, apr_pool_t *pool)
       "  -F [--file] ARG        : read log message from file ARG\n"
       "  -u [--username] ARG    : commit the changes as username ARG\n"
       "  -p [--password] ARG    : use ARG as the password\n"
+      "  --password-from-stdin  : read password from stdin\n"
       "  -U [--root-url] ARG    : interpret all action URLs relative to ARG\n"
       "  -r [--revision] ARG    : use revision ARG as baseline for changes\n"
       "  --with-revprop ARG     : set revision property in the following format:\n"
@@ -480,7 +481,8 @@ sub_main(int *exit_code, int argc, const char *arg
     non_interactive_opt,
     force_interactive_opt,
     trust_server_cert_opt,
-    trust_server_cert_failures_opt
+    trust_server_cert_failures_opt,
+    password_from_stdin_opt
   };
   static const apr_getopt_option_t options[] = {
     {"message", 'm', 1, ""},
@@ -487,6 +489,7 @@ sub_main(int *exit_code, int argc, const char *arg
     {"file", 'F', 1, ""},
     {"username", 'u', 1, ""},
     {"password", 'p', 1, ""},
+    {"password-from-stdin", password_from_stdin_opt, 0, ""},
     {"root-url", 'U', 1, ""},
     {"revision", 'r', 1, ""},
     {"with-revprop",  with_revprop_opt, 1, ""},
@@ -527,6 +530,7 @@ sub_main(int *exit_code, int argc, const char *arg
   svn_client_ctx_t *ctx;
   struct log_message_baton lmb;
   int i;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   /* Check library versions */
   SVN_ERR(check_lib_versions());
@@ -572,6 +576,9 @@ sub_main(int *exit_code, int argc, const char *arg
         case 'p':
           password = apr_pstrdup(pool, arg);
           break;
+        case password_from_stdin_opt:
+          read_pass_from_stdin = TRUE;
+          break;
         case 'U':
           SVN_ERR(svn_utf_cstring_to_utf8(&root_url, arg, pool));
           if (! svn_path_is_url(root_url))
@@ -672,6 +679,15 @@ sub_main(int *exit_code, int argc, const char *arg
                                   "--non-interactive"));
     }
 
+  /* --password-from-stdin can only be used with --non-interactive */
+  if (read_pass_from_stdin && !non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
+
   /* Copy the rest of our command-line arguments to an array,
      UTF-8-ing them along the way. */
   action_args = apr_array_make(pool, opts->argc, sizeof(const char *));
@@ -721,6 +737,12 @@ sub_main(int *exit_code, int argc, const char *arg
                                             "svnmucc: ", "--config-option"));
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&password, pool);
+    }
+
   SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
 
   cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);
Index: subversion/svnrdump/svnrdump.c
===================================================================
--- subversion/svnrdump/svnrdump.c	(revisión: 1811402)
+++ subversion/svnrdump/svnrdump.c	(copia de trabajo)
@@ -59,6 +59,7 @@ enum svn_svnrdump__longopt_t
     opt_config_option,
     opt_auth_username,
     opt_auth_password,
+    opt_auth_password_from_stdin,
     opt_auth_nocache,
     opt_non_interactive,
     opt_skip_revprop,
@@ -66,7 +67,7 @@ enum svn_svnrdump__longopt_t
     opt_incremental,
     opt_trust_server_cert,
     opt_trust_server_cert_failures,
-    opt_version
+    opt_version,
   };
 
 #define SVN_SVNRDUMP__BASE_OPTIONS opt_config_dir, \
@@ -73,6 +74,7 @@ enum svn_svnrdump__longopt_t
                                    opt_config_option, \
                                    opt_auth_username, \
                                    opt_auth_password, \
+                                   opt_auth_password_from_stdin, \
                                    opt_auth_nocache, \
                                    opt_trust_server_cert, \
                                    opt_trust_server_cert_failures, \
@@ -114,6 +116,8 @@ static const apr_getopt_option_t svnrdump__options
                       N_("specify a username ARG")},
     {"password",      opt_auth_password, 1,
                       N_("specify a password ARG")},
+    {"password-from-stdin",   opt_auth_password_from_stdin, 0,
+                      N_("read password from stdin")},
     {"non-interactive", opt_non_interactive, 0,
                       N_("do no interactive prompting (default is to prompt\n"
                          "                             "
@@ -154,6 +158,7 @@ static const apr_getopt_option_t svnrdump__options
                        "valid certificate) and 'other' (all other not\n"
                        "                             "
                        "separately classified certificate errors).")},
+    {"dumpfile", 'F', 1, N_("Read or write to a dumpfile instead of stdin/stdout")},
     {0, 0, 0, 0}
   };
 
@@ -174,6 +179,7 @@ typedef struct opt_baton_t {
   svn_client_ctx_t *ctx;
   svn_ra_session_t *session;
   const char *url;
+  const char *dumpfile;
   svn_boolean_t help;
   svn_boolean_t version;
   svn_opt_revision_t start_revision;
@@ -366,7 +372,8 @@ init_client_context(svn_client_ctx_t **ctx_p,
 
   /* Default authentication providers for non-interactive use */
   SVN_ERR(svn_cmdline_create_auth_baton2(&(ctx->auth_baton), non_interactive,
-                                         username, password, config_dir,
+                                         username, password,
+                                         config_dir,
                                          no_auth_cache, trust_unknown_ca,
                                          trust_cn_mismatch, trust_expired,
                                          trust_not_yet_valid,
@@ -463,31 +470,39 @@ replay_revisions(svn_ra_session_t *session,
                  svn_revnum_t end_revision,
                  svn_boolean_t quiet,
                  svn_boolean_t incremental,
+                 const char *dumpfile,
                  apr_pool_t *pool)
 {
   struct replay_baton *replay_baton;
   const char *uuid;
-  svn_stream_t *stdout_stream;
+  svn_stream_t *dump_stream;
 
-  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_writable(&dump_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdout(&dump_stream, pool));
+    }
 
   replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
-  replay_baton->stdout_stream = stdout_stream;
+  replay_baton->stdout_stream = dump_stream;
   replay_baton->extra_ra_session = extra_ra_session;
   replay_baton->quiet = quiet;
 
   /* Write the magic header and UUID */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
+  SVN_ERR(svn_stream_printf(dump_stream, pool,
                             SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
                             SVN_REPOS_DUMPFILE_FORMAT_VERSION));
   SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
+  SVN_ERR(svn_stream_printf(dump_stream, pool,
                             SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));
 
   /* Fake revision 0 if necessary */
   if (start_revision == 0)
     {
-      SVN_ERR(dump_revision_header(session, stdout_stream,
+      SVN_ERR(dump_revision_header(session, dump_stream,
                                    start_revision, pool));
 
       /* Revision 0 has no tree changes, so we're done. */
@@ -506,7 +521,7 @@ replay_revisions(svn_ra_session_t *session,
   if (!incremental)
     {
       SVN_ERR(dump_initial_full_revision(session, extra_ra_session,
-                                         stdout_stream, start_revision,
+                                         dump_stream, start_revision,
                                          quiet, pool));
       start_revision++;
     }
@@ -538,16 +553,23 @@ replay_revisions(svn_ra_session_t *session,
 static svn_error_t *
 load_revisions(svn_ra_session_t *session,
                svn_ra_session_t *aux_session,
-               const char *url,
+               const char *dumpfile,
                svn_boolean_t quiet,
                apr_hash_t *skip_revprops,
                apr_pool_t *pool)
 {
-  svn_stream_t *stdin_stream;
+  svn_stream_t *dump_stream;
 
-  SVN_ERR(svn_stream_for_stdin2(&stdin_stream, TRUE, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_readonly(&dump_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdin2(&dump_stream, TRUE, pool));
+    }
 
-  SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session,
+  SVN_ERR(svn_rdump__load_dumpstream(dump_stream, session, aux_session,
                                      quiet, skip_revprops,
                                      check_cancel, NULL, pool));
 
@@ -616,7 +638,8 @@ dump_cmd(apr_getopt_t *os,
   return replay_revisions(opt_baton->session, extra_ra_session,
                           opt_baton->start_revision.value.number,
                           opt_baton->end_revision.value.number,
-                          opt_baton->quiet, opt_baton->incremental, pool);
+                          opt_baton->quiet, opt_baton->incremental,
+                          opt_baton->dumpfile, pool);
 }
 
 /* Handle the "load" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -630,8 +653,9 @@ load_cmd(apr_getopt_t *os,
 
   SVN_ERR(svn_client_open_ra_session2(&aux_session, opt_baton->url, NULL,
                                       opt_baton->ctx, pool, pool));
-  return load_revisions(opt_baton->session, aux_session, opt_baton->url,
-                        opt_baton->quiet, opt_baton->skip_revprops, pool);
+  return load_revisions(opt_baton->session, aux_session,
+                        opt_baton->dumpfile, opt_baton->quiet,
+                        opt_baton->skip_revprops, pool);
 }
 
 /* Handle the "help" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -772,6 +796,7 @@ sub_main(int *exit_code, int argc, const char *arg
   apr_getopt_t *os;
   apr_array_header_t *received_opts;
   int i;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
   opt_baton->start_revision.kind = svn_opt_revision_unspecified;
@@ -778,6 +803,7 @@ sub_main(int *exit_code, int argc, const char *arg
   opt_baton->end_revision.kind = svn_opt_revision_unspecified;
   opt_baton->url = NULL;
   opt_baton->skip_revprops = apr_hash_make(pool);
+  opt_baton->dumpfile = NULL;
 
   SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
@@ -850,6 +876,9 @@ sub_main(int *exit_code, int argc, const char *arg
         case opt_auth_password:
           SVN_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
           break;
+        case opt_auth_password_from_stdin:
+          read_pass_from_stdin = TRUE;
+          break;
         case opt_auth_nocache:
           no_auth_cache = TRUE;
           break;
@@ -890,6 +919,11 @@ sub_main(int *exit_code, int argc, const char *arg
                                                      opt_arg, 
                                                      "svnrdump: ",
                                                      pool));
+          break;
+        case 'F':
+          SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+          opt_baton->dumpfile = opt_arg;
+          break;
         }
     }
 
@@ -1005,6 +1039,20 @@ sub_main(int *exit_code, int argc, const char *arg
                                   "--non-interactive"));
     }
 
+  if (read_pass_from_stdin && !non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
+  if (strcmp(subcommand->name, "load") == 0)
+    {
+      if (read_pass_from_stdin)
+        {
+        }
+    }
+
   /* Expect one more non-option argument:  the repository URL. */
   if (os->ind != os->argc - 1)
     {
@@ -1039,9 +1087,16 @@ sub_main(int *exit_code, int argc, const char *arg
         force_interactive = (username == NULL || password == NULL);
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&password, pool);
+    }
+
   non_interactive = !svn_cmdline__be_interactive(non_interactive,
                                                  force_interactive);
 
+
   SVN_ERR(init_client_context(&(opt_baton->ctx),
                               non_interactive,
                               username,
Index: subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout	(revisión: 1811402)
+++ subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout	(copia de trabajo)
@@ -134,6 +134,7 @@ Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG (caution: on many operating
                              systems, other users will be able to see this)
+  --password-from-stdin    : read password from stdin
   --no-auth-cache          : do not cache authentication tokens
   --non-interactive        : do no interactive prompting (default is to prompt
                              only if standard input is a terminal device)
@@ -224,6 +225,7 @@ Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG (caution: on many operating
                              systems, other users will be able to see this)
+  --password-from-stdin    : read password from stdin
   --no-auth-cache          : do not cache authentication tokens
   --non-interactive        : do no interactive prompting (default is to prompt
                              only if standard input is a terminal device)
Index: tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
===================================================================
--- tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c	(revisión: 1811402)
+++ tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c	(copia de trabajo)
@@ -68,6 +68,7 @@
    use the short option letter as identifier.  */
 typedef enum svn_min__longopt_t {
   opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+  opt_auth_password_from_stdin,
   opt_auth_username,
   opt_config_dir,
   opt_config_options,
@@ -113,6 +114,9 @@ const apr_getopt_option_t svn_min__options[] =
                     N_("specify a password ARG (caution: on many operating\n"
                        "                             "
                        "systems, other users will be able to see this)")},
+  {"password-from-stdin",
+                    opt_auth_password_from_stdin, 0,
+                    N_("read password from stdin")},
   {"targets",       opt_targets, 1,
                     N_("pass contents of file ARG as additional args")},
   {"depth",         opt_depth, 1,
@@ -209,11 +213,11 @@ const apr_getopt_option_t svn_min__options[] =
    command to take these arguments allows scripts to just pass them
    willy-nilly to every invocation of 'svn') . */
 const int svn_min__global_options[] =
-{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
-  opt_force_interactive, opt_trust_server_cert,
-  opt_trust_server_cert_unknown_ca, opt_trust_server_cert_cn_mismatch,
-  opt_trust_server_cert_expired, opt_trust_server_cert_not_yet_valid,
-  opt_trust_server_cert_other_failure,
+{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin,
+  opt_no_auth_cache, opt_non_interactive, opt_force_interactive,
+  opt_trust_server_cert, opt_trust_server_cert_unknown_ca,
+  opt_trust_server_cert_cn_mismatch, opt_trust_server_cert_expired,
+  opt_trust_server_cert_not_yet_valid, opt_trust_server_cert_other_failure,
   opt_config_dir, opt_config_options, 0
 };
 
@@ -417,6 +421,7 @@ sub_main(int *exit_code, int argc, const char *arg
   svn_boolean_t interactive_conflicts = FALSE;
   svn_boolean_t force_interactive = FALSE;
   apr_hash_t *cfg_hash;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
@@ -528,6 +533,9 @@ sub_main(int *exit_code, int argc, const char *arg
         SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
                                         opt_arg, pool));
         break;
+      case opt_auth_password_from_stdin:
+        read_pass_from_stdin = TRUE;
+        break;
       case opt_no_auth_cache:
         opt_state.no_auth_cache = TRUE;
         break;
@@ -606,6 +614,14 @@ sub_main(int *exit_code, int argc, const char *arg
                                   opt_state.non_interactive,
                                   force_interactive);
 
+  /* --password-from-stdin can only be used with --non-interactive */
+  if (read_pass_from_stdin && !opt_state.non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
   /* ### This really belongs in libsvn_client.  The trouble is,
      there's no one place there to run it from, no
      svn_client_init().  We'd have to add it to all the public
@@ -788,6 +804,12 @@ sub_main(int *exit_code, int argc, const char *arg
   }
 #endif
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&opt_state.auth_password, pool);
+    }
+
   /* Create a client context object. */
   command_baton.opt_state = &opt_state;
   SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
Index: tools/client-side/svnconflict/svnconflict.c
===================================================================
--- tools/client-side/svnconflict/svnconflict.c	(revisión: 1811402)
+++ tools/client-side/svnconflict/svnconflict.c	(copia de trabajo)
@@ -78,6 +78,7 @@ typedef struct svnconflict_cmd_baton_t
    use the short option letter as identifier.  */
 typedef enum svnconflict_longopt_t {
   opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+  opt_auth_password_from_stdin,
   opt_auth_username,
   opt_config_dir,
   opt_config_options,
@@ -96,6 +97,9 @@ static const apr_getopt_option_t svnconflict_optio
                     N_("specify a password ARG (caution: on many operating\n"
                        "                             "
                        "systems, other users will be able to see this)")},
+  {"password-from-stdin",
+                    opt_auth_password_from_stdin, 0,
+                    N_("read password from stdin")},
   {"config-dir",    opt_config_dir, 1,
                     N_("read user configuration files from directory ARG")},
   {"config-option", opt_config_options, 1,
@@ -141,7 +145,8 @@ static svn_error_t * svnconflict_resolve_tree(apr_
 
 /* Options that apply to all commands. */
 static const int svnconflict_global_options[] =
-{ opt_auth_username, opt_auth_password, opt_config_dir, opt_config_options, 0 };
+{ opt_auth_username, opt_auth_password, opt_auth_password_from_stdin,
+  opt_config_dir, opt_config_options, 0 };
 
 static const svn_opt_subcommand_desc2_t svnconflict_cmd_table[] =
 {
@@ -639,6 +644,7 @@ sub_main(int *exit_code, int argc, const char *arg
   svn_auth_baton_t *ab;
   svn_config_t *cfg_config;
   apr_hash_t *cfg_hash;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
 
@@ -704,6 +710,9 @@ sub_main(int *exit_code, int argc, const char *arg
         SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
                                         opt_arg, pool));
         break;
+      case opt_auth_password_from_stdin:
+        read_pass_from_stdin = TRUE;
+        break;
       case opt_config_dir:
         SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
         opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool);
@@ -845,6 +854,13 @@ sub_main(int *exit_code, int argc, const char *arg
 
   cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&opt_state.auth_password, pool);
+    }
+
+
   /* Create a client context object. */
   command_baton.opt_state = &opt_state;
   SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
Index: tools/dev/svnmover/svnmover.c
===================================================================
--- tools/dev/svnmover/svnmover.c	(revisión: 1811402)
+++ tools/dev/svnmover/svnmover.c	(copia de trabajo)
@@ -4332,7 +4332,8 @@ sub_main(int *exit_code, int argc, const char *arg
     trust_server_cert_opt,
     trust_server_cert_failures_opt,
     ui_opt,
-    colour_opt
+    colour_opt,
+    auth_password_from_stdin_opt
   };
   static const apr_getopt_option_t options[] = {
     {"verbose", 'v', 0, ""},
@@ -4341,6 +4342,7 @@ sub_main(int *exit_code, int argc, const char *arg
     {"file", 'F', 1, ""},
     {"username", 'u', 1, ""},
     {"password", 'p', 1, ""},
+    {"password-from-stdin", auth_password_from_stdin_opt, 1, ""},
     {"root-url", 'U', 1, ""},
     {"revision", 'r', 1, ""},
     {"branch-id", 'B', 1, ""},
@@ -4387,6 +4389,7 @@ sub_main(int *exit_code, int argc, const char *arg
   const char *log_msg;
   svn_tristate_t coloured_output = svn_tristate_false;
   svnmover_wc_t *wc;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   /* Check library versions */
   SVN_ERR(check_lib_versions());
@@ -4431,6 +4434,9 @@ sub_main(int *exit_code, int argc, const char *arg
         case 'p':
           password = apr_pstrdup(pool, arg);
           break;
+        case auth_password_from_stdin_opt:
+          read_pass_from_stdin = TRUE;
+          break;
         case 'U':
           SVN_ERR(svn_utf_cstring_to_utf8(&anchor_url, arg, pool));
           if (! svn_path_is_url(anchor_url))
@@ -4553,6 +4559,13 @@ sub_main(int *exit_code, int argc, const char *arg
                                   "--non-interactive"));
     }
 
+  /* --password-from-stdin can only be used with --non-interactive */
+  if (read_pass_from_stdin && !non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
 
   /* Now initialize the client context */
 
@@ -4580,6 +4593,12 @@ sub_main(int *exit_code, int argc, const char *arg
                                             "svnmover: ", "--config-option"));
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      svn_io_stdin_readline(&password, pool);
+    }
+
   SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
 
   cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);

Reply via email to