X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flocale%2Flocaled.c;h=1fb8cdc3410e6e147fd258731a29b207024b01d0;hb=ce06fdfb3de7a6591041828361f8d10c04a4677e;hp=4e56382f4f2365d6bd4acd2cd7c72cec7981808b;hpb=d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62;p=elogind.git diff --git a/src/locale/localed.c b/src/locale/localed.c index 4e56382f4..1fb8cdc34 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "sd-bus.h" @@ -34,12 +33,12 @@ #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" #include "event-util.h" #include "locale-util.h" +#include "selinux-util.h" #ifdef HAVE_XKBCOMMON #include @@ -375,7 +374,7 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) - log_error("Failed to update the manager environment: %s", strerror(-r)); + log_error_errno(r, "Failed to update the manager environment: %m"); return 0; } @@ -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)) { @@ -541,8 +543,9 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) { 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) @@ -610,10 +613,8 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { int r; r = x11_write_data(c); - if (r < 0) { - log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to set X11 keyboard layout: %m"); log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", strempty(c->x11_layout), @@ -679,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) @@ -754,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; @@ -790,7 +820,7 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { if (modified) { r = vconsole_write_data(c); if (r < 0) - log_error("Failed to set virtual console keymap: %s", strerror(-r)); + log_error_errno(r, "Failed to set virtual console keymap: %m"); log_info("Changed virtual console keymap to '%s' toggle '%s'", strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); @@ -843,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; @@ -869,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; @@ -882,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; } @@ -893,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) @@ -913,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); @@ -923,7 +985,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ r = locale_write_data(c, &settings); if (r < 0) { - log_error("Failed to set locale: %s", strerror(-r)); + log_error_errno(r, "Failed to set locale: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r)); } @@ -967,11 +1029,18 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata if (!streq_ptr(keymap, c->vc_keymap) || !streq_ptr(keymap_toggle, c->vc_keymap_toggle)) { - if ((keymap && (!filename_is_safe(keymap) || !string_is_safe(keymap))) || - (keymap_toggle && (!filename_is_safe(keymap_toggle) || !string_is_safe(keymap_toggle)))) + if ((keymap && (!filename_is_valid(keymap) || !string_is_safe(keymap))) || + (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) @@ -983,7 +1052,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata r = vconsole_write_data(c); if (r < 0) { - log_error("Failed to set virtual console keymap: %s", strerror(-r)); + log_error_errno(r, "Failed to set virtual console keymap: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r)); } @@ -992,7 +1061,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata r = vconsole_reload(bus); if (r < 0) - log_error("Failed to request keymap reload: %s", strerror(-r)); + log_error_errno(r, "Failed to request keymap reload: %m"); sd_bus_emit_properties_changed(bus, "/org/freedesktop/locale1", @@ -1002,7 +1071,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata if (convert) { r = vconsole_convert_to_x11(c, bus); if (r < 0) - log_error("Failed to convert keymap data: %s", strerror(-r)); + log_error_errno(r, "Failed to convert keymap data: %m"); } } @@ -1011,7 +1080,10 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata #ifdef HAVE_XKBCOMMON static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) { - /* suppress xkb messages for now */ + const char *fmt; + + fmt = strjoina("libxkbcommon: ", format); + log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args); } static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { @@ -1087,17 +1159,26 @@ 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 = verify_xkb_rmlvo(model, layout, variant, options); - if (r < 0) - log_warning("Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %s", - strempty(model), strempty(layout), strempty(variant), strempty(options), strerror(-r)); - - 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) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + r = verify_xkb_rmlvo(model, layout, variant, options); + if (r < 0) { + log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m", + strempty(model), strempty(layout), strempty(variant), strempty(options)); + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing"); + } + if (free_and_strdup(&c->x11_layout, layout) < 0 || free_and_strdup(&c->x11_model, model) < 0 || free_and_strdup(&c->x11_variant, variant) < 0 || @@ -1106,7 +1187,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat r = x11_write_data(c); if (r < 0) { - log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + log_error_errno(r, "Failed to set X11 keyboard layout: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r)); } @@ -1124,7 +1205,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat if (convert) { r = x11_convert_to_vconsole(c, bus); if (r < 0) - log_error("Failed to convert keymap data: %s", strerror(-r)); + log_error_errno(r, "Failed to convert keymap data: %m"); } } @@ -1155,28 +1236,20 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { assert(_bus); r = sd_bus_default_system(&bus); - if (r < 0) { - log_error("Failed to get system bus connection: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get system bus connection: %m"); r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c); - if (r < 0) { - log_error("Failed to register object: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to register object: %m"); r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0); - if (r < 0) { - log_error("Failed to register name: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to register name: %m"); r = sd_bus_attach_event(bus, event, 0); - if (r < 0) { - log_error("Failed to attach bus to event loop: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to attach bus to event loop: %m"); *_bus = bus; bus = NULL; @@ -1205,7 +1278,7 @@ int main(int argc, char *argv[]) { r = sd_event_default(&event); if (r < 0) { - log_error("Failed to allocate event loop: %s", strerror(-r)); + log_error_errno(r, "Failed to allocate event loop: %m"); goto finish; } @@ -1217,13 +1290,13 @@ int main(int argc, char *argv[]) { r = context_read_data(&context); if (r < 0) { - log_error("Failed to read locale data: %s", strerror(-r)); + log_error_errno(r, "Failed to read locale data: %m"); goto finish; } r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL); if (r < 0) { - log_error("Failed to run event loop: %s", strerror(-r)); + log_error_errno(r, "Failed to run event loop: %m"); goto finish; }