|
|
bdc76f |
commit e485b2b6e006a7efa5d73e6be7e357a395c77fe3
|
|
|
bdc76f |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
bdc76f |
Date: Tue Apr 23 18:16:26 2019 +0200
|
|
|
bdc76f |
|
|
|
bdc76f |
locale: Add LOCPATH diagnostics to the locale program
|
|
|
bdc76f |
|
|
|
bdc76f |
The implementation of quote_string is based on support_quote_blob.
|
|
|
bdc76f |
|
|
|
bdc76f |
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
|
bdc76f |
|
|
|
bdc76f |
diff --git a/locale/Makefile b/locale/Makefile
|
|
|
bdc76f |
index fd9972279ba7fe0b..42bb36c7d374eebe 100644
|
|
|
bdc76f |
--- a/locale/Makefile
|
|
|
bdc76f |
+++ b/locale/Makefile
|
|
|
bdc76f |
@@ -28,6 +28,7 @@ routines = setlocale findlocale loadlocale loadarchive \
|
|
|
bdc76f |
localeconv nl_langinfo nl_langinfo_l mb_cur_max \
|
|
|
bdc76f |
newlocale duplocale freelocale uselocale
|
|
|
bdc76f |
tests = tst-C-locale tst-locname tst-duplocale
|
|
|
bdc76f |
+tests-special = $(objpfx)tst-locale-locpath.out
|
|
|
bdc76f |
categories = ctype messages monetary numeric time paper name \
|
|
|
bdc76f |
address telephone measurement identification collate
|
|
|
bdc76f |
aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
|
|
|
bdc76f |
@@ -104,3 +105,7 @@ cpp-srcs-left := $(localedef-modules) $(localedef-aux) $(locale-modules) \
|
|
|
bdc76f |
$(lib-modules)
|
|
|
bdc76f |
lib := locale-programs
|
|
|
bdc76f |
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+$(objpfx)tst-locale-locpath.out : tst-locale-locpath.sh $(objpfx)locale
|
|
|
bdc76f |
+ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' '$(test-wrapper-env)' > $@; \
|
|
|
bdc76f |
+ $(evaluate-test)
|
|
|
bdc76f |
diff --git a/locale/programs/locale.c b/locale/programs/locale.c
|
|
|
bdc76f |
index 86941e4ef6e67d78..0e2e3e4e5788246f 100644
|
|
|
bdc76f |
--- a/locale/programs/locale.c
|
|
|
bdc76f |
+++ b/locale/programs/locale.c
|
|
|
bdc76f |
@@ -173,6 +173,9 @@ static int write_archive_locales (void **all_datap, char *linebuf);
|
|
|
bdc76f |
static void write_charmaps (void);
|
|
|
bdc76f |
static void show_locale_vars (void);
|
|
|
bdc76f |
static void show_info (const char *name);
|
|
|
bdc76f |
+static void try_setlocale (int category, const char *category_name);
|
|
|
bdc76f |
+static char *quote_string (const char *input);
|
|
|
bdc76f |
+static void setlocale_diagnostics (void);
|
|
|
bdc76f |
|
|
|
bdc76f |
|
|
|
bdc76f |
int
|
|
|
bdc76f |
@@ -186,10 +189,8 @@ main (int argc, char *argv[])
|
|
|
bdc76f |
|
|
|
bdc76f |
/* Set locale. Do not set LC_ALL because the other categories must
|
|
|
bdc76f |
not be affected (according to POSIX.2). */
|
|
|
bdc76f |
- if (setlocale (LC_CTYPE, "") == NULL)
|
|
|
bdc76f |
- error (0, errno, gettext ("Cannot set LC_CTYPE to default locale"));
|
|
|
bdc76f |
- if (setlocale (LC_MESSAGES, "") == NULL)
|
|
|
bdc76f |
- error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale"));
|
|
|
bdc76f |
+ try_setlocale (LC_CTYPE, "LC_CTYPE");
|
|
|
bdc76f |
+ try_setlocale (LC_MESSAGES, "LC_MESSAGES");
|
|
|
bdc76f |
|
|
|
bdc76f |
/* Initialize the message catalog. */
|
|
|
bdc76f |
textdomain (PACKAGE);
|
|
|
bdc76f |
@@ -200,9 +201,8 @@ main (int argc, char *argv[])
|
|
|
bdc76f |
/* `-a' requests the names of all available locales. */
|
|
|
bdc76f |
if (do_all != 0)
|
|
|
bdc76f |
{
|
|
|
bdc76f |
- if (setlocale (LC_COLLATE, "") == NULL)
|
|
|
bdc76f |
- error (0, errno,
|
|
|
bdc76f |
- gettext ("Cannot set LC_COLLATE to default locale"));
|
|
|
bdc76f |
+ setlocale_diagnostics ();
|
|
|
bdc76f |
+ try_setlocale (LC_COLLATE, "LC_COLLATE");
|
|
|
bdc76f |
write_locales ();
|
|
|
bdc76f |
exit (EXIT_SUCCESS);
|
|
|
bdc76f |
}
|
|
|
bdc76f |
@@ -211,14 +211,15 @@ main (int argc, char *argv[])
|
|
|
bdc76f |
used for the -f argument to localedef(1). */
|
|
|
bdc76f |
if (do_charmaps != 0)
|
|
|
bdc76f |
{
|
|
|
bdc76f |
+ setlocale_diagnostics ();
|
|
|
bdc76f |
write_charmaps ();
|
|
|
bdc76f |
exit (EXIT_SUCCESS);
|
|
|
bdc76f |
}
|
|
|
bdc76f |
|
|
|
bdc76f |
/* Specific information about the current locale are requested.
|
|
|
bdc76f |
Change to this locale now. */
|
|
|
bdc76f |
- if (setlocale (LC_ALL, "") == NULL)
|
|
|
bdc76f |
- error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
|
|
|
bdc76f |
+ try_setlocale (LC_ALL, "LC_ALL");
|
|
|
bdc76f |
+ setlocale_diagnostics ();
|
|
|
bdc76f |
|
|
|
bdc76f |
/* If no real argument is given we have to print the contents of the
|
|
|
bdc76f |
current locale definition variables. These are LANG and the LC_*. */
|
|
|
bdc76f |
@@ -983,3 +984,121 @@ show_info (const char *name)
|
|
|
bdc76f |
For testing and perhaps advanced use allow some more symbols. */
|
|
|
bdc76f |
locale_special (name, show_category_name, show_keyword_name);
|
|
|
bdc76f |
}
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+/* Set to true by try_setlocale if setlocale fails. Used by
|
|
|
bdc76f |
+ setlocale_diagnostics. */
|
|
|
bdc76f |
+static bool setlocale_failed;
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+/* Call setlocale, with non-fatal error reporting. */
|
|
|
bdc76f |
+static void
|
|
|
bdc76f |
+try_setlocale (int category, const char *category_name)
|
|
|
bdc76f |
+{
|
|
|
bdc76f |
+ if (setlocale (category, "") == NULL)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ error (0, errno, gettext ("Cannot set %s to default locale"),
|
|
|
bdc76f |
+ category_name);
|
|
|
bdc76f |
+ setlocale_failed = true;
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+}
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+/* Return a quoted version of the passed string, or NULL on error. */
|
|
|
bdc76f |
+static char *
|
|
|
bdc76f |
+quote_string (const char *input)
|
|
|
bdc76f |
+{
|
|
|
bdc76f |
+ char *buffer;
|
|
|
bdc76f |
+ size_t length;
|
|
|
bdc76f |
+ FILE *stream = open_memstream (&buffer, &length);
|
|
|
bdc76f |
+ if (stream == NULL)
|
|
|
bdc76f |
+ return NULL;
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+ while (true)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ unsigned char ch = *input++;
|
|
|
bdc76f |
+ if (ch == '\0')
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+ /* Use C backslash escapes for those control characters for
|
|
|
bdc76f |
+ which they are defined. */
|
|
|
bdc76f |
+ switch (ch)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ case '\a':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('a', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\b':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('b', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\f':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('f', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\n':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('n', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\r':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('r', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\t':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('t', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\v':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked ('v', stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ case '\\':
|
|
|
bdc76f |
+ case '\'':
|
|
|
bdc76f |
+ case '\"':
|
|
|
bdc76f |
+ putc_unlocked ('\\', stream);
|
|
|
bdc76f |
+ putc_unlocked (ch, stream);
|
|
|
bdc76f |
+ break;
|
|
|
bdc76f |
+ default:
|
|
|
bdc76f |
+ if (ch < ' ' || ch > '~')
|
|
|
bdc76f |
+ /* Use octal sequences because they are fixed width,
|
|
|
bdc76f |
+ unlike hexadecimal sequences. */
|
|
|
bdc76f |
+ fprintf (stream, "\\%03o", ch);
|
|
|
bdc76f |
+ else
|
|
|
bdc76f |
+ putc_unlocked (ch, stream);
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+ if (ferror (stream))
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ fclose (stream);
|
|
|
bdc76f |
+ free (buffer);
|
|
|
bdc76f |
+ return NULL;
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+ if (fclose (stream) != 0)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ free (buffer);
|
|
|
bdc76f |
+ return NULL;
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+ return buffer;
|
|
|
bdc76f |
+}
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+/* Print additional information if there was a setlocale error (during
|
|
|
bdc76f |
+ try_setlocale). */
|
|
|
bdc76f |
+static void
|
|
|
bdc76f |
+setlocale_diagnostics (void)
|
|
|
bdc76f |
+{
|
|
|
bdc76f |
+ if (setlocale_failed)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ const char *locpath = getenv ("LOCPATH");
|
|
|
bdc76f |
+ if (locpath != NULL)
|
|
|
bdc76f |
+ {
|
|
|
bdc76f |
+ char *quoted = quote_string (locpath);
|
|
|
bdc76f |
+ if (quoted != NULL)
|
|
|
bdc76f |
+ fprintf (stderr,
|
|
|
bdc76f |
+ gettext ("\
|
|
|
bdc76f |
+warning: The LOCPATH variable is set to \"%s\"\n"),
|
|
|
bdc76f |
+ quoted);
|
|
|
bdc76f |
+ else
|
|
|
bdc76f |
+ fputs ("warning: The LOCPATH variable is set\n", stderr);
|
|
|
bdc76f |
+ free (quoted);
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+ }
|
|
|
bdc76f |
+}
|
|
|
bdc76f |
diff --git a/locale/tst-locale-locpath.sh b/locale/tst-locale-locpath.sh
|
|
|
bdc76f |
new file mode 100644
|
|
|
bdc76f |
index 0000000000000000..b83de90a39121af6
|
|
|
bdc76f |
--- /dev/null
|
|
|
bdc76f |
+++ b/locale/tst-locale-locpath.sh
|
|
|
bdc76f |
@@ -0,0 +1,83 @@
|
|
|
bdc76f |
+#!/bin/sh
|
|
|
bdc76f |
+# Test that locale prints LOCPATH on failure.
|
|
|
bdc76f |
+# Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
bdc76f |
+# This file is part of the GNU C Library.
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+# The GNU C Library is free software; you can redistribute it and/or
|
|
|
bdc76f |
+# modify it under the terms of the GNU Lesser General Public
|
|
|
bdc76f |
+# License as published by the Free Software Foundation; either
|
|
|
bdc76f |
+# version 2.1 of the License, or (at your option) any later version.
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+# The GNU C Library is distributed in the hope that it will be useful,
|
|
|
bdc76f |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
bdc76f |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
bdc76f |
+# Lesser General Public License for more details.
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+# You should have received a copy of the GNU Lesser General Public
|
|
|
bdc76f |
+# License along with the GNU C Library; if not, see
|
|
|
bdc76f |
+# <http://www.gnu.org/licenses/>.
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+set -ex
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+common_objpfx=$1
|
|
|
bdc76f |
+test_wrapper_env=$2
|
|
|
bdc76f |
+run_program_env=$3
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+LIBPATH="$common_objpfx"
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+testroot="${common_objpfx}locale/tst-locale-locpath-directory"
|
|
|
bdc76f |
+cleanup () {
|
|
|
bdc76f |
+ rm -rf "$testroot"
|
|
|
bdc76f |
+}
|
|
|
bdc76f |
+trap cleanup 0
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+rm -rf "$testroot"
|
|
|
bdc76f |
+mkdir -p $testroot
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+unset LANG
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+${test_wrapper_env} \
|
|
|
bdc76f |
+${run_program_env} LC_ALL=invalid-locale LOCPATH=does-not-exist \
|
|
|
bdc76f |
+${common_objpfx}elf/ld.so --library-path "$LIBPATH" \
|
|
|
bdc76f |
+ "${common_objpfx}locale/locale" \
|
|
|
bdc76f |
+ > "$testroot/stdout" 2> "$testroot/stderr"
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+echo "* standard error"
|
|
|
bdc76f |
+cat "$testroot/stderr"
|
|
|
bdc76f |
+echo "* standard output"
|
|
|
bdc76f |
+cat "$testroot/stdout"
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+cat > "$testroot/stderr-expected" <
|
|
|
bdc76f |
+${common_objpfx}locale/locale: Cannot set LC_CTYPE to default locale: No such file or directory
|
|
|
bdc76f |
+${common_objpfx}locale/locale: Cannot set LC_MESSAGES to default locale: No such file or directory
|
|
|
bdc76f |
+${common_objpfx}locale/locale: Cannot set LC_ALL to default locale: No such file or directory
|
|
|
bdc76f |
+warning: The LOCPATH variable is set to "does-not-exist"
|
|
|
bdc76f |
+EOF
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+cat > "$testroot/stdout-expected" <
|
|
|
bdc76f |
+LANG=
|
|
|
bdc76f |
+LC_CTYPE="invalid-locale"
|
|
|
bdc76f |
+LC_NUMERIC="invalid-locale"
|
|
|
bdc76f |
+LC_TIME="invalid-locale"
|
|
|
bdc76f |
+LC_COLLATE="invalid-locale"
|
|
|
bdc76f |
+LC_MONETARY="invalid-locale"
|
|
|
bdc76f |
+LC_MESSAGES="invalid-locale"
|
|
|
bdc76f |
+LC_PAPER="invalid-locale"
|
|
|
bdc76f |
+LC_NAME="invalid-locale"
|
|
|
bdc76f |
+LC_ADDRESS="invalid-locale"
|
|
|
bdc76f |
+LC_TELEPHONE="invalid-locale"
|
|
|
bdc76f |
+LC_MEASUREMENT="invalid-locale"
|
|
|
bdc76f |
+LC_IDENTIFICATION="invalid-locale"
|
|
|
bdc76f |
+LC_ALL=invalid-locale
|
|
|
bdc76f |
+EOF
|
|
|
bdc76f |
+
|
|
|
bdc76f |
+errors=0
|
|
|
bdc76f |
+if ! cmp -s "$testroot/stderr-expected" "$testroot/stderr" ; then
|
|
|
bdc76f |
+ echo "error: standard error not correct"
|
|
|
bdc76f |
+ errors=1
|
|
|
bdc76f |
+fi
|
|
|
bdc76f |
+if ! cmp -s "$testroot/stdout-expected" "$testroot/stdout" ; then
|
|
|
bdc76f |
+ echo "error: standard output not correct"
|
|
|
bdc76f |
+ errors=1
|
|
|
bdc76f |
+fi
|
|
|
bdc76f |
+exit $errors
|