In the command-line client, forbid
[svn.git] / subversion / libsvn_subr / cmdline.c
blobee65b91ce68048076da96155a7f00119c5827f8d
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 fprintf(error_stream, "%s: error: cannot open '/dev/null'\n",
86 progname);
87 return EXIT_FAILURE;
90 #endif
92 /* Ignore any errors encountered while attempting to change stream
93 buffering, as the streams should retain their default buffering
94 modes. */
95 setvbuf(error_stream, NULL, _IONBF, 0);
96 #ifndef WIN32
97 setvbuf(stdout, NULL, _IOLBF, 0);
98 #endif
100 #ifdef WIN32
101 #if _MSC_VER < 1400
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);
120 #endif
122 #endif /* WIN32 */
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
126 environment. */
127 if (!setlocale(LC_ALL, "")
128 && !setlocale(LC_CTYPE, ""))
130 if (error_stream)
132 const char *env_vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
133 const char **env_var = &env_vars[0], *env_val = NULL;
134 while (*env_var)
136 env_val = getenv(*env_var);
137 if (env_val && env_val[0])
138 break;
139 ++env_var;
142 if (!*env_var)
144 /* Unlikely. Can setlocale fail if no env vars are set? */
145 --env_var;
146 env_val = "not 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();
160 if (status)
162 if (error_stream)
164 char buf[1024];
165 apr_strerror(status, buf, sizeof(buf) - 1);
166 fprintf(error_stream,
167 "%s: error: cannot initialize APR: %s\n",
168 progname, buf);
170 return EXIT_FAILURE;
173 /* This has to happen before any pools are created. */
174 svn_dso_initialize();
176 if (0 > atexit(apr_terminate))
178 if (error_stream)
179 fprintf(error_stream,
180 "%s: error: atexit registration failed\n",
181 progname);
182 return EXIT_FAILURE;
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();
192 if (err)
194 if (error_stream && err->message)
195 fprintf(error_stream, "%s", err->message);
197 svn_error_clear(err);
198 return EXIT_FAILURE;
202 return EXIT_SUCCESS;
206 svn_error_t *
207 svn_cmdline_cstring_from_utf8(const char **dest,
208 const char *src,
209 apr_pool_t *pool)
211 if (output_encoding == NULL)
212 return svn_utf_cstring_from_utf8(dest, src, pool);
213 else
214 return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool);
218 const char *
219 svn_cmdline_cstring_from_utf8_fuzzy(const char *src,
220 apr_pool_t *pool)
222 return svn_utf__cstring_from_utf8_fuzzy(src, pool,
223 svn_cmdline_cstring_from_utf8);
227 svn_error_t *
228 svn_cmdline_cstring_to_utf8(const char **dest,
229 const char *src,
230 apr_pool_t *pool)
232 if (input_encoding == NULL)
233 return svn_utf_cstring_to_utf8(dest, src, pool);
234 else
235 return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool);
239 svn_error_t *
240 svn_cmdline_path_local_style_from_utf8(const char **dest,
241 const char *src,
242 apr_pool_t *pool)
244 return svn_cmdline_cstring_from_utf8(dest,
245 svn_path_local_style(src, pool),
246 pool);
249 svn_error_t *
250 svn_cmdline_printf(apr_pool_t *pool, const char *fmt, ...)
252 const char *message;
253 va_list ap;
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.
263 va_start(ap, fmt);
264 message = apr_pvsprintf(pool, fmt, ap);
265 va_end(ap);
267 return svn_cmdline_fputs(message, stdout, pool);
270 svn_error_t *
271 svn_cmdline_fprintf(FILE *stream, apr_pool_t *pool, const char *fmt, ...)
273 const char *message;
274 va_list ap;
276 /* See svn_cmdline_printf () for a note about character encoding issues. */
278 va_start(ap, fmt);
279 message = apr_pvsprintf(pool, fmt, ap);
280 va_end(ap);
282 return svn_cmdline_fputs(message, stream, pool);
285 svn_error_t *
286 svn_cmdline_fputs(const char *string, FILE* stream, apr_pool_t *pool)
288 svn_error_t *err;
289 const char *out;
291 err = svn_cmdline_cstring_from_utf8(&out, string, pool);
293 if (err)
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
302 a generic error. */
303 errno = 0;
305 if (fputs(out, stream) == EOF)
307 if (errno)
308 return svn_error_wrap_apr(errno, _("Write error"));
309 else
310 return svn_error_create
311 (SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
314 return SVN_NO_ERROR;
317 svn_error_t *
318 svn_cmdline_fflush(FILE *stream)
320 /* See comment in svn_cmdline_fputs about use of errno and stdio. */
321 errno = 0;
322 if (fflush(stream) == EOF)
324 if (errno)
325 return svn_error_wrap_apr(errno, _("Write error"));
326 else
327 return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
330 return SVN_NO_ERROR;
333 const char *svn_cmdline_output_encoding(apr_pool_t *pool)
335 if (output_encoding)
336 return apr_pstrdup(pool, output_encoding);
337 else
338 return SVN_APR_LOCALE_CHARSET;
342 svn_cmdline_handle_exit_error(svn_error_t *err,
343 apr_pool_t *pool,
344 const char *prefix)
346 svn_handle_error2(err, stderr, FALSE, prefix);
347 svn_error_clear(err);
348 if (pool)
349 svn_pool_destroy(pool);
350 return EXIT_FAILURE;
353 svn_error_t *
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,
360 svn_config_t *cfg,
361 svn_cancel_func_t cancel_func,
362 void *cancel_baton,
363 apr_pool_t *pool)
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;
377 #endif
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;
381 #endif
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;
391 #endif
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;
403 if (cancel_func)
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,
415 2, /* retry limit */
416 pool);
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. */
444 if (auth_username)
445 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_USERNAME,
446 auth_username);
447 if (auth_password)
448 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD,
449 auth_password);
451 /* Same with the --non-interactive option. */
452 if (non_interactive)
453 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NON_INTERACTIVE, "");
455 if (config_dir)
456 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_CONFIG_DIR,
457 config_dir);
459 SVN_ERR(svn_config_get_bool(cfg, &store_password_val,
460 SVN_CONFIG_SECTION_AUTH,
461 SVN_CONFIG_OPTION_STORE_PASSWORDS,
462 TRUE));
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,
473 TRUE));
475 if (no_auth_cache || ! store_password_val)
476 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
478 return SVN_NO_ERROR;
481 svn_error_t *
482 svn_cmdline__getopt_init(apr_getopt_t **os,
483 int argc,
484 const char *argv[],
485 apr_pool_t *pool)
487 apr_status_t apr_err;
488 #ifdef AS400_UTF8
489 /* Convert command line args from EBCDIC to UTF-8. */
490 int i;
491 for (i = 0; i < argc; ++i)
493 char *arg_utf8;
494 SVN_ERR(svn_utf_cstring_to_utf8_ex2(&arg_utf8, argv[i],
495 (const char *)0, pool));
496 argv[i] = arg_utf8;
498 #endif
499 apr_err = apr_getopt_init(os, pool, argc, argv);
500 if (apr_err)
501 return svn_error_wrap_apr(apr_err,
502 _("Error initializing command line arguments"));
503 return SVN_NO_ERROR;