X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flocale%2Flocaled.c;h=8d60d0ff133755478e4ed447b6709842e5210f35;hb=652212b0c2b60b9ef9b2e24eae82401f880fa21a;hp=f3e1589a45994159eac47f35942615ee4c359c39;hpb=81fd105a5f9762fa2f2e42bc949876e32b3a126f;p=elogind.git diff --git a/src/locale/localed.c b/src/locale/localed.c index f3e1589a4..8d60d0ff1 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -41,6 +41,10 @@ #include "event-util.h" #include "locale-util.h" +#ifdef HAVE_XKBCOMMON +#include +#endif + enum { /* We don't list LC_ALL here on purpose. People should be * using LANG instead. */ @@ -224,7 +228,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); + r = strv_split_quoted(&a, l, false); if (r < 0) return r; @@ -247,7 +251,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); + r = strv_split_quoted(&a, l, false); if (r < 0) return -ENOMEM; @@ -371,7 +375,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; } @@ -430,7 +434,7 @@ static int vconsole_write_data(Context *c) { return write_env_file_label("/etc/vconsole.conf", l); } -static int write_data_x11(Context *c) { +static int x11_write_data(Context *c) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *temp_path = NULL; int r; @@ -533,7 +537,7 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) { if (l[0] == 0 || l[0] == '#') continue; - r = strv_split_quoted(&b, l); + r = strv_split_quoted(&b, l, false); if (r < 0) return r; @@ -605,9 +609,9 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { if (modified) { int r; - r = write_data_x11(c); + r = x11_write_data(c); if (r < 0) - log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + 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), @@ -625,14 +629,14 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { return 0; } -static int find_converted_keymap(Context *c, char **new_keymap) { +static int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { const char *dir; _cleanup_free_ char *n; - if (c->x11_variant) - n = strjoin(c->x11_layout, "-", c->x11_variant, NULL); + if (x11_variant) + n = strjoin(x11_layout, "-", x11_variant, NULL); else - n = strdup(c->x11_layout); + n = strdup(x11_layout); if (!n) return -ENOMEM; @@ -663,7 +667,7 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { _cleanup_fclose_ FILE *f; unsigned n = 0; unsigned best_matching = 0; - + int r; f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); if (!f) @@ -672,7 +676,6 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { for (;;) { _cleanup_strv_free_ char **a = NULL; unsigned matching = 0; - int r; r = read_next_mapping(f, &n, &a); if (r < 0) @@ -729,6 +732,23 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { } } + if (best_matching < 10 && c->x11_layout) { + /* The best match is only the first part of the X11 + * keymap. Check if we have a converted map which + * matches just the first layout. + */ + char *l, *v = NULL, *converted; + + l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); + if (c->x11_variant) + v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); + r = find_converted_keymap(l, v, &converted); + if (r < 0) + return r; + if (r > 0) + free_and_replace(new_keymap, converted); + } + return 0; } @@ -748,7 +768,7 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { } else { char *new_keymap = NULL; - r = find_converted_keymap(c, &new_keymap); + r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); if (r < 0) return r; else if (r == 0) { @@ -768,7 +788,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)); @@ -901,7 +921,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)); } @@ -961,7 +981,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)); } @@ -970,7 +990,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", @@ -980,13 +1000,61 @@ 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"); } } return sd_bus_reply_method_return(m, NULL); } +#ifdef HAVE_XKBCOMMON +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); + 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) { + const struct xkb_rule_names rmlvo = { + .model = model, + .layout = layout, + .variant = variant, + .options = options, + }; + struct xkb_context *ctx = NULL; + struct xkb_keymap *km = NULL; + int r; + + /* compile keymap from RMLVO information to check out its validity */ + + ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + if (!ctx) { + r = -ENOMEM; + goto exit; + } + + xkb_context_set_log_fn(ctx, log_xkb); + + km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!km) { + r = -EINVAL; + goto exit; + } + + r = 0; + +exit: + xkb_keymap_unref(km); + xkb_context_unref(ctx); + return r; +} +#else +static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { + return 0; +} +#endif + static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; const char *layout, *model, *variant, *options; @@ -1026,15 +1094,22 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat 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 || free_and_strdup(&c->x11_options, options) < 0) return -ENOMEM; - r = write_data_x11(c); + 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)); } @@ -1052,7 +1127,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"); } } @@ -1083,28 +1158,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; @@ -1123,7 +1190,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - label_init("/etc"); + mac_selinux_init("/etc"); if (argc != 1) { log_error("This program takes no arguments."); @@ -1133,7 +1200,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; } @@ -1145,13 +1212,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; }