2 * cmdline.c : Helpers for command-line programs.
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
25 #include <stdlib.h> /* for atexit() */
26 #include <stdio.h> /* for setvbuf() */
27 #include <locale.h> /* for setlocale() */
30 #include <sys/types.h>
40 #include <apr.h> /* for STDIN_FILENO */
41 #include <apr_errno.h> /* for apr_strerror */
42 #include <apr_general.h> /* for apr_initialize/apr_terminate */
43 #include <apr_strings.h> /* for apr_snprintf */
44 #include <apr_pools.h>
45 #include <apr_signal.h>
47 #include "svn_cmdline.h"
48 #include "svn_ctype.h"
50 #include "svn_dirent_uri.h"
53 #include "svn_pools.h"
54 #include "svn_error.h"
59 #include "svn_base64.h"
60 #include "svn_config.h"
61 #include "svn_sorts.h"
62 #include "svn_props.h"
63 #include "svn_subst.h"
65 #include "private/svn_cmdline_private.h"
66 #include "private/svn_utf_private.h"
67 #include "private/svn_sorts_private.h"
68 #include "private/svn_string_private.h"
70 #include "svn_private_config.h"
72 #include "win32_crashrpt.h"
74 #if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1400)
75 /* Before Visual Studio 2005, the C runtime didn't handle encodings for the
76 for the stdio output handling. */
77 #define CMDLINE_USE_CUSTOM_ENCODING
79 /* The stdin encoding. If null, it's the same as the native encoding. */
80 static const char *input_encoding = NULL;
82 /* The stdout encoding. If null, it's the same as the native encoding. */
83 static const char *output_encoding = NULL;
84 #elif defined(WIN32) && defined(_MSC_VER)
85 /* For now limit this code to Visual C++, as the result is highly dependent
86 on the CRT implementation */
87 #define USE_WIN32_CONSOLE_SHORTCUT
89 /* When TRUE, stdout/stderr is directly connected to a console */
90 static svn_boolean_t shortcut_stdout_to_console = FALSE;
91 static svn_boolean_t shortcut_stderr_to_console = FALSE;
96 svn_cmdline_init(const char *progname, FILE *error_stream)
101 char prefix_buf[64]; /* 64 is probably bigger than most program names */
107 /* The following makes sure that file descriptors 0 (stdin), 1
108 (stdout) and 2 (stderr) will not be "reused", because if
109 e.g. file descriptor 2 would be reused when opening a file, a
110 write to stderr would write to that file and most likely
112 if ((fstat(0, &st) == -1 && open("/dev/null", O_RDONLY) == -1) ||
113 (fstat(1, &st) == -1 && open("/dev/null", O_WRONLY) == -1) ||
114 (fstat(2, &st) == -1 && open("/dev/null", O_WRONLY) == -1))
117 fprintf(error_stream, "%s: error: cannot open '/dev/null'\n",
124 /* Ignore any errors encountered while attempting to change stream
125 buffering, as the streams should retain their default buffering
128 setvbuf(error_stream, NULL, _IONBF, 0);
130 setvbuf(stdout, NULL, _IOLBF, 0);
134 #ifdef CMDLINE_USE_CUSTOM_ENCODING
135 /* Initialize the input and output encodings. */
137 static char input_encoding_buffer[16];
138 static char output_encoding_buffer[16];
140 apr_snprintf(input_encoding_buffer, sizeof input_encoding_buffer,
141 "CP%u", (unsigned) GetConsoleCP());
142 input_encoding = input_encoding_buffer;
144 apr_snprintf(output_encoding_buffer, sizeof output_encoding_buffer,
145 "CP%u", (unsigned) GetConsoleOutputCP());
146 output_encoding = output_encoding_buffer;
148 #endif /* CMDLINE_USE_CUSTOM_ENCODING */
150 #ifdef SVN_USE_WIN32_CRASHHANDLER
151 if (!getenv("SVN_CMDLINE_DISABLE_CRASH_HANDLER"))
153 /* Attach (but don't load) the crash handler */
154 SetUnhandledExceptionFilter(svn__unhandled_exception_filter);
157 /* ### This should work for VC++ 2002 (=1300) and later */
158 /* Show the abort message on STDERR instead of a dialog to allow
159 scripts (e.g. our testsuite) to continue after an abort without
160 user intervention. Allow overriding for easier debugging. */
161 if (!getenv("SVN_CMDLINE_USE_DIALOG_FOR_ABORT"))
163 /* In release mode: Redirect abort() errors to stderr */
164 _set_error_mode(_OUT_TO_STDERR);
166 /* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
167 (Ignored in release builds) */
168 _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
169 _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
170 _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
171 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
172 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
173 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
175 #endif /* _MSC_VER >= 1400 */
177 #endif /* SVN_USE_WIN32_CRASHHANDLER */
181 /* C programs default to the "C" locale. But because svn is supposed
182 to be i18n-aware, it should inherit the default locale of its
184 if (!setlocale(LC_ALL, "")
185 && !setlocale(LC_CTYPE, ""))
189 const char *env_vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
190 const char **env_var = &env_vars[0], *env_val = NULL;
193 env_val = getenv(*env_var);
194 if (env_val && env_val[0])
201 /* Unlikely. Can setlocale fail if no env vars are set? */
206 fprintf(error_stream,
207 "%s: warning: cannot set LC_CTYPE locale\n"
208 "%s: warning: environment variable %s is %s\n"
209 "%s: warning: please check that your locale name is correct\n",
210 progname, progname, *env_var, env_val, progname);
214 /* Initialize the APR subsystem, and register an atexit() function
215 to Uninitialize that subsystem at program exit. */
216 status = apr_initialize();
222 apr_strerror(status, buf, sizeof(buf) - 1);
223 fprintf(error_stream,
224 "%s: error: cannot initialize APR: %s\n",
230 strncpy(prefix_buf, progname, sizeof(prefix_buf) - 3);
231 prefix_buf[sizeof(prefix_buf) - 3] = '\0';
232 strcat(prefix_buf, ": ");
234 /* DSO pool must be created before any other pools used by the
235 application so that pool cleanup doesn't unload DSOs too
236 early. See docstring of svn_dso_initialize2(). */
237 if ((err = svn_dso_initialize2()))
240 svn_handle_error2(err, error_stream, TRUE, prefix_buf);
242 svn_error_clear(err);
246 if (0 > atexit(apr_terminate))
249 fprintf(error_stream,
250 "%s: error: atexit registration failed\n",
255 /* Create a pool for use by the UTF-8 routines. It will be cleaned
256 up by APR at exit time. */
257 pool = svn_pool_create(NULL);
258 svn_utf_initialize2(FALSE, pool);
260 if ((err = svn_nls_init()))
263 svn_handle_error2(err, error_stream, TRUE, prefix_buf);
265 svn_error_clear(err);
269 #ifdef USE_WIN32_CONSOLE_SHORTCUT
270 if (_isatty(STDOUT_FILENO))
273 HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
275 /* stdout is a char device handle, but is it the console? */
276 if (GetConsoleMode(stdout_handle, &ignored))
277 shortcut_stdout_to_console = TRUE;
279 /* Don't close stdout_handle */
281 if (_isatty(STDERR_FILENO))
284 HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
286 /* stderr is a char device handle, but is it the console? */
287 if (GetConsoleMode(stderr_handle, &ignored))
288 shortcut_stderr_to_console = TRUE;
290 /* Don't close stderr_handle */
299 svn_cmdline_cstring_from_utf8(const char **dest,
303 #ifdef CMDLINE_USE_CUSTOM_ENCODING
304 if (output_encoding != NULL)
305 return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool);
308 return svn_utf_cstring_from_utf8(dest, src, pool);
313 svn_cmdline_cstring_from_utf8_fuzzy(const char *src,
316 return svn_utf__cstring_from_utf8_fuzzy(src, pool,
317 svn_cmdline_cstring_from_utf8);
322 svn_cmdline_cstring_to_utf8(const char **dest,
326 #ifdef CMDLINE_USE_CUSTOM_ENCODING
327 if (input_encoding != NULL)
328 return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool);
331 return svn_utf_cstring_to_utf8(dest, src, pool);
336 svn_cmdline_path_local_style_from_utf8(const char **dest,
340 return svn_cmdline_cstring_from_utf8(dest,
341 svn_dirent_local_style(src, pool),
346 svn_cmdline__stdin_readline(const char **result,
347 apr_pool_t *result_pool,
348 apr_pool_t *scratch_pool)
350 svn_stringbuf_t *buf = NULL;
351 svn_stream_t *stdin_stream = NULL;
352 svn_boolean_t oob = FALSE;
354 SVN_ERR(svn_stream_for_stdin2(&stdin_stream, TRUE, scratch_pool));
355 SVN_ERR(svn_stream_readline(stdin_stream, &buf, APR_EOL_STR, &oob, result_pool));
363 svn_cmdline_printf(apr_pool_t *pool, const char *fmt, ...)
368 /* A note about encoding issues:
369 * APR uses the execution character set, but here we give it UTF-8 strings,
370 * both the fmt argument and any other string arguments. Since apr_pvsprintf
371 * only cares about and produces ASCII characters, this works under the
372 * assumption that all supported platforms use an execution character set
373 * with ASCII as a subset.
377 message = apr_pvsprintf(pool, fmt, ap);
380 return svn_cmdline_fputs(message, stdout, pool);
384 svn_cmdline_fprintf(FILE *stream, apr_pool_t *pool, const char *fmt, ...)
389 /* See svn_cmdline_printf () for a note about character encoding issues. */
392 message = apr_pvsprintf(pool, fmt, ap);
395 return svn_cmdline_fputs(message, stream, pool);
399 svn_cmdline_fputs(const char *string, FILE* stream, apr_pool_t *pool)
404 #ifdef USE_WIN32_CONSOLE_SHORTCUT
405 /* For legacy reasons the Visual C++ runtime converts output to the console
406 from the native 'ansi' encoding, to unicode, then back to 'ansi' and then
407 onwards to the console which is implemented as unicode.
409 For operations like 'svn status -v' this may cause about 70% of the total
410 processing time, with absolutely no gain.
412 For this specific scenario this shortcut exists. It has the nice side
413 effect of allowing full unicode output to the console.
415 Note that this shortcut is not used when the output is redirected, as in
416 that case the data is put on the pipe/file after the first conversion to
417 ansi. In this case the most expensive conversion is already avoided.
419 if ((stream == stdout && shortcut_stdout_to_console)
420 || (stream == stderr && shortcut_stderr_to_console))
424 if (string[0] == '\0')
427 SVN_ERR(svn_cmdline_fflush(stream)); /* Flush existing output */
429 SVN_ERR(svn_utf__win32_utf8_to_utf16(&result, string, NULL, pool));
433 if (apr_get_os_error())
435 return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
443 err = svn_cmdline_cstring_from_utf8(&out, string, pool);
447 svn_error_clear(err);
448 out = svn_cmdline_cstring_from_utf8_fuzzy(string, pool);
451 /* On POSIX systems, errno will be set on an error in fputs, but this might
452 not be the case on other platforms. We reset errno and only
453 use it if it was set by the below fputs call. Else, we just return
457 if (fputs(out, stream) == EOF)
459 if (apr_get_os_error()) /* is errno on POSIX */
461 /* ### Issue #3014: Return a specific error for broken pipes,
462 * ### with a single element in the error chain. */
463 if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
464 return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
466 return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
469 return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
476 svn_cmdline_fflush(FILE *stream)
478 /* See comment in svn_cmdline_fputs about use of errno and stdio. */
480 if (fflush(stream) == EOF)
482 if (apr_get_os_error()) /* is errno on POSIX */
484 /* ### Issue #3014: Return a specific error for broken pipes,
485 * ### with a single element in the error chain. */
486 if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
487 return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
489 return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
492 return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
498 const char *svn_cmdline_output_encoding(apr_pool_t *pool)
500 #ifdef CMDLINE_USE_CUSTOM_ENCODING
502 return apr_pstrdup(pool, output_encoding);
505 return SVN_APR_LOCALE_CHARSET;
509 svn_cmdline_handle_exit_error(svn_error_t *err,
514 * Don't print anything on broken pipes. The pipe was likely
515 * closed by the process at the other end. We expect that
516 * process to perform error reporting as necessary.
518 * ### This assumes that there is only one error in a chain for
519 * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
520 if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
521 svn_handle_error2(err, stderr, FALSE, prefix);
522 svn_error_clear(err);
524 svn_pool_destroy(pool);
528 struct trust_server_cert_non_interactive_baton {
529 svn_boolean_t trust_server_cert_unknown_ca;
530 svn_boolean_t trust_server_cert_cn_mismatch;
531 svn_boolean_t trust_server_cert_expired;
532 svn_boolean_t trust_server_cert_not_yet_valid;
533 svn_boolean_t trust_server_cert_other_failure;
536 /* This implements 'svn_auth_ssl_server_trust_prompt_func_t'.
538 Don't actually prompt. Instead, set *CRED_P to valid credentials
539 iff FAILURES is empty or may be accepted according to the flags
540 in BATON. If there are any other failure bits, then set *CRED_P
541 to null (that is, reject the cert).
543 Ignore MAY_SAVE; we don't save certs we never prompted for.
545 Ignore REALM and CERT_INFO,
547 Ignore any further films by George Lucas. */
549 trust_server_cert_non_interactive(svn_auth_cred_ssl_server_trust_t **cred_p,
552 apr_uint32_t failures,
553 const svn_auth_ssl_server_cert_info_t
555 svn_boolean_t may_save,
558 struct trust_server_cert_non_interactive_baton *b = baton;
559 apr_uint32_t non_ignored_failures;
562 /* Mask away bits we are instructed to ignore. */
563 non_ignored_failures = failures & ~(
564 (b->trust_server_cert_unknown_ca ? SVN_AUTH_SSL_UNKNOWNCA : 0)
565 | (b->trust_server_cert_cn_mismatch ? SVN_AUTH_SSL_CNMISMATCH : 0)
566 | (b->trust_server_cert_expired ? SVN_AUTH_SSL_EXPIRED : 0)
567 | (b->trust_server_cert_not_yet_valid ? SVN_AUTH_SSL_NOTYETVALID : 0)
568 | (b->trust_server_cert_other_failure ? SVN_AUTH_SSL_OTHER : 0)
571 /* If no failures remain, accept the certificate. */
572 if (non_ignored_failures == 0)
574 *cred_p = apr_pcalloc(pool, sizeof(**cred_p));
575 (*cred_p)->may_save = FALSE;
576 (*cred_p)->accepted_failures = failures;
583 svn_cmdline_create_auth_baton2(svn_auth_baton_t **ab,
584 svn_boolean_t non_interactive,
585 const char *auth_username,
586 const char *auth_password,
587 const char *config_dir,
588 svn_boolean_t no_auth_cache,
589 svn_boolean_t trust_server_cert_unknown_ca,
590 svn_boolean_t trust_server_cert_cn_mismatch,
591 svn_boolean_t trust_server_cert_expired,
592 svn_boolean_t trust_server_cert_not_yet_valid,
593 svn_boolean_t trust_server_cert_other_failure,
595 svn_cancel_func_t cancel_func,
600 svn_boolean_t store_password_val = TRUE;
601 svn_boolean_t store_auth_creds_val = TRUE;
602 svn_auth_provider_object_t *provider;
603 svn_cmdline_prompt_baton2_t *pb = NULL;
605 /* The whole list of registered providers */
606 apr_array_header_t *providers;
608 /* Populate the registered providers with the platform-specific providers */
609 SVN_ERR(svn_auth_get_platform_specific_client_providers(&providers,
612 /* If we have a cancellation function, cram it and the stuff it
613 needs into the prompt baton. */
616 pb = apr_palloc(pool, sizeof(*pb));
617 pb->cancel_func = cancel_func;
618 pb->cancel_baton = cancel_baton;
619 pb->config_dir = config_dir;
622 if (!non_interactive)
624 /* This provider doesn't prompt the user in order to get creds;
625 it prompts the user regarding the caching of creds. */
626 svn_auth_get_simple_provider2(&provider,
627 svn_cmdline_auth_plaintext_prompt,
632 svn_auth_get_simple_provider2(&provider, NULL, NULL, pool);
635 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
636 svn_auth_get_username_provider(&provider, pool);
637 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
639 svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
640 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
641 svn_auth_get_ssl_client_cert_file_provider(&provider, pool);
642 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
644 if (!non_interactive)
646 /* This provider doesn't prompt the user in order to get creds;
647 it prompts the user regarding the caching of creds. */
648 svn_auth_get_ssl_client_cert_pw_file_provider2
649 (&provider, svn_cmdline_auth_plaintext_passphrase_prompt,
654 svn_auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
657 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
659 if (!non_interactive)
661 svn_boolean_t ssl_client_cert_file_prompt;
663 SVN_ERR(svn_config_get_bool(cfg, &ssl_client_cert_file_prompt,
664 SVN_CONFIG_SECTION_AUTH,
665 SVN_CONFIG_OPTION_SSL_CLIENT_CERT_FILE_PROMPT,
668 /* Two basic prompt providers: username/password, and just username. */
669 svn_auth_get_simple_prompt_provider(&provider,
670 svn_cmdline_auth_simple_prompt,
674 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
676 svn_auth_get_username_prompt_provider
677 (&provider, svn_cmdline_auth_username_prompt, pb,
678 2, /* retry limit */ pool);
679 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
681 /* SSL prompt providers: server-certs and client-cert-passphrases. */
682 svn_auth_get_ssl_server_trust_prompt_provider
683 (&provider, svn_cmdline_auth_ssl_server_trust_prompt, pb, pool);
684 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
686 svn_auth_get_ssl_client_cert_pw_prompt_provider
687 (&provider, svn_cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool);
688 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
690 /* If configuration allows, add a provider for client-cert path
692 if (ssl_client_cert_file_prompt)
694 svn_auth_get_ssl_client_cert_prompt_provider
695 (&provider, svn_cmdline_auth_ssl_client_cert_prompt, pb, 2, pool);
696 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
699 else if (trust_server_cert_unknown_ca || trust_server_cert_cn_mismatch ||
700 trust_server_cert_expired || trust_server_cert_not_yet_valid ||
701 trust_server_cert_other_failure)
703 struct trust_server_cert_non_interactive_baton *b;
705 b = apr_palloc(pool, sizeof(*b));
706 b->trust_server_cert_unknown_ca = trust_server_cert_unknown_ca;
707 b->trust_server_cert_cn_mismatch = trust_server_cert_cn_mismatch;
708 b->trust_server_cert_expired = trust_server_cert_expired;
709 b->trust_server_cert_not_yet_valid = trust_server_cert_not_yet_valid;
710 b->trust_server_cert_other_failure = trust_server_cert_other_failure;
712 /* Remember, only register this provider if non_interactive. */
713 svn_auth_get_ssl_server_trust_prompt_provider
714 (&provider, trust_server_cert_non_interactive, b, pool);
715 APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
718 /* Build an authentication baton to give to libsvn_client. */
719 svn_auth_open(ab, providers, pool);
721 /* Place any default --username or --password credentials into the
722 auth_baton's run-time parameter hash. */
724 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_USERNAME,
727 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD,
730 /* Same with the --non-interactive option. */
732 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NON_INTERACTIVE, "");
735 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_CONFIG_DIR,
738 /* Determine whether storing passwords in any form is allowed.
739 * This is the deprecated location for this option, the new
740 * location is SVN_CONFIG_CATEGORY_SERVERS. The RA layer may
741 * override the value we set here. */
742 SVN_ERR(svn_config_get_bool(cfg, &store_password_val,
743 SVN_CONFIG_SECTION_AUTH,
744 SVN_CONFIG_OPTION_STORE_PASSWORDS,
745 SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS));
747 if (! store_password_val)
748 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
750 /* Determine whether we are allowed to write to the auth/ area.
751 * This is the deprecated location for this option, the new
752 * location is SVN_CONFIG_CATEGORY_SERVERS. The RA layer may
753 * override the value we set here. */
754 SVN_ERR(svn_config_get_bool(cfg, &store_auth_creds_val,
755 SVN_CONFIG_SECTION_AUTH,
756 SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
757 SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS));
759 if (no_auth_cache || ! store_auth_creds_val)
760 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
762 #ifdef SVN_HAVE_GNOME_KEYRING
763 svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC,
764 &svn_cmdline__auth_gnome_keyring_unlock_prompt);
765 #endif /* SVN_HAVE_GNOME_KEYRING */
771 svn_cmdline__getopt_init(apr_getopt_t **os,
776 apr_status_t apr_err = apr_getopt_init(os, pool, argc, argv);
778 return svn_error_wrap_apr(apr_err,
779 _("Error initializing command line arguments"));
785 svn_cmdline__print_xml_prop(svn_stringbuf_t **outstr,
786 const char* propname,
787 svn_string_t *propval,
788 svn_boolean_t inherited_prop,
791 const char *xml_safe;
792 const char *encoding = NULL;
795 *outstr = svn_stringbuf_create_empty(pool);
797 if (svn_xml_is_xml_safe(propval->data, propval->len))
799 svn_stringbuf_t *xml_esc = NULL;
800 svn_xml_escape_cdata_string(&xml_esc, propval, pool);
801 xml_safe = xml_esc->data;
805 const svn_string_t *base64ed = svn_base64_encode_string2(propval, TRUE,
808 xml_safe = base64ed->data;
812 svn_xml_make_open_tag(
813 outstr, pool, svn_xml_protect_pcdata,
814 inherited_prop ? "inherited_property" : "property",
816 "encoding", encoding, SVN_VA_NULL);
818 svn_xml_make_open_tag(
819 outstr, pool, svn_xml_protect_pcdata,
820 inherited_prop ? "inherited_property" : "property",
821 "name", propname, SVN_VA_NULL);
823 svn_stringbuf_appendcstr(*outstr, xml_safe);
825 svn_xml_make_close_tag(
827 inherited_prop ? "inherited_property" : "property");
832 /* Return the most similar string to NEEDLE in HAYSTACK, which contains
833 * HAYSTACK_LEN elements. Return NULL if no string is sufficiently similar.
835 /* See svn_cl__similarity_check() for a more general solution. */
837 most_similar(const char *needle_cstr,
838 const char **haystack,
839 apr_size_t haystack_len,
840 apr_pool_t *scratch_pool)
842 const char *max_similar = NULL;
843 apr_size_t max_score = 0;
846 svn_string_t *needle_str = svn_string_create(needle_cstr, scratch_pool);
848 svn_membuf__create(&membuf, 64, scratch_pool);
850 for (i = 0; i < haystack_len; i++)
853 svn_string_t *hay = svn_string_create(haystack[i], scratch_pool);
855 score = svn_string__similarity(needle_str, hay, &membuf, NULL);
857 /* If you update this factor, consider updating
858 * svn_cl__similarity_check(). */
859 if (score >= (2 * SVN_STRING__SIM_RANGE_MAX + 1) / 3
860 && score > max_score)
863 max_similar = haystack[i];
870 /* Verify that NEEDLE is in HAYSTACK, which contains HAYSTACK_LEN elements. */
872 string_in_array(const char *needle,
873 const char **haystack,
874 apr_size_t haystack_len,
875 apr_pool_t *scratch_pool)
877 const char *next_of_kin;
879 for (i = 0; i < haystack_len; i++)
881 if (!strcmp(needle, haystack[i]))
886 next_of_kin = most_similar(needle, haystack, haystack_len, scratch_pool);
888 return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
889 _("Ignoring unknown value '%s'; "
890 "did you mean '%s'?"),
891 needle, next_of_kin);
893 return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
894 _("Ignoring unknown value '%s'"),
898 #include "config_keys.inc"
900 /* Validate the FILE, SECTION, and OPTION components of CONFIG_OPTION are
901 * known. Return an error if not. (An unknown value may be either a typo
902 * or added in a newer minor version of Subversion.) */
904 validate_config_option(svn_cmdline__config_argument_t *config_option,
905 apr_pool_t *scratch_pool)
907 svn_boolean_t arbitrary_keys = FALSE;
909 /* TODO: some day, we could also verify that OPTION is valid for SECTION;
910 i.e., forbid invalid combinations such as config:auth:diff-extensions. */
912 #define ARRAYLEN(x) ( sizeof((x)) / sizeof((x)[0]) )
914 SVN_ERR(string_in_array(config_option->file, svn__valid_config_files,
915 ARRAYLEN(svn__valid_config_files),
917 SVN_ERR(string_in_array(config_option->section, svn__valid_config_sections,
918 ARRAYLEN(svn__valid_config_sections),
921 /* Don't validate option names for sections such as servers[group],
922 * config[tunnels], and config[auto-props] that permit arbitrary options. */
926 for (i = 0; i < ARRAYLEN(svn__empty_config_sections); i++)
928 if (!strcmp(config_option->section, svn__empty_config_sections[i]))
929 arbitrary_keys = TRUE;
933 if (! arbitrary_keys)
934 SVN_ERR(string_in_array(config_option->option, svn__valid_config_options,
935 ARRAYLEN(svn__valid_config_options),
944 svn_cmdline__parse_config_option(apr_array_header_t *config_options,
949 svn_cmdline__config_argument_t *config_option;
950 const char *first_colon, *second_colon, *equals_sign;
951 apr_size_t len = strlen(opt_arg);
952 if ((first_colon = strchr(opt_arg, ':')) && (first_colon != opt_arg))
954 if ((second_colon = strchr(first_colon + 1, ':')) &&
955 (second_colon != first_colon + 1))
957 if ((equals_sign = strchr(second_colon + 1, '=')) &&
958 (equals_sign != second_colon + 1))
960 svn_error_t *warning;
962 config_option = apr_pcalloc(pool, sizeof(*config_option));
963 config_option->file = apr_pstrndup(pool, opt_arg,
964 first_colon - opt_arg);
965 config_option->section = apr_pstrndup(pool, first_colon + 1,
966 second_colon - first_colon - 1);
967 config_option->option = apr_pstrndup(pool, second_colon + 1,
968 equals_sign - second_colon - 1);
970 warning = validate_config_option(config_option, pool);
973 svn_handle_warning2(stderr, warning, prefix);
974 svn_error_clear(warning);
977 if (! (strchr(config_option->option, ':')))
979 config_option->value = apr_pstrndup(pool, equals_sign + 1,
980 opt_arg + len - equals_sign - 1);
981 APR_ARRAY_PUSH(config_options, svn_cmdline__config_argument_t *)
988 return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
989 _("Invalid syntax of argument of --config-option"));
993 svn_cmdline__apply_config_options(apr_hash_t *config,
994 const apr_array_header_t *config_options,
996 const char *argument_name)
1000 for (i = 0; i < config_options->nelts; i++)
1003 svn_cmdline__config_argument_t *arg =
1004 APR_ARRAY_IDX(config_options, i,
1005 svn_cmdline__config_argument_t *);
1007 cfg = svn_hash_gets(config, arg->file);
1011 svn_config_set(cfg, arg->section, arg->option, arg->value);
1015 svn_error_t *err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
1016 _("Unrecognized file in argument of %s"), argument_name);
1018 svn_handle_warning2(stderr, err, prefix);
1019 svn_error_clear(err);
1023 return SVN_NO_ERROR;
1026 /* Return a copy, allocated in POOL, of the next line of text from *STR
1027 * up to and including a CR and/or an LF. Change *STR to point to the
1028 * remainder of the string after the returned part. If there are no
1029 * characters to be returned, return NULL; never return an empty string.
1032 next_line(const char **str, apr_pool_t *pool)
1034 const char *start = *str;
1035 const char *p = *str;
1037 /* n.b. Throughout this fn, we never read any character after a '\0'. */
1038 /* Skip over all non-EOL characters, if any. */
1039 while (*p != '\r' && *p != '\n' && *p != '\0')
1041 /* Skip over \r\n or \n\r or \r or \n, if any. */
1042 if (*p == '\r' || *p == '\n')
1046 if ((c == '\r' && *p == '\n') || (c == '\n' && *p == '\r'))
1050 /* Now p points after at most one '\n' and/or '\r'. */
1056 return svn_string_ncreate(start, p - start, pool)->data;
1060 svn_cmdline__indent_string(const char *str,
1064 svn_stringbuf_t *out = svn_stringbuf_create_empty(pool);
1067 while ((line = next_line(&str, pool)))
1069 svn_stringbuf_appendcstr(out, indent);
1070 svn_stringbuf_appendcstr(out, line);
1076 svn_cmdline__print_prop_hash(svn_stream_t *out,
1077 apr_hash_t *prop_hash,
1078 svn_boolean_t names_only,
1081 apr_array_header_t *sorted_props;
1084 sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
1086 for (i = 0; i < sorted_props->nelts; i++)
1088 svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
1089 const char *pname = item.key;
1090 svn_string_t *propval = item.value;
1091 const char *pname_stdout;
1093 if (svn_prop_needs_translation(pname))
1094 SVN_ERR(svn_subst_detranslate_string(&propval, propval,
1097 SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_stdout, pname, pool));
1101 pname_stdout = apr_psprintf(pool, " %s\n", pname_stdout);
1102 SVN_ERR(svn_subst_translate_cstring2(pname_stdout, &pname_stdout,
1103 APR_EOL_STR, /* 'native' eol */
1104 FALSE, /* no repair */
1105 NULL, /* no keywords */
1106 FALSE, /* no expansion */
1109 SVN_ERR(svn_stream_puts(out, pname_stdout));
1113 /* ### We leave these printfs for now, since if propval wasn't
1114 translated above, we don't know anything about its encoding.
1115 In fact, it might be binary data... */
1116 printf(" %s\n", pname_stdout);
1121 /* Add an extra newline to the value before indenting, so that
1122 * every line of output has the indentation whether the value
1123 * already ended in a newline or not. */
1124 const char *newval = apr_psprintf(pool, "%s\n", propval->data);
1125 const char *indented_newval = svn_cmdline__indent_string(newval,
1130 SVN_ERR(svn_stream_puts(out, indented_newval));
1134 printf("%s", indented_newval);
1139 return SVN_NO_ERROR;
1143 svn_cmdline__print_xml_prop_hash(svn_stringbuf_t **outstr,
1144 apr_hash_t *prop_hash,
1145 svn_boolean_t names_only,
1146 svn_boolean_t inherited_props,
1149 apr_array_header_t *sorted_props;
1152 if (*outstr == NULL)
1153 *outstr = svn_stringbuf_create_empty(pool);
1155 sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
1157 for (i = 0; i < sorted_props->nelts; i++)
1159 svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
1160 const char *pname = item.key;
1161 svn_string_t *propval = item.value;
1165 svn_xml_make_open_tag(
1166 outstr, pool, svn_xml_self_closing,
1167 inherited_props ? "inherited_property" : "property",
1168 "name", pname, SVN_VA_NULL);
1172 const char *pname_out;
1174 if (svn_prop_needs_translation(pname))
1175 SVN_ERR(svn_subst_detranslate_string(&propval, propval,
1178 SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_out, pname, pool));
1180 svn_cmdline__print_xml_prop(outstr, pname_out, propval,
1181 inherited_props, pool);
1185 return SVN_NO_ERROR;
1189 svn_cmdline__stdin_is_a_terminal(void)
1192 return (_isatty(STDIN_FILENO) != 0);
1194 return (isatty(STDIN_FILENO) != 0);
1199 svn_cmdline__stdout_is_a_terminal(void)
1202 return (_isatty(STDOUT_FILENO) != 0);
1204 return (isatty(STDOUT_FILENO) != 0);
1209 svn_cmdline__stderr_is_a_terminal(void)
1212 return (_isatty(STDERR_FILENO) != 0);
1214 return (isatty(STDERR_FILENO) != 0);
1219 svn_cmdline__be_interactive(svn_boolean_t non_interactive,
1220 svn_boolean_t force_interactive)
1222 /* If neither --non-interactive nor --force-interactive was passed,
1223 * be interactive if stdin is a terminal.
1224 * If --force-interactive was passed, always be interactive. */
1225 if (!force_interactive && !non_interactive)
1227 return svn_cmdline__stdin_is_a_terminal();
1229 else if (force_interactive)
1232 return !non_interactive;
1236 /* Helper for the next two functions. Set *EDITOR to some path to an
1237 editor binary. Sources to search include: the EDITOR_CMD argument
1238 (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
1239 is not NULL), $VISUAL, $EDITOR. Return
1240 SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
1241 static svn_error_t *
1242 find_editor_binary(const char **editor,
1243 const char *editor_cmd,
1247 struct svn_config_t *cfg;
1249 /* Use the editor specified on the command line via --editor-cmd, if any. */
1252 /* Otherwise look for the Subversion-specific environment variable. */
1254 e = getenv("SVN_EDITOR");
1256 /* If not found then fall back on the config file. */
1259 cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;
1260 svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
1261 SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
1264 /* If not found yet then try general purpose environment variables. */
1266 e = getenv("VISUAL");
1268 e = getenv("EDITOR");
1270 #ifdef SVN_CLIENT_EDITOR
1271 /* If still not found then fall back on the hard-coded default. */
1273 e = SVN_CLIENT_EDITOR;
1276 /* Error if there is no editor specified */
1281 for (c = e; *c; c++)
1282 if (!svn_ctype_isspace(*c))
1286 return svn_error_create
1287 (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
1288 _("The EDITOR, SVN_EDITOR or VISUAL environment variable or "
1289 "'editor-cmd' run-time configuration option is empty or "
1290 "consists solely of whitespace. Expected a shell command."));
1293 return svn_error_create
1294 (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
1295 _("None of the environment variables SVN_EDITOR, VISUAL or EDITOR are "
1296 "set, and no 'editor-cmd' run-time configuration option was found"));
1299 return SVN_NO_ERROR;
1304 svn_cmdline__edit_file_externally(const char *path,
1305 const char *editor_cmd,
1309 const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
1312 apr_status_t apr_err;
1314 svn_dirent_split(&base_dir, &file_name, path, pool);
1316 SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
1318 apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
1320 return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
1322 /* APR doesn't like "" directories */
1323 if (base_dir[0] == '\0')
1326 SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
1328 apr_err = apr_filepath_set(base_dir_apr, pool);
1330 return svn_error_wrap_apr
1331 (apr_err, _("Can't change working directory to '%s'"), base_dir);
1333 cmd = apr_psprintf(pool, "%s %s", editor, file_name);
1334 sys_err = system(cmd);
1336 apr_err = apr_filepath_set(old_cwd, pool);
1338 svn_handle_error2(svn_error_wrap_apr
1339 (apr_err, _("Can't restore working directory")),
1340 stderr, TRUE /* fatal */, "svn: ");
1343 /* Extracting any meaning from sys_err is platform specific, so just
1344 use the raw value. */
1345 return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
1346 _("system('%s') returned %d"), cmd, sys_err);
1348 return SVN_NO_ERROR;
1353 svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
1354 const char **tmpfile_left /* UTF-8! */,
1355 const char *editor_cmd,
1356 const char *base_dir /* UTF-8! */,
1357 const svn_string_t *contents /* UTF-8! */,
1358 const char *filename,
1360 svn_boolean_t as_text,
1361 const char *encoding,
1366 apr_file_t *tmp_file;
1367 const char *tmpfile_name;
1368 const char *tmpfile_native;
1369 const char *base_dir_apr;
1370 svn_string_t *translated_contents;
1371 apr_status_t apr_err;
1373 apr_finfo_t finfo_before, finfo_after;
1374 svn_error_t *err = SVN_NO_ERROR;
1377 svn_boolean_t remove_file = TRUE;
1379 SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
1381 /* Convert file contents from UTF-8/LF if desired. */
1384 const char *translated;
1385 SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated,
1387 NULL, FALSE, pool));
1388 translated_contents = svn_string_create_empty(pool);
1390 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data,
1391 translated, encoding, pool));
1393 SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data,
1395 translated_contents->len = strlen(translated_contents->data);
1398 translated_contents = svn_string_dup(contents, pool);
1400 /* Move to BASE_DIR to avoid getting characters that need quoting
1401 into tmpfile_name */
1402 apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
1404 return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
1406 /* APR doesn't like "" directories */
1407 if (base_dir[0] == '\0')
1410 SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
1411 apr_err = apr_filepath_set(base_dir_apr, pool);
1414 return svn_error_wrap_apr
1415 (apr_err, _("Can't change working directory to '%s'"), base_dir);
1418 /*** From here on, any problems that occur require us to cd back!! ***/
1420 /* Ask the working copy for a temporary file named FILENAME-something. */
1421 err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
1425 svn_io_file_del_none, pool, pool);
1427 if (err && (APR_STATUS_IS_EACCES(err->apr_err) || err->apr_err == EROFS))
1429 const char *temp_dir_apr;
1431 svn_error_clear(err);
1433 SVN_ERR(svn_io_temp_dir(&base_dir, pool));
1435 SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool));
1436 apr_err = apr_filepath_set(temp_dir_apr, pool);
1439 return svn_error_wrap_apr
1440 (apr_err, _("Can't change working directory to '%s'"), base_dir);
1443 err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
1447 svn_io_file_del_none, pool, pool);
1453 /*** From here on, any problems that occur require us to cleanup
1454 the file we just created!! ***/
1456 /* Dump initial CONTENTS to TMP_FILE. */
1457 err = svn_io_file_write_full(tmp_file, translated_contents->data,
1458 translated_contents->len, &written,
1461 err = svn_error_compose_create(err, svn_io_file_close(tmp_file, pool));
1463 /* Make sure the whole CONTENTS were written, else return an error. */
1467 /* Get information about the temporary file before the user has
1468 been allowed to edit its contents. */
1469 err = svn_io_stat(&finfo_before, tmpfile_name, APR_FINFO_MTIME, pool);
1473 /* Backdate the file a little bit in case the editor is very fast
1474 and doesn't change the size. (Use two seconds, since some
1475 filesystems have coarse granularity.) It's OK if this call
1476 fails, so we don't check its return value.*/
1477 err = svn_io_set_file_affected_time(finfo_before.mtime
1478 - apr_time_from_sec(2),
1479 tmpfile_name, pool);
1480 svn_error_clear(err);
1482 /* Stat it again to get the mtime we actually set. */
1483 err = svn_io_stat(&finfo_before, tmpfile_name,
1484 APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
1488 /* Prepare the editor command line. */
1489 err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
1492 cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
1494 /* If the caller wants us to leave the file around, return the path
1495 of the file we'll use, and make a note not to destroy it. */
1498 *tmpfile_left = svn_dirent_join(base_dir, tmpfile_name, pool);
1499 remove_file = FALSE;
1502 /* Now, run the editor command line. */
1503 sys_err = system(cmd);
1506 /* Extracting any meaning from sys_err is platform specific, so just
1507 use the raw value. */
1508 err = svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
1509 _("system('%s') returned %d"), cmd, sys_err);
1513 /* Get information about the temporary file after the assumed editing. */
1514 err = svn_io_stat(&finfo_after, tmpfile_name,
1515 APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
1519 /* If the file looks changed... */
1520 if ((finfo_before.mtime != finfo_after.mtime) ||
1521 (finfo_before.size != finfo_after.size))
1523 svn_stringbuf_t *edited_contents_s;
1524 err = svn_stringbuf_from_file2(&edited_contents_s, tmpfile_name, pool);
1528 *edited_contents = svn_stringbuf__morph_into_string(edited_contents_s);
1530 /* Translate back to UTF8/LF if desired. */
1533 err = svn_subst_translate_string2(edited_contents, NULL, NULL,
1534 *edited_contents, encoding, FALSE,
1538 err = svn_error_quick_wrap
1540 _("Error normalizing edited contents to internal format"));
1547 /* No edits seem to have been made */
1548 *edited_contents = NULL;
1554 /* Remove the file from disk. */
1555 err = svn_error_compose_create(
1557 svn_io_remove_file2(tmpfile_name, FALSE, pool));
1561 /* If we against all probability can't cd back, all further relative
1562 file references would be screwed up, so we have to abort. */
1563 apr_err = apr_filepath_set(old_cwd, pool);
1566 svn_handle_error2(svn_error_wrap_apr
1567 (apr_err, _("Can't restore working directory")),
1568 stderr, TRUE /* fatal */, "svn: ");
1571 return svn_error_trace(err);
1575 svn_cmdline__parse_trust_options(
1576 svn_boolean_t *trust_server_cert_unknown_ca,
1577 svn_boolean_t *trust_server_cert_cn_mismatch,
1578 svn_boolean_t *trust_server_cert_expired,
1579 svn_boolean_t *trust_server_cert_not_yet_valid,
1580 svn_boolean_t *trust_server_cert_other_failure,
1581 const char *opt_arg,
1582 apr_pool_t *scratch_pool)
1584 apr_array_header_t *failures;
1587 *trust_server_cert_unknown_ca = FALSE;
1588 *trust_server_cert_cn_mismatch = FALSE;
1589 *trust_server_cert_expired = FALSE;
1590 *trust_server_cert_not_yet_valid = FALSE;
1591 *trust_server_cert_other_failure = FALSE;
1593 failures = svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, scratch_pool);
1595 for (i = 0; i < failures->nelts; i++)
1597 const char *value = APR_ARRAY_IDX(failures, i, const char *);
1598 if (!strcmp(value, "unknown-ca"))
1599 *trust_server_cert_unknown_ca = TRUE;
1600 else if (!strcmp(value, "cn-mismatch"))
1601 *trust_server_cert_cn_mismatch = TRUE;
1602 else if (!strcmp(value, "expired"))
1603 *trust_server_cert_expired = TRUE;
1604 else if (!strcmp(value, "not-yet-valid"))
1605 *trust_server_cert_not_yet_valid = TRUE;
1606 else if (!strcmp(value, "other"))
1607 *trust_server_cert_other_failure = TRUE;
1609 return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
1610 _("Unknown value '%s' for %s.\n"
1611 "Supported values: %s"),
1613 "--trust-server-cert-failures",
1614 "unknown-ca, cn-mismatch, expired, "
1615 "not-yet-valid, other");
1618 return SVN_NO_ERROR;
1621 /* Flags to see if we've been cancelled by the client or not. */
1622 static volatile sig_atomic_t cancelled = FALSE;
1623 static volatile sig_atomic_t signum_cancelled = 0;
1625 /* The signals we handle. */
1626 static int signal_map [] = {
1629 /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
1640 /* A signal handler to support cancellation. */
1642 signal_handler(int signum)
1646 apr_signal(signum, SIG_IGN);
1648 for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
1649 if (signal_map[i] == signum)
1651 signum_cancelled = i + 1;
1656 /* An svn_cancel_func_t callback. */
1657 static svn_error_t *
1658 check_cancel(void *baton)
1660 /* Cancel baton should be always NULL in command line client. */
1661 SVN_ERR_ASSERT(baton == NULL);
1663 return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
1665 return SVN_NO_ERROR;
1669 svn_cmdline__setup_cancellation_handler(void)
1673 for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
1674 apr_signal(signal_map[i], signal_handler);
1677 /* Disable SIGPIPE generation for the platforms that have it. */
1678 apr_signal(SIGPIPE, SIG_IGN);
1682 /* Disable SIGXFSZ generation for the platforms that have it, otherwise
1683 * working with large files when compiled against an APR that doesn't have
1684 * large file support will crash the program, which is uncool. */
1685 apr_signal(SIGXFSZ, SIG_IGN);
1688 return check_cancel;
1692 svn_cmdline__disable_cancellation_handler(void)
1696 for (i = 0; i < sizeof(signal_map)/sizeof(signal_map[0]); ++i)
1697 apr_signal(signal_map[i], SIG_DFL);
1701 svn_cmdline__cancellation_exit(void)
1705 if (cancelled && signum_cancelled)
1706 signum = signal_map[signum_cancelled - 1];
1710 apr_signal(signum, SIG_DFL);
1711 /* No APR support for getpid() so cannot use apr_proc_kill(). */
1712 kill(getpid(), signum);