chiark / gitweb /
Remove src/libudev
[elogind.git] / src / locale / localed.c
index 529a9abfd6fdbeb4175daeddd0f4cd442c958f66..fd0eb2db550e6a7ef2976ba51bc90e0704066da5 100644 (file)
@@ -33,7 +33,6 @@
 #include "env-util.h"
 #include "fileio.h"
 #include "fileio-label.h"
-#include "label.h"
 #include "bus-util.h"
 #include "bus-error.h"
 #include "bus-message.h"
@@ -228,7 +227,7 @@ static int x11_read_data(Context *c) {
                 if (in_section && first_word(l, "Option")) {
                         _cleanup_strv_free_ char **a = NULL;
 
-                        r = strv_split_quoted(&a, l, false);
+                        r = strv_split_quoted(&a, l, 0);
                         if (r < 0)
                                 return r;
 
@@ -251,7 +250,7 @@ static int x11_read_data(Context *c) {
                 } else if (!in_section && first_word(l, "Section")) {
                         _cleanup_strv_free_ char **a = NULL;
 
-                        r = strv_split_quoted(&a, l, false);
+                        r = strv_split_quoted(&a, l, 0);
                         if (r < 0)
                                 return -ENOMEM;
 
@@ -512,7 +511,9 @@ static const char* strnulldash(const char *s) {
         return isempty(s) || streq(s, "-") ? NULL : s;
 }
 
-static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
+static int read_next_mapping(const char* filename,
+                             unsigned min_fields, unsigned max_fields,
+                             FILE *f, unsigned *n, char ***a) {
         assert(f);
         assert(n);
         assert(a);
@@ -521,6 +522,7 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
                 char line[LINE_MAX];
                 char *l, **b;
                 int r;
+                size_t length;
 
                 errno = 0;
                 if (!fgets(line, sizeof(line), f)) {
@@ -537,12 +539,13 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
                 if (l[0] == 0 || l[0] == '#')
                         continue;
 
-                r = strv_split_quoted(&b, l, false);
+                r = strv_split_quoted(&b, l, 0);
                 if (r < 0)
                         return r;
 
-                if (strv_length(b) < 5) {
-                        log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
+                length = strv_length(b);
+                if (length < min_fields || length > max_fields) {
+                        log_error("Invalid line %s:%u, ignoring.", filename, *n);
                         strv_free(b);
                         continue;
 
@@ -579,7 +582,7 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
                         _cleanup_strv_free_ char **a = NULL;
                         int r;
 
-                        r = read_next_mapping(f, &n, &a);
+                        r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
                         if (r < 0)
                                 return r;
                         if (r == 0)
@@ -677,7 +680,7 @@ static int find_legacy_keymap(Context *c, char **new_keymap) {
                 _cleanup_strv_free_ char **a = NULL;
                 unsigned matching = 0;
 
-                r = read_next_mapping(f, &n, &a);
+                r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -752,6 +755,35 @@ static int find_legacy_keymap(Context *c, char **new_keymap) {
         return 0;
 }
 
+static int find_language_fallback(const char *lang, char **language) {
+        _cleanup_fclose_ FILE *f = NULL;
+        unsigned n = 0;
+
+        assert(language);
+
+        f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                _cleanup_strv_free_ char **a = NULL;
+                int r;
+
+                r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a);
+                if (r <= 0)
+                        return r;
+
+                if (streq(lang, a[0])) {
+                        assert(strv_length(a) == 2);
+                        *language = a[1];
+                        a[1] = NULL;
+                        return 1;
+                }
+        }
+
+        assert_not_reached("should not be here");
+}
+
 static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
         bool modified = false;
         int r;
@@ -841,9 +873,10 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
         Context *c = userdata;
         _cleanup_strv_free_ char **l = NULL;
         char **i;
+        const char *lang = NULL;
         int interactive;
         bool modified = false;
-        bool passed[_LOCALE_MAX] = {};
+        bool have[_LOCALE_MAX] = {};
         int p;
         int r;
 
@@ -867,7 +900,10 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
                             (*i)[k] == '=' &&
                             locale_is_valid((*i) + k + 1)) {
                                 valid = true;
-                                passed[p] = true;
+                                have[p] = true;
+
+                                if (p == LOCALE_LANG)
+                                        lang = (*i) + k + 1;
 
                                 if (!streq_ptr(*i + k + 1, c->locale[p]))
                                         modified = true;
@@ -880,10 +916,31 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
         }
 
+        /* If LANG was specified, but not LANGUAGE, check if we should
+         * set it based on the language fallback table. */
+        if (have[LOCALE_LANG] && !have[LOCALE_LANGUAGE]) {
+                _cleanup_free_ char *language = NULL;
+
+                assert(lang);
+
+                (void) find_language_fallback(lang, &language);
+                if (language) {
+                        log_debug("Converted LANG=%s to LANGUAGE=%s", lang, language);
+                        if (!streq_ptr(language, c->locale[LOCALE_LANGUAGE])) {
+                                r = strv_extendf(&l, "LANGUAGE=%s", language);
+                                if (r < 0)
+                                        return r;
+
+                                have[LOCALE_LANGUAGE] = true;
+                                modified = true;
+                        }
+                }
+        }
+
         /* Check whether a variable is unset */
         if (!modified)
                 for (p = 0; p < _LOCALE_MAX; p++)
-                        if (!isempty(c->locale[p]) && !passed[p]) {
+                        if (!isempty(c->locale[p]) && !have[p]) {
                                 modified = true;
                                 break;
                         }
@@ -891,7 +948,14 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
         if (modified) {
                 _cleanup_strv_free_ char **settings = NULL;
 
-                r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-locale", interactive, &c->polkit_registry, error);
+                r = bus_verify_polkit_async(
+                                m,
+                                CAP_SYS_ADMIN,
+                                "org.freedesktop.locale1.set-locale",
+                                interactive,
+                                UID_INVALID,
+                                &c->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -911,7 +975,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
                         }
 
                 for (p = 0; p < _LOCALE_MAX; p++) {
-                        if (passed[p])
+                        if (have[p])
                                 continue;
 
                         free_and_replace(&c->locale[p], NULL);
@@ -969,7 +1033,14 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
                     (keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle))))
                         return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data");
 
-                r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", interactive, &c->polkit_registry, error);
+                r = bus_verify_polkit_async(
+                                m,
+                                CAP_SYS_ADMIN,
+                                "org.freedesktop.locale1.set-keyboard",
+                                interactive,
+                                UID_INVALID,
+                                &c->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1011,7 +1082,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
 static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
         const char *fmt;
 
-        fmt = strappenda("libxkbcommon: ", format);
+        fmt = strjoina("libxkbcommon: ", format);
         log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
 }
 
@@ -1088,7 +1159,14 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
                     (options && !string_is_safe(options)))
                         return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data");
 
-                r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", interactive, &c->polkit_registry, error);
+                r = bus_verify_polkit_async(
+                                m,
+                                CAP_SYS_ADMIN,
+                                "org.freedesktop.locale1.set-keyboard",
+                                interactive,
+                                UID_INVALID,
+                                &c->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)