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))
85 fprintf(error_stream
, "%s: error: cannot open '/dev/null'\n",
92 /* Ignore any errors encountered while attempting to change stream
93 buffering, as the streams should retain their default buffering
95 setvbuf(error_stream
, NULL
, _IONBF
, 0);
97 setvbuf(stdout
, NULL
, _IOLBF
, 0);
102 /* Initialize the input and output encodings. */
104 static char input_encoding_buffer
[16];
105 static char output_encoding_buffer
[16];
107 apr_snprintf(input_encoding_buffer
, sizeof input_encoding_buffer
,
108 "CP%u", (unsigned) GetConsoleCP());
109 input_encoding
= input_encoding_buffer
;
111 apr_snprintf(output_encoding_buffer
, sizeof output_encoding_buffer
,
112 "CP%u", (unsigned) GetConsoleOutputCP());
113 output_encoding
= output_encoding_buffer
;
115 #endif /* _MSC_VER < 1400 */
117 #ifdef SVN_USE_WIN32_CRASHHANDLER
118 /* Attach (but don't load) the crash handler */
119 SetUnhandledExceptionFilter(svn__unhandled_exception_filter
);
124 /* C programs default to the "C" locale. But because svn is supposed
125 to be i18n-aware, it should inherit the default locale of its
127 if (!setlocale(LC_ALL
, "")
128 && !setlocale(LC_CTYPE
, ""))
132 const char *env_vars
[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL
};
133 const char **env_var
= &env_vars
[0], *env_val
= NULL
;
136 env_val
= getenv(*env_var
);
137 if (env_val
&& env_val
[0])
144 /* Unlikely. Can setlocale fail if no env vars are set? */
149 fprintf(error_stream
,
150 "%s: warning: cannot set LC_CTYPE locale\n"
151 "%s: warning: environment variable %s is %s\n"
152 "%s: warning: please check that your locale name is correct\n",
153 progname
, progname
, *env_var
, env_val
, progname
);
157 /* Initialize the APR subsystem, and register an atexit() function
158 to Uninitialize that subsystem at program exit. */
159 status
= apr_initialize();
165 apr_strerror(status
, buf
, sizeof(buf
) - 1);
166 fprintf(error_stream
,
167 "%s: error: cannot initialize APR: %s\n",
173 /* This has to happen before any pools are created. */
174 svn_dso_initialize();
176 if (0 > atexit(apr_terminate
))
179 fprintf(error_stream
,
180 "%s: error: atexit registration failed\n",
185 /* Create a pool for use by the UTF-8 routines. It will be cleaned
186 up by APR at exit time. */
187 pool
= svn_pool_create(NULL
);
188 svn_utf_initialize(pool
);
191 svn_error_t
*err
= svn_nls_init();
194 if (error_stream
&& err
->message
)
195 fprintf(error_stream
, "%s", err
->message
);
197 svn_error_clear(err
);
207 svn_cmdline_cstring_from_utf8(const char **dest
,
211 if (output_encoding
== NULL
)
212 return svn_utf_cstring_from_utf8(dest
, src
, pool
);
214 return svn_utf_cstring_from_utf8_ex2(dest
, src
, output_encoding
, pool
);
219 svn_cmdline_cstring_from_utf8_fuzzy(const char *src
,
222 return svn_utf__cstring_from_utf8_fuzzy(src
, pool
,
223 svn_cmdline_cstring_from_utf8
);
228 svn_cmdline_cstring_to_utf8(const char **dest
,
232 if (input_encoding
== NULL
)
233 return svn_utf_cstring_to_utf8(dest
, src
, pool
);
235 return svn_utf_cstring_to_utf8_ex2(dest
, src
, input_encoding
, pool
);
240 svn_cmdline_path_local_style_from_utf8(const char **dest
,
244 return svn_cmdline_cstring_from_utf8(dest
,
245 svn_path_local_style(src
, pool
),
250 svn_cmdline_printf(apr_pool_t
*pool
, const char *fmt
, ...)
255 /* A note about encoding issues:
256 * APR uses the execution character set, but here we give it UTF-8 strings,
257 * both the fmt argument and any other string arguments. Since apr_pvsprintf
258 * only cares about and produces ASCII characters, this works under the
259 * assumption that all supported platforms use an execution character set
260 * with ASCII as a subset.
264 message
= apr_pvsprintf(pool
, fmt
, ap
);
267 return svn_cmdline_fputs(message
, stdout
, pool
);
271 svn_cmdline_fprintf(FILE *stream
, apr_pool_t
*pool
, const char *fmt
, ...)
276 /* See svn_cmdline_printf () for a note about character encoding issues. */
279 message
= apr_pvsprintf(pool
, fmt
, ap
);
282 return svn_cmdline_fputs(message
, stream
, pool
);
286 svn_cmdline_fputs(const char *string
, FILE* stream
, apr_pool_t
*pool
)
291 err
= svn_cmdline_cstring_from_utf8(&out
, string
, pool
);
295 svn_error_clear(err
);
296 out
= svn_cmdline_cstring_from_utf8_fuzzy(string
, pool
);
299 /* On POSIX systems, errno will be set on an error in fputs, but this might
300 not be the case on other platforms. We reset errno and only
301 use it if it was set by the below fputs call. Else, we just return
305 if (fputs(out
, stream
) == EOF
)
308 return svn_error_wrap_apr(errno
, _("Write error"));
310 return svn_error_create
311 (SVN_ERR_IO_WRITE_ERROR
, NULL
, NULL
);
318 svn_cmdline_fflush(FILE *stream
)
320 /* See comment in svn_cmdline_fputs about use of errno and stdio. */
322 if (fflush(stream
) == EOF
)
325 return svn_error_wrap_apr(errno
, _("Write error"));
327 return svn_error_create(SVN_ERR_IO_WRITE_ERROR
, NULL
, NULL
);
333 const char *svn_cmdline_output_encoding(apr_pool_t
*pool
)
336 return apr_pstrdup(pool
, output_encoding
);
338 return SVN_APR_LOCALE_CHARSET
;
342 svn_cmdline_handle_exit_error(svn_error_t
*err
,
346 svn_handle_error2(err
, stderr
, FALSE
, prefix
);
347 svn_error_clear(err
);
349 svn_pool_destroy(pool
);
354 svn_cmdline_setup_auth_baton(svn_auth_baton_t
**ab
,
355 svn_boolean_t non_interactive
,
356 const char *auth_username
,
357 const char *auth_password
,
358 const char *config_dir
,
359 svn_boolean_t no_auth_cache
,
361 svn_cancel_func_t cancel_func
,
365 svn_boolean_t store_password_val
= TRUE
;
366 svn_auth_provider_object_t
*provider
;
368 /* The whole list of registered providers */
369 apr_array_header_t
*providers
370 = apr_array_make(pool
, 12, sizeof(svn_auth_provider_object_t
*));
372 /* The main disk-caching auth providers, for both
373 'username/password' creds and 'username' creds. */
374 #if defined(WIN32) && !defined(__MINGW32__)
375 svn_auth_get_windows_simple_provider(&provider
, pool
);
376 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
378 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
379 svn_auth_get_keychain_simple_provider(&provider
, pool
);
380 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
382 svn_auth_get_simple_provider(&provider
, pool
);
383 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
384 svn_auth_get_username_provider(&provider
, pool
);
385 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
387 /* The server-cert, client-cert, and client-cert-password providers. */
388 #if defined(WIN32) && !defined(__MINGW32__)
389 svn_auth_get_windows_ssl_server_trust_provider(&provider
, pool
);
390 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
392 svn_auth_get_ssl_server_trust_file_provider(&provider
, pool
);
393 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
394 svn_auth_get_ssl_client_cert_file_provider(&provider
, pool
);
395 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
396 svn_auth_get_ssl_client_cert_pw_file_provider(&provider
, pool
);
397 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
399 if (non_interactive
== FALSE
)
401 svn_cmdline_prompt_baton_t
*pb
= NULL
;
405 pb
= apr_palloc(pool
, sizeof(*pb
));
407 pb
->cancel_func
= cancel_func
;
408 pb
->cancel_baton
= cancel_baton
;
411 /* Two basic prompt providers: username/password, and just username. */
412 svn_auth_get_simple_prompt_provider(&provider
,
413 svn_cmdline_auth_simple_prompt
,
417 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
419 svn_auth_get_username_prompt_provider
420 (&provider
, svn_cmdline_auth_username_prompt
, pb
,
421 2, /* retry limit */ pool
);
422 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
424 /* Three ssl prompt providers, for server-certs, client-certs,
425 and client-cert-passphrases. */
426 svn_auth_get_ssl_server_trust_prompt_provider
427 (&provider
, svn_cmdline_auth_ssl_server_trust_prompt
, pb
, pool
);
428 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
430 svn_auth_get_ssl_client_cert_prompt_provider
431 (&provider
, svn_cmdline_auth_ssl_client_cert_prompt
, pb
, 2, pool
);
432 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
434 svn_auth_get_ssl_client_cert_pw_prompt_provider
435 (&provider
, svn_cmdline_auth_ssl_client_cert_pw_prompt
, pb
, 2, pool
);
436 APR_ARRAY_PUSH(providers
, svn_auth_provider_object_t
*) = provider
;
439 /* Build an authentication baton to give to libsvn_client. */
440 svn_auth_open(ab
, providers
, pool
);
442 /* Place any default --username or --password credentials into the
443 auth_baton's run-time parameter hash. */
445 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DEFAULT_USERNAME
,
448 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DEFAULT_PASSWORD
,
451 /* Same with the --non-interactive option. */
453 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_NON_INTERACTIVE
, "");
456 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_CONFIG_DIR
,
459 SVN_ERR(svn_config_get_bool(cfg
, &store_password_val
,
460 SVN_CONFIG_SECTION_AUTH
,
461 SVN_CONFIG_OPTION_STORE_PASSWORDS
,
464 if (! store_password_val
)
465 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS
, "");
467 /* There are two different ways the user can disable disk caching
468 of credentials: either via --no-auth-cache, or in the config
469 file ('store-auth-creds = no'). */
470 SVN_ERR(svn_config_get_bool(cfg
, &store_password_val
,
471 SVN_CONFIG_SECTION_AUTH
,
472 SVN_CONFIG_OPTION_STORE_AUTH_CREDS
,
475 if (no_auth_cache
|| ! store_password_val
)
476 svn_auth_set_parameter(*ab
, SVN_AUTH_PARAM_NO_AUTH_CACHE
, "");
482 svn_cmdline__getopt_init(apr_getopt_t
**os
,
487 apr_status_t apr_err
;
489 /* Convert command line args from EBCDIC to UTF-8. */
491 for (i
= 0; i
< argc
; ++i
)
494 SVN_ERR(svn_utf_cstring_to_utf8_ex2(&arg_utf8
, argv
[i
],
495 (const char *)0, pool
));
499 apr_err
= apr_getopt_init(os
, pool
, argc
, argv
);
501 return svn_error_wrap_apr(apr_err
,
502 _("Error initializing command line arguments"));