[systemd-devel] [PATCH] [RFC]logind: set locale in user sessions
Tom Gundersen
teg at jklm.no
Wed Jan 2 03:46:31 PST 2013
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
More information about the systemd-devel
mailing list