2 * cmdline.c : Helpers for command-line programs.
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
20 #include <stdlib.h> /* for atexit() */
21 #include <stdio.h> /* for setvbuf() */
22 #include <locale.h> /* for setlocale() */
25 #include <sys/types.h>
31 #include <apr_errno.h> /* for apr_strerror */
32 #include <apr_general.h> /* for apr_initialize/apr_terminate */
33 #include <apr_atomic.h> /* for apr_atomic_init */
34 #include <apr_strings.h> /* for apr_snprintf */
35 #include <apr_pools.h>
37 #include "svn_cmdline.h"
40 #include "svn_pools.h"
41 #include "svn_error.h"
46 #include "svn_private_config.h"
48 #include "win32_crashrpt.h"
50 /* The stdin encoding. If null, it's the same as the native encoding. */
51 static const char *input_encoding
= NULL
;
53 /* The stdout encoding. If null, it's the same as the native encoding. */
54 static const char *output_encoding
= NULL
;
58 svn_cmdline_init(const char *progname
, FILE *error_stream
)
67 /* The following makes sure that file descriptors 0 (stdin), 1
68 (stdout) and 2 (stderr) will not be "reused", because if
69 e.g. file descriptor 2 would be reused when opening a file, a
70 write to stderr would write to that file and most likely
73 /* Even with the UTF support in V5R4 a few functions on OS400 don't
74 * support UTF-8 string arguments and require EBCDIC paths, including
78 if ((fstat(0, &st
) == -1 && open("/dev/null", O_RDONLY
) == -1) ||
79 (fstat(1, &st
) == -1 && open("/dev/null", O_WRONLY
) == -1) ||
80 (fstat(2, &st
) == -1 && open("/dev/null", O_WRONLY
) == -1))
86 fprintf(error_stream
, "%s: error: cannot open '/dev/null'\n",
93 /* Ignore any errors encountered while attempting to change stream
94 buffering, as the streams should retain their default buffering
97 setvbuf(error_stream
, NULL
, _IONBF
, 0);
99 setvbuf(stdout
, NULL
, _IOLBF
, 0);
104 /* Initialize the input and output encodings. */
106 static char input_encoding_buffer
[16];
107 static char output_encoding_buffer
[16];
109 apr_snprintf(input_encoding_buffer
, sizeof input_encoding_buffer
,
110 "CP%u", (unsigned) GetConsoleCP());
111 input_encoding
= input_encoding_buffer
;
113 apr_snprintf(output_encoding_buffer
, sizeof output_encoding_buffer
,
114 "CP%u", (unsigned) GetConsoleOutputCP());
115 output_encoding
= output_encoding_buffer
;
117 #endif /* _MSC_VER < 1400 */
119 #ifdef SVN_USE_WIN32_CRASHHANDLER
120 /* Attach (but don't load) the crash handler */
121 SetUnhandledExceptionFilter(svn__unhandled_exception_filter
);
126 /* C programs default to the "C" locale. But because svn is supposed
127 to be i18n-aware, it should inherit the default locale of its
129 if (!setlocale(LC_ALL
, "")
130 && !setlocale(LC_CTYPE
, ""))
134 const char *env_vars
[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL
};
135 const char **env_var
= &env_vars
[0], *env_val
= NULL
;
138 env_val
= getenv(*env_var
);
139 if (env_val
&& env_val
[0])
146 /* Unlikely. Can setlocale fail if no env vars are set? */
151 fprintf(error_stream
,
152 "%s: warning: cannot set LC_CTYPE locale\n"
153 "%s: warning: environment variable %s is %s\n"
154 "%s: warning: please check that your locale name is correct\n",
155 progname
, progname
, *env_var
, env_val
, progname
);
159 /* Initialize the APR subsystem, and register an atexit() function
160 to Uninitialize that subsystem at program exit. */
161 status
= apr_initialize();
167 apr_strerror(status
, buf
, sizeof(buf
) - 1);
168 fprintf(error_stream
,
169 "%s: error: cannot initialize APR: %s\n",
175 /* This has to happen before any pools are created. */
176 svn_dso_initialize();
178 if (0 > atexit(apr_terminate
))
181 fprintf(error_stream
,
182 "%s: error: atexit registration failed\n",
187 /* Create a pool for use by the UTF-8 routines. It will be cleaned
188 up by APR at exit time. */
189 pool
= svn_pool_create(NULL
);
190 svn_utf_initialize(pool
);
193 svn_error_t
*err
= svn_nls_init();
196 if (error_stream
&& err
->message
)
197 fprintf(error_stream
, "%s", err
->message
);
199 svn_error_clear(err
);
209 svn_cmdline_cstring_from_utf8(const char **dest
,
213 if (output_encoding
== NULL
)
214 return svn_utf_cstring_from_utf8(dest
, src
, pool
);
216 return svn_utf_cstring_from_utf8_ex2(dest
, src
, output_encoding
, pool
);
221 svn_cmdline_cstring_from_utf8_fuzzy(const char *src
,
224 return svn_utf__cstring_from_utf8_fuzzy(src
, pool
,
225 svn_cmdline_cstring_from_utf8
);
230 svn_cmdline_cstring_to_utf8(const char **dest
,
234 if (input_encoding
== NULL
)
235 return svn_utf_cstring_to_utf8(dest
, src
, pool
);
237 return svn_utf_cstring_to_utf8_ex2(dest
, src
, input_encoding
, pool
);
242 svn_cmdline_path_local_style_from_utf8(const char **dest
,
246 return svn_cmdline_cstring_from_utf8(dest
,
247 svn_path_local_style(src
, pool
),
252 svn_cmdline_printf(apr_pool_t
*pool
, const char *fmt
, ...)
257 /* A note about encoding issues:
258 * APR uses the execution character set, but here we give it UTF-8 strings,
259 * both the fmt argument and any other string arguments. Since apr_pvsprintf
260 * only cares about and produces ASCII characters, this works under the
261 * assumption that all supported platforms use an execution character set
262 * with ASCII as a subset.
266 message
= apr_pvsprintf(pool
, fmt
, ap
);
269 return svn_cmdline_fputs(message
, stdout
, pool
);
273 svn_cmdline_fprintf(FILE *stream
, apr_pool_t
*pool
, const char *fmt
, ...)
278 /* See svn_cmdline_printf () for a note about character encoding issues. */
281 message
= apr_pvsprintf(pool
, fmt
, ap
);
284 return svn_cmdline_fputs(message
, stream
, pool
);
288 svn_cmdline_fputs(const char *string
, FILE* stream
, apr_pool_t
*pool
)
293 err
= svn_cmdline_cstring_from_utf8(&out
, string
, pool
);
297 svn_error_clear(err
);
298 out
= svn_cmdline_cstring_from_utf8_fuzzy(string
, pool
);
301 /* On POSIX systems, errno will be set on an error in fputs, but this might
302 not be the case on other platforms. We reset errno and only
303 use it if it was set by the below fputs call. Else, we just return
307 if (fputs(out
, stream
) == EOF
)
310 return svn_error_wrap_apr(errno
, _("Write error"));
312 return svn_error_create
313 (SVN_ERR_IO_WRITE_ERROR
, NULL
, NULL
);
320 svn_cmdline_fflush(FILE *stream
)
322 /* See comment in svn_cmdline_fputs about use of errno and stdio. */
324 if (fflush(stream
) == EOF
)
327 return svn_error_wrap_apr(errno
, _("Write error"));
329 return svn_error_create(SVN_ERR_IO_WRITE_ERROR
, NULL
, NULL
);
335 const char *svn_cmdline_output_encoding(apr_pool_t
*pool
)
338 return apr_pstrdup(pool
, output_encoding
);
340 return SVN_APR_LOCALE_CHARSET
;
344 svn_cmdline_handle_exit_error(svn_error_t
*err
,
348 svn_handle_error2(err
, stderr
, FALSE
, prefix
);
349 svn_error_clear(err
);
351 svn_pool_destroy(pool
);
356 svn_cmdline_setup_auth_baton(svn_auth_baton_t
**ab
,
357 svn_boolean_t non_interactive
,
358 const char *auth_username
,
359 const char *auth_password
,
360 const char *config_dir
,
361 svn_boolean_t no_auth_cache
,
363 svn_cancel_func_t cancel_func
,
367 svn_boolean_t store_password_val
= TRUE
;
368 svn_auth_provider_object_t
*provider
;
370 /* The whole list of registered providers */
371 apr_array_header_t
*providers
372 = apr_array_make(pool
, 12, sizeof(svn_auth_provider_object_t
*));
374 /* The main disk-caching auth providers, for both
375 'username/password' creds and 'username' creds. */
376 #if defined(WIN32) && !defined(__MINGW32__)
377 svn_auth_get_windows_simple_provider(&provider
, pool
);
378 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
380 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
381 svn_auth_get_keychain_simple_provider(&provider
, pool
);
382 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
384 svn_auth_get_simple_provider(&provider
, pool
);
385 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
386 svn_auth_get_username_provider(&provider
, pool
);
387 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
389 /* The server-cert, client-cert, and client-cert-password providers. */
390 #if defined(WIN32) && !defined(__MINGW32__)
391 svn_auth_get_windows_ssl_server_trust_provider(&provider
, pool
);
392 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
394 svn_auth_get_ssl_server_trust_file_provider(&provider
, pool
);
395 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
396 svn_auth_get_ssl_client_cert_file_provider(&provider
, pool
);
397 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
398 svn_auth_get_ssl_client_cert_pw_file_provider(&provider
, pool
);
399 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
401 if (non_interactive
== FALSE
)
403 svn_cmdline_prompt_baton_t
*pb
= NULL
;
407 pb
= apr_palloc(pool
, sizeof(*pb
));
409 pb
->cancel_func
= cancel_func
;
410 pb
->cancel_baton
= cancel_baton
;
413 /* Two basic prompt providers: username/password, and just username. */
414 svn_auth_get_simple_prompt_provider(&provider
,
415 svn_cmdline_auth_simple_prompt
,
419 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
421 svn_auth_get_username_prompt_provider
422 (&provider
, svn_cmdline_auth_username_prompt
, pb
,
423 2, /* retry limit */ pool
);
424 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
426 /* Three ssl prompt providers, for server-certs, client-certs,
427 and client-cert-passphrases. */
428 svn_auth_get_ssl_server_trust_prompt_provider
429 (&provider
, svn_cmdline_auth_ssl_server_trust_prompt
, pb
, pool
);
430 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
432 svn_auth_get_ssl_client_cert_prompt_provider
433 (&provider
, svn_cmdline_auth_ssl_client_cert_prompt
, pb
, 2, pool
);
434 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
436 svn_auth_get_ssl_client_cert_pw_prompt_provider
437 (&provider
, svn_cmdline_auth_ssl_client_cert_pw_prompt
, pb
, 2, pool
);
438 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
441 /* Build an authentication baton to give to libsvn_client. */
442 svn_auth_open(ab
, providers
, pool
);
444 /* Place any default --username or --password credentials into the
445 auth_baton's run-time parameter hash. */
447 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DEFAULT_USERNAME
,
450 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DEFAULT_PASSWORD
,
453 /* Same with the --non-interactive option. */
455 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_NON_INTERACTIVE
, "");
458 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_CONFIG_DIR
,
461 SVN_ERR(svn_config_get_bool(cfg
, &store_password_val
,
462 SVN_CONFIG_SECTION_AUTH
,
463 SVN_CONFIG_OPTION_STORE_PASSWORDS
,
466 if (! store_password_val
)
467 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS
, "");
469 /* There are two different ways the user can disable disk caching
470 of credentials: either via --no-auth-cache, or in the config
471 file ('store-auth-creds = no'). */
472 SVN_ERR(svn_config_get_bool(cfg
, &store_password_val
,
473 SVN_CONFIG_SECTION_AUTH
,
474 SVN_CONFIG_OPTION_STORE_AUTH_CREDS
,
477 if (no_auth_cache
|| ! store_password_val
)
478 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_NO_AUTH_CACHE
, "");
484 svn_cmdline__getopt_init(apr_getopt_t
**os
,
489 apr_status_t apr_err
;
491 /* Convert command line args from EBCDIC to UTF-8. */
493 for (i
= 0; i
< argc
; ++i
)
496 SVN_ERR(svn_utf_cstring_to_utf8_ex2(&arg_utf8
, argv
[i
],
497 (const char *)0, pool
));
501 apr_err
= apr_getopt_init(os
, pool
, argc
, argv
);
503 return svn_error_wrap_apr(apr_err
,
504 _("Error initializing command line arguments"));