Changes the pam module to now set the locale for user-sessions, similarly to what is done system-wide in PID1.
The logic is: the kernel command-line takes precedence, then XDG_CONFIG_HOME/locale.conf, then /etc/locale.conf and finally any legacy distro-specific files that might still be supported. The parsing of the locale settings is split out of core/ and moved to shared/. This is an important feature for Arch, as we traditionally set the system locale in all user sessions, so this means we can remove a work-around [0] and close some related bugs (e.g., [1]). [0]: <https://projects.archlinux.org/svntogit/packages.git/tree/trunk/locale.sh?h=packages/filesystem> [1]: <https://bugs.archlinux.org/task/33231> --- Makefile.am | 5 +- man/locale.conf.xml | 17 +++- src/core/locale-setup.c | 196 ++-------------------------------------------- src/login/pam-module.c | 57 ++++++++++++++ src/shared/locale-parse.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/locale-parse.h | 63 +++++++++++++++ 6 files changed, 341 insertions(+), 193 deletions(-) create mode 100644 src/shared/locale-parse.c create mode 100644 src/shared/locale-parse.h diff --git a/Makefile.am b/Makefile.am index 94ae549..f78ce99 100644 --- a/Makefile.am +++ b/Makefile.am @@ -847,7 +847,10 @@ libsystemd_shared_la_SOURCES = \ src/shared/time-dst.c \ src/shared/time-dst.h \ src/shared/calendarspec.c \ - src/shared/calendarspec.h + src/shared/calendarspec.h \ + src/shared/locale-parse.c \ + src/shared/locale-parse.h + libsystemd_shared_la_LIBADD = libsystemd-daemon.la diff --git a/man/locale.conf.xml b/man/locale.conf.xml index 06c0af0..5d8e99a 100644 --- a/man/locale.conf.xml +++ b/man/locale.conf.xml @@ -49,6 +49,7 @@ <refsynopsisdiv> <para><filename>/etc/locale.conf</filename></para> + <para><filename>$XDG_CONFIG_HOME/locale.conf</filename></para> </refsynopsisdiv> <refsect1> @@ -57,7 +58,14 @@ <para>The <filename>/etc/locale.conf</filename> file configures system-wide locale settings. It is read at early-boot by - <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> + and at session-start by + <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> + + <para>The <filename>$XDG_CONFIG_HOME/locale.conf</filename> + file configures user-specific locale settings. It is read + at session-start by + <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> <para>The basic file format of <filename>locale.conf</filename> is a @@ -87,6 +95,13 @@ used to override the locale settings at boot.</para> <para>The locale settings configured in + <filename>$XDG_CONFIG_HOME/locale.conf</filename>, are + user-specific and are inherited by every program in the + users session, unless overridden or unset by individual + programs. + </para> + + <para>The locale settings configured in <filename>/etc/locale.conf</filename> are system-wide and are inherited by every service or user, unless overridden or unset by individual programs or diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 8821fc2..f4ecb9e 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -19,208 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <stdlib.h> #include <errno.h> #include "locale-setup.h" -#include "util.h" +#include "locale-parse.h" #include "macro.h" -#include "virt.h" - -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - - VARIABLE_LANG, - VARIABLE_LANGUAGE, - VARIABLE_LC_CTYPE, - VARIABLE_LC_NUMERIC, - VARIABLE_LC_TIME, - VARIABLE_LC_COLLATE, - VARIABLE_LC_MONETARY, - VARIABLE_LC_MESSAGES, - VARIABLE_LC_PAPER, - VARIABLE_LC_NAME, - VARIABLE_LC_ADDRESS, - VARIABLE_LC_TELEPHONE, - VARIABLE_LC_MEASUREMENT, - VARIABLE_LC_IDENTIFICATION, - _VARIABLE_MAX -}; - -static const char * const variable_names[_VARIABLE_MAX] = { - [VARIABLE_LANG] = "LANG", - [VARIABLE_LANGUAGE] = "LANGUAGE", - [VARIABLE_LC_CTYPE] = "LC_CTYPE", - [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", - [VARIABLE_LC_TIME] = "LC_TIME", - [VARIABLE_LC_COLLATE] = "LC_COLLATE", - [VARIABLE_LC_MONETARY] = "LC_MONETARY", - [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", - [VARIABLE_LC_PAPER] = "LC_PAPER", - [VARIABLE_LC_NAME] = "LC_NAME", - [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", - [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", - [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", - [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; int locale_setup(void) { char *variables[_VARIABLE_MAX]; - int r = 0, i; + int r, i; zero(variables); - if (detect_container(NULL) <= 0) { - r = parse_env_file("/proc/cmdline", WHITESPACE, -#if defined(TARGET_FEDORA) - "LANG", &variables[VARIABLE_LANG], -#endif - "locale.LANG", &variables[VARIABLE_LANG], - "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], - "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "locale.LC_TIME", &variables[VARIABLE_LC_TIME], - "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], - "locale.LC_NAME", &variables[VARIABLE_LC_NAME], - "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); - } - - /* Hmm, nothing set on the kernel cmd line? Then let's - * try /etc/locale.conf */ - if (r <= 0) { - r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LANGUAGE", &variables[VARIABLE_LANGUAGE], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/locale.conf: %s", strerror(-r)); - } - -#if defined(TARGET_ALTLINUX) - if (r <= 0) { - r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - -#elif defined(TARGET_SUSE) - if (r <= 0) { - r = parse_env_file("/etc/sysconfig/language", NEWLINE, - "RC_LANG", &variables[VARIABLE_LANG], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r)); - } - -#elif defined(TARGET_DEBIAN) || defined(TARGET_ANGSTROM) - if (r <= 0) { - r = parse_env_file("/etc/default/locale", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/default/locale: %s", strerror(-r)); - } - -#elif defined(TARGET_GENTOO) - /* Gentoo's openrc expects locale variables in /etc/env.d/ - * These files are later compiled by env-update into shell - * export commands at /etc/profile.env, with variables being - * exported by openrc's runscript (so /etc/init.d/) - */ - if (r <= 0) { - r = parse_env_file("/etc/profile.env", NEWLINE, - "export LANG", &variables[VARIABLE_LANG], - "export LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "export LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "export LC_TIME", &variables[VARIABLE_LC_TIME], - "export LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "export LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "export LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "export LC_PAPER", &variables[VARIABLE_LC_PAPER], - "export LC_NAME", &variables[VARIABLE_LC_NAME], - "export LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "export LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "export LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/profile.env: %s", strerror(-r)); - } - -#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA) - if (r <= 0) { - r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - -#endif - - if (!variables[VARIABLE_LANG]) { - variables[VARIABLE_LANG] = strdup("C"); - if (!variables[VARIABLE_LANG]) { - r = -ENOMEM; - goto finish; - } - } + r = locale_parse(variables, NULL); + if (r < 0) + goto finish; for (i = 0; i < _VARIABLE_MAX; i++) { if (variables[i]) { diff --git a/src/login/pam-module.c b/src/login/pam-module.c index 88b0ef9..8971658 100644 --- a/src/login/pam-module.c +++ b/src/login/pam-module.c @@ -41,6 +41,7 @@ #include "dbus-common.h" #include "def.h" #include "socket-util.h" +#include "locale-parse.h" static int parse_argv(pam_handle_t *handle, int argc, const char **argv, @@ -321,6 +322,60 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_ return 0; } +static int locale_setup(pam_handle_t *handle, const char *home) { + char *variables[_VARIABLE_MAX]; + _cleanup_free_ char *user_locale = NULL; + const char *path; + int r, i; + + assert(handle); + + zero(variables); + + path = pam_getenv(handle, "XDG_CONFIG_HOME"); + if (isempty(path)) + path = getenv("XDG_CONFIG_HOME"); + + if (!isempty(path)) { + if (asprintf(&user_locale, "%s/locale.conf", path) < 0) { + r = PAM_BUF_ERR; + goto finish; + } + } else { + path = pam_getenv(handle, "HOME"); + if (isempty(path)) + path = getenv("HOME"); + if (isempty(path)) + path = home; + + if (asprintf(&user_locale, "%s/.config/locale.conf", path) < 0) { + r = PAM_BUF_ERR; + goto finish; + } + } + + r = locale_parse(variables, user_locale); + if (r < 0) + goto finish; + + for (i = 0; i < _VARIABLE_MAX; i++) { + if (variables[i]) { + if (pam_misc_setenv(handle, variable_names[i], variables[i], 0) < 0) { + r = -errno; + goto finish; + } + } + } + + r = 0; + +finish: + for (i = 0; i < _VARIABLE_MAX; i++) + free(variables[i]); + + return r; +} + _public_ PAM_EXTERN int pam_sm_open_session( pam_handle_t *handle, int flags, @@ -364,6 +419,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) goto finish; + locale_setup(handle, pw->pw_dir); + /* Make sure we don't enter a loop by talking to * systemd-logind when it is actually waiting for the * background to finish start-up. If the service is diff --git a/src/shared/locale-parse.c b/src/shared/locale-parse.c new file mode 100644 index 0000000..9e04fbd --- /dev/null +++ b/src/shared/locale-parse.c @@ -0,0 +1,196 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <string.h> +#include <errno.h> + +#include "locale-parse.h" +#include "util.h" +#include "virt.h" + +static int locale_parse_file(char *variables[_VARIABLE_MAX], const char *filename) { + int r; + + assert(filename); + + r = parse_env_file(filename, NEWLINE, + "LANG", &variables[VARIABLE_LANG], + "LANGUAGE", &variables[VARIABLE_LANGUAGE], + "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "LC_TIME", &variables[VARIABLE_LC_TIME], + "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "LC_PAPER", &variables[VARIABLE_LC_PAPER], + "LC_NAME", &variables[VARIABLE_LC_NAME], + "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read %s: %s", filename, strerror(-r)); + + return r; +} + +int locale_parse(char *variables[_VARIABLE_MAX], const char *user_locale) { + int r = 0; + + if (detect_container(NULL) <= 0) { + r = parse_env_file("/proc/cmdline", WHITESPACE, +#if defined(TARGET_FEDORA) + "LANG", &variables[VARIABLE_LANG], +#endif + "locale.LANG", &variables[VARIABLE_LANG], + "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], + "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "locale.LC_TIME", &variables[VARIABLE_LC_TIME], + "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], + "locale.LC_NAME", &variables[VARIABLE_LC_NAME], + "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); + } + + /* If nothing set on the kernel commandline, parse user-specific config file */ + if (r <= 0 && user_locale) + r = locale_parse_file(variables, user_locale); + + /* If the user-specific config file, could not be parsed, try the system-wide config file */ + if (r <= 0) + r = locale_parse_file(variables, "/etc/locale.conf"); + + /* If the system-wide config file could not be parsed, try a legacy file */ +#if defined(TARGET_ALTLINUX) + if (r <= 0) { + r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, + "LANG", &variables[VARIABLE_LANG], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); + } + +#elif defined(TARGET_SUSE) + if (r <= 0) { + r = parse_env_file("/etc/sysconfig/language", NEWLINE, + "RC_LANG", &variables[VARIABLE_LANG], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r)); + } + +#elif defined(TARGET_DEBIAN) || defined(TARGET_ANGSTROM) + if (r <= 0) { + r = parse_env_file("/etc/default/locale", NEWLINE, + "LANG", &variables[VARIABLE_LANG], + "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "LC_TIME", &variables[VARIABLE_LC_TIME], + "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "LC_PAPER", &variables[VARIABLE_LC_PAPER], + "LC_NAME", &variables[VARIABLE_LC_NAME], + "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/default/locale: %s", strerror(-r)); + } + +#elif defined(TARGET_GENTOO) + /* Gentoo's openrc expects locale variables in /etc/env.d/ + * These files are later compiled by env-update into shell + * export commands at /etc/profile.env, with variables being + * exported by openrc's runscript (so /etc/init.d/) + */ + if (r <= 0) { + r = parse_env_file("/etc/profile.env", NEWLINE, + "export LANG", &variables[VARIABLE_LANG], + "export LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "export LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "export LC_TIME", &variables[VARIABLE_LC_TIME], + "export LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "export LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "export LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "export LC_PAPER", &variables[VARIABLE_LC_PAPER], + "export LC_NAME", &variables[VARIABLE_LC_NAME], + "export LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "export LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "export LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/profile.env: %s", strerror(-r)); + } + +#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA) + if (r <= 0) { + r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, + "LANG", &variables[VARIABLE_LANG], + "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "LC_TIME", &variables[VARIABLE_LC_TIME], + "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "LC_PAPER", &variables[VARIABLE_LC_PAPER], + "LC_NAME", &variables[VARIABLE_LC_NAME], + "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); + } + +#endif + + if (!variables[VARIABLE_LANG]) { + variables[VARIABLE_LANG] = strdup("C"); + if (!variables[VARIABLE_LANG]) { + return -ENOMEM; + } + } + + return 0; +} diff --git a/src/shared/locale-parse.h b/src/shared/locale-parse.h new file mode 100644 index 0000000..a829730 --- /dev/null +++ b/src/shared/locale-parse.h @@ -0,0 +1,63 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +enum { + /* We don't list LC_ALL here on purpose. People should be + * using LANG instead. */ + + VARIABLE_LANG, + VARIABLE_LANGUAGE, + VARIABLE_LC_CTYPE, + VARIABLE_LC_NUMERIC, + VARIABLE_LC_TIME, + VARIABLE_LC_COLLATE, + VARIABLE_LC_MONETARY, + VARIABLE_LC_MESSAGES, + VARIABLE_LC_PAPER, + VARIABLE_LC_NAME, + VARIABLE_LC_ADDRESS, + VARIABLE_LC_TELEPHONE, + VARIABLE_LC_MEASUREMENT, + VARIABLE_LC_IDENTIFICATION, + _VARIABLE_MAX +}; + +static const char * const variable_names[_VARIABLE_MAX] = { + [VARIABLE_LANG] = "LANG", + [VARIABLE_LANGUAGE] = "LANGUAGE", + [VARIABLE_LC_CTYPE] = "LC_CTYPE", + [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", + [VARIABLE_LC_TIME] = "LC_TIME", + [VARIABLE_LC_COLLATE] = "LC_COLLATE", + [VARIABLE_LC_MONETARY] = "LC_MONETARY", + [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", + [VARIABLE_LC_PAPER] = "LC_PAPER", + [VARIABLE_LC_NAME] = "LC_NAME", + [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", + [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", + [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +}; + +int locale_parse(char *[], const char *); -- 1.8.0.3 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel