From: Zbigniew Jędrzejewski-Szmek Date: Mon, 18 Nov 2013 18:42:57 +0000 (-0500) Subject: localed: match converted keymaps before legacy X-Git-Tag: v209~1403 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=0732ef7acf37473847992888bcb6446726d9d877 localed: match converted keymaps before legacy Before, X11 keymap fr-pc105-oss would be converted to fr, even though fr-oss exists. Now, if /usr/lib/kbd/keymaps/xkb/[-].map[.gz] exists, [-] will be used as the console keymap, falling back to the legacy mappings otherwise. % sudo localectl set-x11-keymap pl pc105 % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: pl (was pl2 before) X11 Layout: pl X11 Model: pc105 % sudo localectl set-x11-keymap fr pc105 oss % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: fr-oss (was fr before) X11 Layout: fr X11 Model: pc105 X11 Variant: oss % sudo localectl set-x11-keymap fr pc105 % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: fr X11 Layout: fr X11 Model: pc105 % sudo localectl set-x11-keymap gb % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: gb (was uk before) X11 Layout: gb --- diff --git a/src/locale/localectl.c b/src/locale/localectl.c index f7fea48ff..76a53f6ff 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -42,6 +42,7 @@ #include "set.h" #include "path-util.h" #include "utf8.h" +#include "def.h" static bool arg_no_pager = false; static bool arg_ask_password = true; @@ -437,15 +438,14 @@ static int nftw_cb( static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { _cleanup_strv_free_ char **l = NULL; + const char *dir; keymaps = set_new(string_hash_func, string_compare_func); if (!keymaps) return log_oom(); - nftw("/usr/share/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS); - nftw("/usr/share/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS); - nftw("/usr/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS); - nftw("/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS); + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) + nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS); l = set_get_strv(keymaps); if (!l) { diff --git a/src/locale/localed.c b/src/locale/localed.c index 5275ef3e5..1248f20c9 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -633,8 +633,114 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { return 0; } +static int find_converted_keymap(Context *c, char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + + if (c->x11_variant) + n = strjoin(c->x11_layout, "-", c->x11_variant, NULL); + else + n = strdup(c->x11_layout); + if (!n) + return -ENOMEM; + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; + + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; + + if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) { + *new_keymap = n; + n = NULL; + return 1; + } + } + + return 0; +} + +static int find_legacy_keymap(Context *c, char **new_keymap) { + _cleanup_fclose_ FILE *f; + unsigned n = 0; + unsigned best_matching = 0; + + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; + int r; + + r = read_next_mapping(f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + /* Determine how well matching this entry is */ + if (streq_ptr(c->x11_layout, a[1])) + /* If we got an exact match, this is best */ + matching = 10; + else { + size_t x; + + x = strcspn(c->x11_layout, ","); + + /* We have multiple X layouts, look for an + * entry that matches our key with everything + * but the first layout stripped off. */ + if (x > 0 && + strlen(a[1]) == x && + strneq(c->x11_layout, a[1], x)) + matching = 5; + else { + size_t w; + + /* If that didn't work, strip off the + * other layouts from the entry, too */ + w = strcspn(a[1], ","); + + if (x > 0 && x == w && + memcmp(c->x11_layout, a[1], x) == 0) + matching = 1; + } + } + + if (matching > 0 && + streq_ptr(c->x11_model, a[2])) { + matching++; + + if (streq_ptr(c->x11_variant, a[3])) { + matching++; + + if (streq_ptr(c->x11_options, a[4])) + matching++; + } + } + + /* The best matching entry so far, then let's save that */ + if (matching > best_matching) { + best_matching = matching; + + free(*new_keymap); + *new_keymap = strdup(a[0]); + if (!*new_keymap) + return -ENOMEM; + } + } + + return 0; +} + static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { bool modified = false; + int r; assert(bus); @@ -646,79 +752,15 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { context_free_x11(c); } else { - _cleanup_fclose_ FILE *f; - unsigned n = 0; - unsigned best_matching = 0; char *new_keymap = NULL; - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - _cleanup_strv_free_ char **a = NULL; - unsigned matching = 0; - int r; - - r = read_next_mapping(f, &n, &a); + r = find_converted_keymap(c, &new_keymap); + if (r < 0) + return r; + else if (r == 0) { + r = find_legacy_keymap(c, &new_keymap); if (r < 0) return r; - if (r == 0) - break; - - /* Determine how well matching this entry is */ - if (streq_ptr(c->x11_layout, a[1])) - /* If we got an exact match, this is best */ - matching = 10; - else { - size_t x; - - x = strcspn(c->x11_layout, ","); - - /* We have multiple X layouts, look - * for an entry that matches our key - * with the everything but the first - * layout stripped off. */ - if (x > 0 && - strlen(a[1]) == x && - strneq(c->x11_layout, a[1], x)) - matching = 5; - else { - size_t w; - - /* If that didn't work, strip - * off the other layouts from - * the entry, too */ - w = strcspn(a[1], ","); - - if (x > 0 && x == w && - memcmp(c->x11_layout, a[1], x) == 0) - matching = 1; - } - } - - if (matching > 0 && - streq_ptr(c->x11_model, a[2])) { - matching++; - - if (streq_ptr(c->x11_variant, a[3])) { - matching++; - - if (streq_ptr(c->x11_options, a[4])) - matching++; - } - } - - /* The best matching entry so far, then let's - * save that */ - if (matching > best_matching) { - best_matching = matching; - - free(new_keymap); - new_keymap = strdup(a[0]); - if (!new_keymap) - return -ENOMEM; - } } if (!streq_ptr(c->vc_keymap, new_keymap)) { @@ -730,8 +772,6 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { } if (modified) { - int r; - r = vconsole_write_data(c); if (r < 0) log_error("Failed to set virtual console keymap: %s", strerror(-r)); diff --git a/src/shared/def.h b/src/shared/def.h index d7e077a57..825db9507 100644 --- a/src/shared/def.h +++ b/src/shared/def.h @@ -43,3 +43,16 @@ #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS #define REBOOT_PARAM_FILE "/run/systemd/reboot-param" + +#ifdef HAVE_SPLIT_USR +#define KBD_KEYMAP_DIRS \ + "/usr/share/keymaps/\0" \ + "/usr/share/kbd/keymaps/\0" \ + "/usr/lib/kbd/keymaps/\0" \ + "/lib/kbd/keymaps/\0" +#else +#define KBD_KEYMAP_DIRS \ + "/usr/share/keymaps/\0" \ + "/usr/share/kbd/keymaps/\0" \ + "/usr/lib/kbd/keymaps/\0" +#endif