[systemd-devel] [PATCH 2/2] localectl: verify layout, model, variant and options

Jan Synacek jsynacek at redhat.com
Mon Oct 20 03:43:40 PDT 2014


When setting any of those using set-x11-keymap, check that their values
are available on the system.
---
 src/locale/localectl.c | 208 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 139 insertions(+), 69 deletions(-)

diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 3690f9f..0caf467 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -53,6 +53,14 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
 static char *arg_host = NULL;
 static bool arg_convert = true;
 
+enum keymap_state {
+        NONE,
+        MODELS   = 1 << 0,
+        LAYOUTS  = 1 << 1,
+        VARIANTS = 1 << 2,
+        OPTIONS  = 1 << 3
+};
+
 static void pager_open_if_enabled(void) {
 
         if (arg_no_pager)
@@ -350,59 +358,12 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
         return 0;
 }
 
-static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *layout, *model, *variant, *options;
-        int r;
-
-        assert(bus);
-        assert(args);
-
-        if (n > 5) {
-                log_error("Too many arguments.");
-                return -EINVAL;
-        }
-
-        polkit_agent_open_if_enabled();
-
-        layout = args[1];
-        model = n > 2 ? args[2] : "";
-        variant = n > 3 ? args[3] : "";
-        options = n > 4 ? args[4] : "";
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.locale1",
-                        "/org/freedesktop/locale1",
-                        "org.freedesktop.locale1",
-                        "SetX11Keyboard",
-                        &error,
-                        NULL,
-                        "ssssbb", layout, model, variant, options,
-                                  arg_convert, arg_ask_password);
-        if (r < 0)
-                log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
-
-        return r;
-}
-
-static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
+static int get_x11_keymaps_internal(char ***list, enum keymap_state look_for, const char *layout)
+{
         _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_strv_free_ char **list = NULL;
         char line[LINE_MAX];
-        enum {
-                NONE,
-                MODELS,
-                LAYOUTS,
-                VARIANTS,
-                OPTIONS
-        } state = NONE, look_for;
-        int r;
-
-        if (n > 2) {
-                log_error("Too many arguments.");
-                return -EINVAL;
-        }
+        enum keymap_state state = NONE;
+        int r = 0;
 
         f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
         if (!f) {
@@ -410,17 +371,6 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
                 return -errno;
         }
 
-        if (streq(args[0], "list-x11-keymap-models"))
-                look_for = MODELS;
-        else if (streq(args[0], "list-x11-keymap-layouts"))
-                look_for = LAYOUTS;
-        else if (streq(args[0], "list-x11-keymap-variants"))
-                look_for = VARIANTS;
-        else if (streq(args[0], "list-x11-keymap-options"))
-                look_for = OPTIONS;
-        else
-                assert_not_reached("Wrong parameter");
-
         FOREACH_LINE(line, f, break) {
                 char *l, *w;
 
@@ -444,12 +394,12 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
                         continue;
                 }
 
-                if (state != look_for)
+                if (!(state & look_for))
                         continue;
 
                 w = l + strcspn(l, WHITESPACE);
 
-                if (n > 1) {
+                if (layout) {
                         char *e;
 
                         if (*w == 0)
@@ -465,23 +415,143 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
 
                         *e = 0;
 
-                        if (!streq(w, args[1]))
+                        if (!streq(w, layout))
                                 continue;
                 } else
                         *w = 0;
 
-                 r = strv_extend(&list, l);
+                 r = strv_extend(list, l);
                  if (r < 0)
                          return log_oom();
         }
 
-        if (strv_isempty(list)) {
+        if (strv_isempty(*list)) {
                 log_error("Couldn't find any entries.");
                 return -ENOENT;
         }
 
-        strv_sort(list);
-        strv_uniq(list);
+        strv_sort(*list);
+        strv_uniq(*list);
+
+        return r;
+}
+
+static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_strv_free_ char **list = NULL, **layouts = NULL, **variants = NULL, **options = NULL;
+        char **it;
+        const char *layouts_arg, *variants_arg, *options_arg;
+        const char *model;
+        enum keymap_state look_for;
+        int r;
+
+        assert(bus);
+        assert(args);
+
+        if (n > 5) {
+                log_error("Too many arguments.");
+                return -EINVAL;
+        }
+
+        polkit_agent_open_if_enabled();
+
+        layouts_arg = args[1];
+        model = n > 2 ? args[2] : "";
+        variants_arg = n > 3 ? args[3] : "";
+        options_arg = n > 4 ? args[4] : "";
+
+        look_for = LAYOUTS;
+        layouts = strv_split(layouts_arg, ",");
+        if (!layouts)
+                return log_oom();
+
+        if (!streq(variants_arg, "")) {
+                look_for |= VARIANTS;
+                variants = strv_split(variants_arg, ",");
+                if (!variants)
+                        return log_oom();
+        }
+
+        if (!streq(options_arg, "")) {
+                look_for |= OPTIONS;
+                options = strv_split(options_arg, ",");
+                if (!options)
+                        return log_oom();
+        }
+
+        look_for |= !streq(model, "") * MODELS;
+
+        r = get_x11_keymaps_internal(&list, look_for, NULL);
+
+        STRV_FOREACH(it, layouts)
+                if (!strv_find(list, *it)) {
+                        fprintf(stderr, "Requested layout '%s' not available.\n", *it);
+                        return -EINVAL;
+                }
+
+
+        if (variants)
+                STRV_FOREACH(it, variants)
+                        if ((look_for & VARIANTS) && !strv_find(list, *it)) {
+                                fprintf(stderr, "Requested variant '%s' not available.\n", *it);
+                                return -EINVAL;
+                        }
+
+        if (options)
+                STRV_FOREACH(it, options)
+                        if ((look_for & OPTIONS) && !strv_find(list, *it)) {
+                                fprintf(stderr, "Requested options '%s' not available.\n", *it);
+                                return -EINVAL;
+                        }
+
+        if ((look_for & MODELS) && !strv_find(list, model)) {
+                fprintf(stderr, "Requested model '%s' not available.\n", model);
+                return -EINVAL;
+        }
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.locale1",
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "SetX11Keyboard",
+                        &error,
+                        NULL,
+                        "ssssbb", layouts_arg, model, variants_arg, options_arg,
+                                  arg_convert, arg_ask_password);
+        if (r < 0)
+                log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
+
+        return r;
+}
+
+
+static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
+        _cleanup_strv_free_ char **list = NULL;
+        const char *layout;
+        enum keymap_state look_for;
+        int r;
+
+        if (n > 2) {
+                log_error("Too many arguments.");
+                return -EINVAL;
+        }
+
+        if (streq(args[0], "list-x11-keymap-models"))
+                look_for = MODELS;
+        else if (streq(args[0], "list-x11-keymap-layouts"))
+                look_for = LAYOUTS;
+        else if (streq(args[0], "list-x11-keymap-variants"))
+                look_for = VARIANTS;
+        else if (streq(args[0], "list-x11-keymap-options"))
+                look_for = OPTIONS;
+        else
+                assert_not_reached("Wrong parameter");
+
+        layout = (n == 2) ? args[1] : NULL;
+        r = get_x11_keymaps_internal(&list, look_for, layout);
+        if (r < 0)
+                return r;
 
         pager_open_if_enabled();
 
-- 
1.9.3



More information about the systemd-devel mailing list