Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-12-01 Thread Lennart Poettering
On Mon, 24.11.14 15:21, David Herrmann (dh.herrm...@gmail.com) wrote:

 I now pushed something to -git, see:
 
 commit d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62
 Author: David Herrmann dh.herrm...@gmail.com
 Date:   Mon Nov 24 15:12:42 2014 +0100
 
 localed: validate xkb keymaps
 
 I think duplicating the xkb-parsers is something we should avoid. Ran
 Benita was even working on a v2 format to drop all the legacy bits
 no-one uses in the old, crufty xkb format. I dislike having a fixed
 parser in systemd. Sure, our --list-layouts option needs to do this,
 but maybe we can drop that some day, too.
 
 I pushed a fix to test-compile keymaps on set-x11-keymap calls. So
 far, I only print a warning if it fails. Please feel free to post
 patches to extend this. For instance, I think we might want to do that
 in localectl (maybe even forward the xkb-logs then) and fail hard if
 the compilation fails (even though I dislike --force options..).

Wouldn't it make sense to refuse keymaps we cannot compile from the
localed side? I kinda prefer doing the validity checks on the server
side. Doing enumeration (which is primarily relevant fo cmdline
completion) on the client side is OK, but validity checking should
really be done on the server side.

I think it would be great if we'd generate a simply nice error message
if the compile test failed (just some error Keyboard map could not be
compiled, refusing. or so).

Lennart

-- 
Lennart Poettering, Red Hat
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-12-01 Thread Lennart Poettering
On Mon, 24.11.14 13:31, Jan Synacek (jsyna...@redhat.com) wrote:

 Lennart Poettering lenn...@poettering.net writes:
  On Fri, 14.11.14 12:42, Jan Synacek (jsyna...@redhat.com) wrote:
  +if (look_for == LAYOUTS) {
  +Set *s;
  +char *k;
  +Iterator i;
  +/* XXX: Is there a better way to sort Hashmap keys? */
  +_cleanup_strv_free_ char **tmp = NULL;
  +
  +HASHMAP_FOREACH_KEY(s, k, keymap-x11_layouts, i)
  +if (strv_extend(tmp, k)  0)
  +(void) log_oom();
 
  There's hashmap_get_strv() for cases like this.
 
 I need keys, not values. I didn't find any hashmap_get_strv() equivalent
 for keys.

Maybe add it then? I think this might become useful even beyond the
kbd mapping part one day.

  Also, please neer invoke strv_extend() when appending to unbounded
  arrays. It's slow! 
 
 What is a preffered way to extend a strv? In this case, I know the final
 size, so it the array could manually be copied. I don't think that
 that's very nice, though.

Best case: you know the precise size of the array in the end. In that
case, simply use realloc()/realloc_multiply() to allocate the right
sized array, fill it in, done.

If you don#t know the size, but you guess that it might be quite a few
entries in there in the end and you might be adding a good chunk of
them, please use greedy_realloc(). It grows the array exponentially,
which is very beneficial performance-wise.

If you don't know the size, but you are pretty sure that it will never
gro to more than 10 entries or so, and that you are just going to
add a couple of them, then strv_extend()/strv_push()/strv_consume()
are OK.

  Humm, when clearing up hashmaps please just write a loop that steals
  the first entry, free it and then repeat. Iterating through a hashmap
  while deleting its entries is unnecessary...
 
 I need to free its entries *and* keys. I didn't find any function that I
 could use for that, apart from hashmap_free_free(), which crashes in
 my case.

while ((k = hashmap_first_key())) {
  v = hashmap_steal_first();
  free(v);
  free(k);
}

Lennart

-- 
Lennart Poettering, Red Hat
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-24 Thread Jan Synacek
Lennart Poettering lenn...@poettering.net writes:
 On Fri, 14.11.14 12:42, Jan Synacek (jsyna...@redhat.com) wrote:
 +if (look_for == LAYOUTS) {
 +Set *s;
 +char *k;
 +Iterator i;
 +/* XXX: Is there a better way to sort Hashmap keys? */
 +_cleanup_strv_free_ char **tmp = NULL;
 +
 +HASHMAP_FOREACH_KEY(s, k, keymap-x11_layouts, i)
 +if (strv_extend(tmp, k)  0)
 +(void) log_oom();

 There's hashmap_get_strv() for cases like this.

I need keys, not values. I didn't find any hashmap_get_strv() equivalent
for keys.


 Also, please neer invoke strv_extend() when appending to unbounded
 arrays. It's slow! 

What is a preffered way to extend a strv? In this case, I know the final
size, so it the array could manually be copied. I don't think that
that's very nice, though.

 +void xkb_keymap_free_components(X11Keymap *keymap) {
 +if (keymap-x11_layouts) {
 +Set *s;
 +char *k;
 +Iterator i;
 +
 +HASHMAP_FOREACH_KEY(s, k, keymap-x11_layouts, i) {
 +free(k);
 +set_free_free(s);
 +}

 Humm, when clearing up hashmaps please just write a loop that steals
 the first entry, free it and then repeat. Iterating through a hashmap
 while deleting its entries is unnecessary...

I need to free its entries *and* keys. I didn't find any function that I
could use for that, apart from hashmap_free_free(), which crashes in my case.

 Lennart

 -- 
 Lennart Poettering, Red Hat

Cheers,
-- 
Jan Synacek
Software Engineer, Red Hat


signature.asc
Description: PGP signature
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-24 Thread David Herrmann
Hi

On Wed, Nov 19, 2014 at 9:41 AM, Jan Synacek jsyna...@redhat.com wrote:
 David Herrmann dh.herrm...@gmail.com writes:
 Hi

 On Fri, Nov 14, 2014 at 12:42 PM, Jan Synacek jsyna...@redhat.com wrote:
 Try to validate the input similarly to how setxkbmap does it. Multiple
 layouts and variants can be specified, separated by a comma. Variants
 can also be left out, meaning that the user doesn't want any particular
 variant for the respective layout.

 Variants are validated respectively to their layouts. First variant
 validates against first layout, second variant to second layout, etc. If
 there are more entries of either layouts or variants, only their
 respective counterparts are validated, the rest is ignored.

 Examples:
 $ set-x11-keymap us,cz  pc105 ,qwerty
 us is not validated, because no respective variant was specified. cz
 is checked for an existing qwerty variant, the check succeeds.

 $ set-x11-keymap us pc105 ,qwerty
 us is not validated as in the above example. The rest of the variants
 is ignored, because there are no respective layouts.

 $ set-x11-keymap us,cz pc105 qwerty
 us is validated against the qwerty variant, check fails, because
 there is no qwerty variant for the us layout.

 $ set-x11-keymap us,cz pc105 euro,qwerty
 Validation succeeds, there is the euro variant for the us layout,
 and qwerty variant for the cz layout.

 http://lists.freedesktop.org/archives/systemd-devel/2014-October/024411.html

 I didn't follow the discussion on v1, but why don't we use
 libxkbcommon to compile the keymap? If it doesn't compile, print an
 error (or warning and maybe optionally still proceed?).

 Sure, this would add a dependency to libxkbcommon for localed, but we
 could make it optional. And libxkbcommon has no dependencies by
 itself. Furthermore, set-x11-keymap is pretty useless without
 libxkbcommon installed, anyway.

 It'd be a ~10 line patch to use
 xkb_context_new()+xkb_keymap_from_rmlvo(). And it would be guaranteed
 to have the same semantics as the real keymap compilation.

 Thanks
 David

 For some reason, I was under the impression that depending on
 libxkbcommon would mean depending on plenty of X libraries... Using the
 library and making the dependency on it optional sounds like the best
 solution to me.

 Waiting for more opinions.

I now pushed something to -git, see:

commit d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62
Author: David Herrmann dh.herrm...@gmail.com
Date:   Mon Nov 24 15:12:42 2014 +0100

localed: validate xkb keymaps

I think duplicating the xkb-parsers is something we should avoid. Ran
Benita was even working on a v2 format to drop all the legacy bits
no-one uses in the old, crufty xkb format. I dislike having a fixed
parser in systemd. Sure, our --list-layouts option needs to do this,
but maybe we can drop that some day, too.

I pushed a fix to test-compile keymaps on set-x11-keymap calls. So
far, I only print a warning if it fails. Please feel free to post
patches to extend this. For instance, I think we might want to do that
in localectl (maybe even forward the xkb-logs then) and fail hard if
the compilation fails (even though I dislike --force options..).

I hope my commit is something to base further work on. I tried keeping
it as non-intrusive as possible.

Thanks
David
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-19 Thread Jan Synacek
David Herrmann dh.herrm...@gmail.com writes:
 Hi

 On Fri, Nov 14, 2014 at 12:42 PM, Jan Synacek jsyna...@redhat.com wrote:
 Try to validate the input similarly to how setxkbmap does it. Multiple
 layouts and variants can be specified, separated by a comma. Variants
 can also be left out, meaning that the user doesn't want any particular
 variant for the respective layout.

 Variants are validated respectively to their layouts. First variant
 validates against first layout, second variant to second layout, etc. If
 there are more entries of either layouts or variants, only their
 respective counterparts are validated, the rest is ignored.

 Examples:
 $ set-x11-keymap us,cz  pc105 ,qwerty
 us is not validated, because no respective variant was specified. cz
 is checked for an existing qwerty variant, the check succeeds.

 $ set-x11-keymap us pc105 ,qwerty
 us is not validated as in the above example. The rest of the variants
 is ignored, because there are no respective layouts.

 $ set-x11-keymap us,cz pc105 qwerty
 us is validated against the qwerty variant, check fails, because
 there is no qwerty variant for the us layout.

 $ set-x11-keymap us,cz pc105 euro,qwerty
 Validation succeeds, there is the euro variant for the us layout,
 and qwerty variant for the cz layout.

 http://lists.freedesktop.org/archives/systemd-devel/2014-October/024411.html

 I didn't follow the discussion on v1, but why don't we use
 libxkbcommon to compile the keymap? If it doesn't compile, print an
 error (or warning and maybe optionally still proceed?).

 Sure, this would add a dependency to libxkbcommon for localed, but we
 could make it optional. And libxkbcommon has no dependencies by
 itself. Furthermore, set-x11-keymap is pretty useless without
 libxkbcommon installed, anyway.

 It'd be a ~10 line patch to use
 xkb_context_new()+xkb_keymap_from_rmlvo(). And it would be guaranteed
 to have the same semantics as the real keymap compilation.

 Thanks
 David

For some reason, I was under the impression that depending on
libxkbcommon would mean depending on plenty of X libraries... Using the
library and making the dependency on it optional sounds like the best
solution to me.

Waiting for more opinions.

Cheers,
-- 
Jan Synacek
Software Engineer, Red Hat


signature.asc
Description: PGP signature
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-14 Thread Jan Synacek
Try to validate the input similarly to how setxkbmap does it. Multiple
layouts and variants can be specified, separated by a comma. Variants
can also be left out, meaning that the user doesn't want any particular
variant for the respective layout.

Variants are validated respectively to their layouts. First variant
validates against first layout, second variant to second layout, etc. If
there are more entries of either layouts or variants, only their
respective counterparts are validated, the rest is ignored.

Examples:
$ set-x11-keymap us,cz  pc105 ,qwerty
us is not validated, because no respective variant was specified. cz
is checked for an existing qwerty variant, the check succeeds.

$ set-x11-keymap us pc105 ,qwerty
us is not validated as in the above example. The rest of the variants
is ignored, because there are no respective layouts.

$ set-x11-keymap us,cz pc105 qwerty
us is validated against the qwerty variant, check fails, because
there is no qwerty variant for the us layout.

$ set-x11-keymap us,cz pc105 euro,qwerty
Validation succeeds, there is the euro variant for the us layout,
and qwerty variant for the cz layout.

http://lists.freedesktop.org/archives/systemd-devel/2014-October/024411.html
---
v2:
- rewrite to use the X11Keymap struct
- use greedy allocation where it makes sense
- rename enum keymap_state to KeymapComponent
- on the server side, propagate error to the client and don't log it
- on the server side, change SD_BUS_ERROR_FAILED to SD_BUS_ERROR_INVALID_ARGS

 Makefile.am|   2 +
 src/locale/localectl.c |  85 ++---
 src/locale/localed.c   |   6 +
 src/shared/xkb-util.c  | 319 +
 src/shared/xkb-util.h  |  50 
 5 files changed, 385 insertions(+), 77 deletions(-)
 create mode 100644 src/shared/xkb-util.c
 create mode 100644 src/shared/xkb-util.h

diff --git a/Makefile.am b/Makefile.am
index 701666c..224582c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -772,6 +772,8 @@ libsystemd_shared_la_SOURCES = \
src/shared/time-util.h \
src/shared/locale-util.c \
src/shared/locale-util.h \
+   src/shared/xkb-util.c \
+   src/shared/xkb-util.h \
src/shared/mempool.c \
src/shared/mempool.h \
src/shared/hashmap.c \
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index d4a2d29..08a1011 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -46,6 +46,7 @@
 #include virt.h
 #include fileio.h
 #include locale-util.h
+#include xkb-util.h
 
 static bool arg_no_pager = false;
 static bool arg_ask_password = true;
@@ -388,15 +389,8 @@ static int set_x11_keymap(sd_bus *bus, char **args, 
unsigned n) {
 
 static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
 _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;
+_cleanup_(xkb_keymap_free_components) X11Keymap keymap = {};
+enum KeymapComponent look_for;
 int r;
 
 if (n  2) {
@@ -404,12 +398,6 @@ static int list_x11_keymaps(sd_bus *bus, char **args, 
unsigned n) {
 return -EINVAL;
 }
 
-f = fopen(/usr/share/X11/xkb/rules/base.lst, re);
-if (!f) {
-log_error(Failed to open keyboard mapping list. %m);
-return -errno;
-}
-
 if (streq(args[0], list-x11-keymap-models))
 look_for = MODELS;
 else if (streq(args[0], list-x11-keymap-layouts))
@@ -421,71 +409,14 @@ static int list_x11_keymaps(sd_bus *bus, char **args, 
unsigned n) {
 else
 assert_not_reached(Wrong parameter);
 
-FOREACH_LINE(line, f, break) {
-char *l, *w;
-
-l = strstrip(line);
-
-if (isempty(l))
-continue;
-
-if (l[0] == '!') {
-if (startswith(l, ! model))
-state = MODELS;
-else if (startswith(l, ! layout))
-state = LAYOUTS;
-else if (startswith(l, ! variant))
-state = VARIANTS;
-else if (startswith(l, ! option))
-state = OPTIONS;
-else
-state = NONE;
-
-continue;
-}
-
-if (state != look_for)
-continue;
-
-w = l + strcspn(l, WHITESPACE);
-
-if (n  1) {
-char *e;
-
-if (*w == 0)
-continue;
-
-*w = 0;
-w++;
-   

Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-14 Thread Susant Sahani

On 11/14/2014 05:12 PM, Jan Synacek wrote:

+int xkb_validate_keymaps(const char *model,
+ const char *layouts_arg,
+ const char *variants_arg,
+ const char *options_arg,
+ char **error)
+{


'{' should start next to ')' on the same line


Susant
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-14 Thread Susant Sahani


On 11/14/2014 05:12 PM, Jan Synacek wrote:

+int xkb_keymap_get_components(X11Keymap *keymap) {
+_cleanup_strv_free_ char **models = NULL, **options = NULL;
+_cleanup_fclose_ FILE *f;
+char line[LINE_MAX];
+enum KeymapComponent state = NONE;
+size_t m = 0, o = 0, allocm = 0, alloco = 0;
+
+Hashmap *x11_layouts;
+int r;
+
+x11_layouts = hashmap_new(string_hash_ops);
+if (!x11_layouts)
+return log_oom();
+
+f = fopen(/usr/share/X11/xkb/rules/base.lst, re);
+if (!f) {
+log_error(Failed to open keyboard mapping list. %m);


 isn't x11_layouts leaking memory here ? should not we free this

+return -errno;
+}
+
+FOREACH_LINE(line, f, break) {
+char *l, *w;
+_cleanup_free_ char *layout = NULL;
+
+l = strstrip(line);
+
+if (isempty(l))
+continue;


Susant
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-14 Thread Lennart Poettering
On Fri, 14.11.14 12:42, Jan Synacek (jsyna...@redhat.com) wrote:

 
 diff --git a/Makefile.am b/Makefile.am
 index 701666c..224582c 100644
 --- a/Makefile.am
 +++ b/Makefile.am
 @@ -772,6 +772,8 @@ libsystemd_shared_la_SOURCES = \
   src/shared/time-util.h \
   src/shared/locale-util.c \
   src/shared/locale-util.h \
 + src/shared/xkb-util.c \
 + src/shared/xkb-util.h \
   src/shared/mempool.c \
   src/shared/mempool.h \
   src/shared/hashmap.c \
 diff --git a/src/locale/localectl.c b/src/locale/localectl.c
 index d4a2d29..08a1011 100644
 --- a/src/locale/localectl.c
 +++ b/src/locale/localectl.c
 @@ -46,6 +46,7 @@
  #include virt.h
  #include fileio.h
  #include locale-util.h
 +#include xkb-util.h
  
  static bool arg_no_pager = false;
  static bool arg_ask_password = true;
 @@ -388,15 +389,8 @@ static int set_x11_keymap(sd_bus *bus, char **args, 
 unsigned n) {
  
  static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
  _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;
 +_cleanup_(xkb_keymap_free_components) X11Keymap keymap = {};
 +enum KeymapComponent look_for;
  int r;

As mentioned earlier, we usually use typedef enum for internal
enums. 

 +
 +static char **xkb_parse_argument(const char *arg) {
 +_cleanup_free_ char *input = NULL;
 +char *token;
 +char **result = NULL;
 +int r;
 +
 +if (!arg)
 +return NULL;
 +
 +input = strdup(arg);
 +if (!input)
 +return NULL;
 +
 +token = strsep(input, ,);
 +while(token) {
 +r = strv_extend(result, token);
 +if (r  0)
 +return NULL;
 +token = strsep(input, ,);
 +}
 +
 +return result;

I'd really prefer if we could update strv_split() with a new flag or
so that doesn't collapse multiple separator fields into one.

 +}
 +
 +int xkb_keymap_get_components(X11Keymap *keymap) {
 +_cleanup_strv_free_ char **models = NULL, **options = NULL;
 +_cleanup_fclose_ FILE *f;

Needs to be initialized to NULL. Otherwise we might call fclose() on
an uninitialized pointer of hashmap_new() fails.

 +char line[LINE_MAX];
 +enum KeymapComponent state = NONE;
 +size_t m = 0, o = 0, allocm = 0, alloco = 0;
 +

Spurious newline?

 +Hashmap *x11_layouts;
 +int r;
 +
 +x11_layouts = hashmap_new(string_hash_ops);
 +if (!x11_layouts)
 +return log_oom();
 +
 +f = fopen(/usr/share/X11/xkb/rules/base.lst, re);
 +if (!f) {
 +log_error(Failed to open keyboard mapping list. %m);
 +return -errno;
 +}

x11_layouts is not freed here...

 +
 +FOREACH_LINE(line, f, break) {
 +char *l, *w;
 +_cleanup_free_ char *layout = NULL;
 +
 +l = strstrip(line);
 +
 +if (isempty(l))
 +continue;
 +
 +if (l[0] == '!') {
 +if (startswith(l, ! model))
 +state = MODELS;
 +else if (startswith(l, ! layout))
 +state = LAYOUTS;
 +else if (startswith(l, ! variant))
 +state = VARIANTS;
 +else if (startswith(l, ! option))
 +state = OPTIONS;
 +else
 +state = NONE;
 +
 +continue;
 +}
 +
 +w = l + strcspn(l, WHITESPACE);
 +
 +if (state == VARIANTS  *w != 0) {
 +char *e;
 +
 +*w = 0;
 +w++;
 +w += strspn(w, WHITESPACE);
 +
 +e = strchr(w, ':');
 +if (!e)
 +continue;
 +
 +*e = 0;
 +layout = strdup(w);
 +} else {
 +*w = 0;
 +layout = strdup(l);
 +}
 +
 +if (!layout)
 +return log_oom();
 +
 +if (state == LAYOUTS) {
 +_cleanup_set_free_ Set *item = NULL;
 +
 +item = set_new(string_hash_ops);
 +if (!item)
 +return log_oom();
 +
 +if (!hashmap_contains(x11_layouts, layout)) {
 +r = hashmap_put(x11_layouts, layout, item);

Re: [systemd-devel] [PATCH v2] localed: validate set-x11-keymap input

2014-11-14 Thread Ronny Chevalier
2014-11-14 12:42 GMT+01:00 Jan Synacek jsyna...@redhat.com:
 Try to validate the input similarly to how setxkbmap does it. Multiple
 layouts and variants can be specified, separated by a comma. Variants
 can also be left out, meaning that the user doesn't want any particular
 variant for the respective layout.

 Variants are validated respectively to their layouts. First variant
 validates against first layout, second variant to second layout, etc. If
 there are more entries of either layouts or variants, only their
 respective counterparts are validated, the rest is ignored.

 Examples:
 $ set-x11-keymap us,cz  pc105 ,qwerty
 us is not validated, because no respective variant was specified. cz
 is checked for an existing qwerty variant, the check succeeds.

 $ set-x11-keymap us pc105 ,qwerty
 us is not validated as in the above example. The rest of the variants
 is ignored, because there are no respective layouts.

 $ set-x11-keymap us,cz pc105 qwerty
 us is validated against the qwerty variant, check fails, because
 there is no qwerty variant for the us layout.

 $ set-x11-keymap us,cz pc105 euro,qwerty
 Validation succeeds, there is the euro variant for the us layout,
 and qwerty variant for the cz layout.

 http://lists.freedesktop.org/archives/systemd-devel/2014-October/024411.html
 ---
 v2:
 - rewrite to use the X11Keymap struct
 - use greedy allocation where it makes sense
 - rename enum keymap_state to KeymapComponent
 - on the server side, propagate error to the client and don't log it
 - on the server side, change SD_BUS_ERROR_FAILED to SD_BUS_ERROR_INVALID_ARGS

  Makefile.am|   2 +
  src/locale/localectl.c |  85 ++---
  src/locale/localed.c   |   6 +
  src/shared/xkb-util.c  | 319 
 +
  src/shared/xkb-util.h  |  50 
  5 files changed, 385 insertions(+), 77 deletions(-)
  create mode 100644 src/shared/xkb-util.c
  create mode 100644 src/shared/xkb-util.h

 diff --git a/Makefile.am b/Makefile.am
 index 701666c..224582c 100644
 --- a/Makefile.am
 +++ b/Makefile.am
 @@ -772,6 +772,8 @@ libsystemd_shared_la_SOURCES = \
 src/shared/time-util.h \
 src/shared/locale-util.c \
 src/shared/locale-util.h \
 +   src/shared/xkb-util.c \
 +   src/shared/xkb-util.h \
 src/shared/mempool.c \
 src/shared/mempool.h \
 src/shared/hashmap.c \
 diff --git a/src/locale/localectl.c b/src/locale/localectl.c
 index d4a2d29..08a1011 100644
 --- a/src/locale/localectl.c
 +++ b/src/locale/localectl.c
 @@ -46,6 +46,7 @@
  #include virt.h
  #include fileio.h
  #include locale-util.h
 +#include xkb-util.h

  static bool arg_no_pager = false;
  static bool arg_ask_password = true;
 @@ -388,15 +389,8 @@ static int set_x11_keymap(sd_bus *bus, char **args, 
 unsigned n) {

  static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
  _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;
 +_cleanup_(xkb_keymap_free_components) X11Keymap keymap = {};
 +enum KeymapComponent look_for;
  int r;

  if (n  2) {
 @@ -404,12 +398,6 @@ static int list_x11_keymaps(sd_bus *bus, char **args, 
 unsigned n) {
  return -EINVAL;
  }

 -f = fopen(/usr/share/X11/xkb/rules/base.lst, re);
 -if (!f) {
 -log_error(Failed to open keyboard mapping list. %m);
 -return -errno;
 -}
 -
  if (streq(args[0], list-x11-keymap-models))
  look_for = MODELS;
  else if (streq(args[0], list-x11-keymap-layouts))
 @@ -421,71 +409,14 @@ static int list_x11_keymaps(sd_bus *bus, char **args, 
 unsigned n) {
  else
  assert_not_reached(Wrong parameter);

 -FOREACH_LINE(line, f, break) {
 -char *l, *w;
 -
 -l = strstrip(line);
 -
 -if (isempty(l))
 -continue;
 -
 -if (l[0] == '!') {
 -if (startswith(l, ! model))
 -state = MODELS;
 -else if (startswith(l, ! layout))
 -state = LAYOUTS;
 -else if (startswith(l, ! variant))
 -state = VARIANTS;
 -else if (startswith(l, ! option))
 -state = OPTIONS;
 -else
 -state = NONE;
 -
 -continue;
 -}
 -
 -if (state != look_for)
 -continue;
 -
 -w = l + strcspn(l, WHITESPACE);
 -
 -if (n  1) {
 -