Change the format of the revprops block sent in svnserve for
[svn.git] / subversion / libsvn_subr / cmdline.c
blobee829f0351319da844d5492aa794c111bbb745c6
1 /*
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() */
24 #ifndef WIN32
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #endif
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"
38 #include "svn_dso.h"
39 #include "svn_path.h"
40 #include "svn_pools.h"
41 #include "svn_error.h"
42 #include "svn_nls.h"
43 #include "svn_auth.h"
44 #include "utf_impl.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;
57 int
58 svn_cmdline_init(const char *progname, FILE *error_stream)
60 apr_status_t status;
61 apr_pool_t *pool;
63 #ifndef WIN32
65 struct stat st;
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
71 corrupt it. */
72 #ifdef AS400_UTF8
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
75 * open(). */
76 #pragma convert(0)
77 #endif
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))
81 #ifdef AS400_UTF8
82 #pragma convert(1208)
83 #endif
85 if (error_stream)
86 fprintf(error_stream, "%s: error: cannot open '/dev/null'\n",
87 progname);
88 return EXIT_FAILURE;
91 #endif
93 /* Ignore any errors encountered while attempting to change stream
94 buffering, as the streams should retain their default buffering
95 modes. */
96 if (error_stream)
97 setvbuf(error_stream, NULL, _IONBF, 0);
98 #ifndef WIN32
99 setvbuf(stdout, NULL, _IOLBF, 0);
100 #endif
102 #ifdef WIN32
103 #if _MSC_VER < 1400
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);
122 #endif
124 #endif /* WIN32 */
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
128 environment. */
129 if (!setlocale(LC_ALL, "")
130 && !setlocale(LC_CTYPE, ""))
132 if (error_stream)
134 const char *env_vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
135 const char **env_var = &env_vars[0], *env_val = NULL;
136 while (*env_var)
138 env_val = getenv(*env_var);
139 if (env_val && env_val[0])
140 break;
141 ++env_var;
144 if (!*env_var)
146 /* Unlikely. Can setlocale fail if no env vars are set? */
147 --env_var;
148 env_val = "not 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();
162 if (status)
164 if (error_stream)
166 char buf[1024];
167 apr_strerror(status, buf, sizeof(buf) - 1);
168 fprintf(error_stream,
169 "%s: error: cannot initialize APR: %s\n",
170 progname, buf);
172 return EXIT_FAILURE;
175 /* This has to happen before any pools are created. */
176 svn_dso_initialize();
178 if (0 > atexit(apr_terminate))
180 if (error_stream)
181 fprintf(error_stream,
182 "%s: error: atexit registration failed\n",
183 progname);
184 return EXIT_FAILURE;
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();
194 if (err)
196 if (error_stream && err->message)
197 fprintf(error_stream, "%s", err->message);
199 svn_error_clear(err);
200 return EXIT_FAILURE;
204 return EXIT_SUCCESS;
208 svn_error_t *
209 svn_cmdline_cstring_from_utf8(const char **dest,
210 const char *src,
211 apr_pool_t *pool)
213 if (output_encoding == NULL)
214 return svn_utf_cstring_from_utf8(dest, src, pool);
215 else
216 return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool);
220 const char *
221 svn_cmdline_cstring_from_utf8_fuzzy(const char *src,
222 apr_pool_t *pool)
224 return svn_utf__cstring_from_utf8_fuzzy(src, pool,
225 svn_cmdline_cstring_from_utf8);
229 svn_error_t *
230 svn_cmdline_cstring_to_utf8(const char **dest,
231 const char *src,
232 apr_pool_t *pool)
234 if (input_encoding == NULL)
235 return svn_utf_cstring_to_utf8(dest, src, pool);
236 else
237 return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool);
241 svn_error_t *
242 svn_cmdline_path_local_style_from_utf8(const char **dest,
243 const char *src,
244 apr_pool_t *pool)
246 return svn_cmdline_cstring_from_utf8(dest,
247 svn_path_local_style(src, pool),
248 pool);
251 svn_error_t *
252 svn_cmdline_printf(apr_pool_t *pool, const char *fmt, ...)
254 const char *message;
255 va_list ap;
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.
265 va_start(ap, fmt);
266 message = apr_pvsprintf(pool, fmt, ap);
267 va_end(ap);
269 return svn_cmdline_fputs(message, stdout, pool);
272 svn_error_t *
273 svn_cmdline_fprintf(FILE *stream, apr_pool_t *pool, const char *fmt, ...)
275 const char *message;
276 va_list ap;
278 /* See svn_cmdline_printf () for a note about character encoding issues. */
280 va_start(ap, fmt);
281 message = apr_pvsprintf(pool, fmt, ap);
282 va_end(ap);
284 return svn_cmdline_fputs(message, stream, pool);
287 svn_error_t *
288 svn_cmdline_fputs(const char *string, FILE* stream, apr_pool_t *pool)
290 svn_error_t *err;
291 const char *out;
293 err = svn_cmdline_cstring_from_utf8(&out, string, pool);
295 if (err)
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
304 a generic error. */
305 errno = 0;
307 if (fputs(out, stream) == EOF)
309 if (errno)
310 return svn_error_wrap_apr(errno, _("Write error"));
311 else
312 return svn_error_create
313 (SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
316 return SVN_NO_ERROR;
319 svn_error_t *
320 svn_cmdline_fflush(FILE *stream)
322 /* See comment in svn_cmdline_fputs about use of errno and stdio. */
323 errno = 0;
324 if (fflush(stream) == EOF)
326 if (errno)
327 return svn_error_wrap_apr(errno, _("Write error"));
328 else
329 return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
332 return SVN_NO_ERROR;
335 const char *svn_cmdline_output_encoding(apr_pool_t *pool)
337 if (output_encoding)
338 return apr_pstrdup(pool, output_encoding);
339 else
340 return SVN_APR_LOCALE_CHARSET;
344 svn_cmdline_handle_exit_error(svn_error_t *err,
345 apr_pool_t *pool,
346 const char *prefix)
348 svn_handle_error2(err, stderr, FALSE, prefix);
349 svn_error_clear(err);
350 if (pool)
351 svn_pool_destroy(pool);
352 return EXIT_FAILURE;
355 svn_error_t *
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,
362 svn_config_t *cfg,
363 svn_cancel_func_t cancel_func,
364 void *cancel_baton,
365 apr_pool_t *pool)
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;
379 #endif
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;
383 #endif
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;
393 #endif
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;
405 if (cancel_func)
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,
417 2, /* retry limit */
418 pool);
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. */
446 if (auth_username)
447 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_USERNAME,
448 auth_username);
449 if (auth_password)
450 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD,
451 auth_password);
453 /* Same with the --non-interactive option. */
454 if (non_interactive)
455 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NON_INTERACTIVE, "");
457 if (config_dir)
458 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_CONFIG_DIR,
459 config_dir);
461 SVN_ERR(svn_config_get_bool(cfg, &store_password_val,
462 SVN_CONFIG_SECTION_AUTH,
463 SVN_CONFIG_OPTION_STORE_PASSWORDS,
464 TRUE));
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,
475 TRUE));
477 if (no_auth_cache || ! store_password_val)
478 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
480 return SVN_NO_ERROR;
483 svn_error_t *
484 svn_cmdline__getopt_init(apr_getopt_t **os,
485 int argc,
486 const char *argv[],
487 apr_pool_t *pool)
489 apr_status_t apr_err;
490 #ifdef AS400_UTF8
491 /* Convert command line args from EBCDIC to UTF-8. */
492 int i;
493 for (i = 0; i < argc; ++i)
495 char *arg_utf8;
496 SVN_ERR(svn_utf_cstring_to_utf8_ex2(&arg_utf8, argv[i],
497 (const char *)0, pool));
498 argv[i] = arg_utf8;
500 #endif
501 apr_err = apr_getopt_init(os, pool, argc, argv);
502 if (apr_err)
503 return svn_error_wrap_apr(apr_err,
504 _("Error initializing command line arguments"));
505 return SVN_NO_ERROR;