--- elogind-241.3-orig/meson.build	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/meson.build	2019-08-25 12:17:48.274738372 -0500
@@ -274,9 +274,9 @@ conf.set_quoted('ROOTPREFIX',
 #endif // 0
 conf.set_quoted('SYSTEM_SHUTDOWN_PATH',                       systemshutdowndir)
 conf.set_quoted('SYSTEM_SLEEP_PATH',                          systemsleepdir)
+conf.set_quoted('SYSTEMD_KBD_MODEL_MAP',                      join_paths(pkgdatadir, 'kbd-model-map'))
+conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP',              join_paths(pkgdatadir, 'language-fallback-map'))
 #if 0 /// UNNEEDED by elogind
-# conf.set_quoted('SYSTEMD_KBD_MODEL_MAP',                      join_paths(pkgdatadir, 'kbd-model-map'))
-# conf.set_quoted('SYSTEMD_LANGUAGE_FALLBACK_MAP',              join_paths(pkgdatadir, 'language-fallback-map'))
 # conf.set_quoted('SYSTEMD_TEST_DATA',                          join_paths(testsdir, 'testdata'))
 # conf.set_quoted('SYSTEMD_CATALOG_DIR',                        catalogdir)
 # conf.set_quoted('UDEVLIBEXECDIR',                             udevlibexecdir)
@@ -1541,7 +1541,9 @@ foreach term : ['utmp',
 #                 'resolve',
 #                 'logind',
 #                 'hostnamed',
-#                 'localed',
+#endif // 0
+                'localed',
+#if 0 /// UNNEEDED by elogind
 #                 'machined',
 #                 'portabled',
 #                 'networkd',
@@ -1820,7 +1822,9 @@ subdir('src/shared')
 # subdir('src/hostname')
 # subdir('src/import')
 # subdir('src/kernel-install')
-# subdir('src/locale')
+#endif // 0
+subdir('src/locale')
+#if 0 /// UNNEEDED by elogind
 # subdir('src/machine')
 # subdir('src/portable')
 # subdir('src/nspawn')
@@ -2429,31 +2433,33 @@ endif
 #         public_programs += exe
 # endif
 #
-# if conf.get('ENABLE_LOCALED') == 1
-#         if conf.get('HAVE_XKBCOMMON') == 1
-#                 # logind will load libxkbcommon.so dynamically on its own
-#                 deps = [libdl]
-#         else
-#                 deps = []
-#         endif
-#
-#         executable('systemd-localed',
-#                    systemd_localed_sources,
-#                    include_directories : includes,
-#                    link_with : [libshared],
-#                    dependencies : deps,
-#                    install_rpath : rootlibexecdir,
-#                    install : true,
-#                    install_dir : rootlibexecdir)
-#
-#         exe = executable('localectl',
-#                          localectl_sources,
-#                          include_directories : includes,
-#                          link_with : [libshared],
-#                          install_rpath : rootlibexecdir,
-#                          install : true)
-#         public_programs += exe
-# endif
+#endif // 0
+if conf.get('ENABLE_LOCALED') == 1
+        if conf.get('HAVE_XKBCOMMON') == 1
+                # logind will load libxkbcommon.so dynamically on its own
+                deps = [libdl]
+        else
+                deps = []
+        endif
+
+        executable('systemd-localed',
+                   systemd_localed_sources,
+                   include_directories : includes,
+                   link_with : [libshared],
+                   dependencies : deps,
+                   install_rpath : rootlibexecdir,
+                   install : true,
+                   install_dir : rootlibexecdir)
+
+        exe = executable('localectl',
+                         localectl_sources,
+                         include_directories : includes,
+                         link_with : [libshared],
+                         install_rpath : rootlibexecdir,
+                         install : true)
+        public_programs += exe
+endif
+#if 0 /// UNNEEDED by elogind
 #
 # if conf.get('ENABLE_TIMEDATED') == 1
 #         executable('systemd-timedated',
@@ -3645,7 +3651,9 @@ foreach tuple : [
 #         ['hostnamed'],
 #         ['timedated'],
 #         ['timesyncd'],
-#         ['localed'],
+#endif // 0
+        ['localed'],
+#if 0 /// UNNEEDED by elogind
 #         ['networkd'],
 #         ['resolve'],
 #         ['DNS-over-TLS(gnutls)',  conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1],
--- elogind-241.3-orig/meson_options.txt	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/meson_options.txt	2019-08-25 12:04:19.883311095 -0500
@@ -116,8 +116,10 @@ option('utmp', type : 'boolean',
 #        description : 'install the systemd-logind stack')
 # option('hostnamed', type : 'boolean',
 #        description : 'install the systemd-hostnamed stack')
-# option('localed', type : 'boolean',
-#        description : 'install the systemd-localed stack')
+#endif // 0
+option('localed', type : 'boolean',
+       description : 'install the systemd-localed stack')
+#if 0 /// UNNEEDED by elogind
 # option('machined', type : 'boolean',
 #        description : 'install the systemd-machined stack')
 # option('portabled', type : 'boolean',
diff -Naurp elogind-241.3-orig/src/basic/proc-cmdline.c elogind-241.3/src/basic/proc-cmdline.c
--- elogind-241.3-orig/src/basic/proc-cmdline.c	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/src/basic/proc-cmdline.c	2019-08-25 12:19:16.465767155 -0500
@@ -135,7 +135,6 @@ static bool relaxed_equal_char(char a, c
                 (a == '-' && b == '_');
 }
 
-#if 0 /// UNNEEDED by elogind
 char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
         assert(s);
         assert(prefix);
@@ -148,7 +147,6 @@ char *proc_cmdline_key_startswith(const
 
         return (char*) s;
 }
-#endif // 0
 
 bool proc_cmdline_key_streq(const char *x, const char *y) {
         assert(x);
@@ -258,7 +256,7 @@ int proc_cmdline_get_bool(const char *ke
 
         return 1;
 }
-
+#endif // 0
 int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
         _cleanup_free_ char *line = NULL;
         const char *p;
@@ -314,7 +312,7 @@ int proc_cmdline_get_key_many_internal(P
 
         return ret;
 }
-
+#if 0 /// UNNEEDED by elogind
 int shall_restore_state(void) {
         bool ret;
         int r;
diff -Naurp elogind-241.3-orig/src/basic/proc-cmdline.h elogind-241.3/src/basic/proc-cmdline.h
--- elogind-241.3-orig/src/basic/proc-cmdline.h	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/src/basic/proc-cmdline.h	2019-08-25 12:18:56.786760710 -0500
@@ -21,12 +21,12 @@ int proc_cmdline_parse(const proc_cmdlin
 #if 0 /// UNNEEDED by elogind
 int proc_cmdline_get_key(const char *parameter, ProcCmdlineFlags flags, char **value);
 int proc_cmdline_get_bool(const char *key, bool *ret);
+#endif // 0
 
 int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...);
 #define proc_cmdline_get_key_many(flags, ...) proc_cmdline_get_key_many_internal(flags, __VA_ARGS__, NULL)
 
 char *proc_cmdline_key_startswith(const char *s, const char *prefix);
-#endif // 0
 bool proc_cmdline_key_streq(const char *x, const char *y);
 
 #if 0 /// UNNEEDED by elogind
diff -Naurp elogind-241.3-orig/src/locale/kbd-model-map elogind-241.3/src/locale/kbd-model-map
--- elogind-241.3-orig/src/locale/kbd-model-map	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/kbd-model-map	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,68 @@
+# Generated from system-config-keyboard's model list
+# consolelayout		xlayout	xmodel		xvariant	xoptions
+sg			ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
+nl			nl	pc105		-		terminate:ctrl_alt_bksp
+mk-utf			mk,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+trq			tr	pc105		-		terminate:ctrl_alt_bksp
+uk			gb	pc105		-		terminate:ctrl_alt_bksp
+is-latin1		is	pc105		-		terminate:ctrl_alt_bksp
+de			de	pc105		-		terminate:ctrl_alt_bksp
+la-latin1		latam	pc105		-		terminate:ctrl_alt_bksp
+us			us	pc105+inet	-		terminate:ctrl_alt_bksp
+ko			kr	pc105		-		terminate:ctrl_alt_bksp
+ro-std			ro	pc105		std		terminate:ctrl_alt_bksp
+de-latin1		de	pc105		-		terminate:ctrl_alt_bksp
+slovene			si	pc105		-		terminate:ctrl_alt_bksp
+hu101			hu	pc105		qwerty		terminate:ctrl_alt_bksp
+jp106			jp	jp106		-		terminate:ctrl_alt_bksp
+croat			hr	pc105		-		terminate:ctrl_alt_bksp
+it2			it	pc105		-		terminate:ctrl_alt_bksp
+hu			hu	pc105		-		terminate:ctrl_alt_bksp
+sr-latin		rs	pc105		latin		terminate:ctrl_alt_bksp
+fi			fi	pc105		-		terminate:ctrl_alt_bksp
+fr_CH			ch	pc105		fr		terminate:ctrl_alt_bksp
+dk-latin1		dk	pc105		-		terminate:ctrl_alt_bksp
+fr			fr	pc105		-		terminate:ctrl_alt_bksp
+it			it	pc105		-		terminate:ctrl_alt_bksp
+ua-utf			ua,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin1		fr	pc105		-		terminate:ctrl_alt_bksp
+sg-latin1		ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
+be-latin1		be	pc105		-		terminate:ctrl_alt_bksp
+dk			dk	pc105		-		terminate:ctrl_alt_bksp
+fr-pc			fr	pc105		-		terminate:ctrl_alt_bksp
+bg_pho-utf8		bg,us	pc105		,phonetic	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+it-ibm			it	pc105		-		terminate:ctrl_alt_bksp
+cz-us-qwertz		cz,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+br-abnt2		br	abnt2		-		terminate:ctrl_alt_bksp
+ro			ro	pc105		-		terminate:ctrl_alt_bksp
+us-acentos		us	pc105		intl		terminate:ctrl_alt_bksp
+pt-latin1		pt	pc105		-		terminate:ctrl_alt_bksp
+ro-std-cedilla		ro	pc105		std_cedilla	terminate:ctrl_alt_bksp
+tj_alt-UTF8		tj	pc105		-		terminate:ctrl_alt_bksp
+de-latin1-nodeadkeys	de	pc105		nodeadkeys	terminate:ctrl_alt_bksp
+no			no	pc105		-		terminate:ctrl_alt_bksp
+bg_bds-utf8		bg,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+dvorak			us	pc105		dvorak		terminate:ctrl_alt_bksp
+dvorak			us	pc105		dvorak-alt-intl	terminate:ctrl_alt_bksp
+ru			ru,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+cz-lat2			cz	pc105		qwerty		terminate:ctrl_alt_bksp
+pl2			pl	pc105		-		terminate:ctrl_alt_bksp
+es			es	pc105		-		terminate:ctrl_alt_bksp
+ro-cedilla		ro	pc105		cedilla		terminate:ctrl_alt_bksp
+ie			ie	pc105		-		terminate:ctrl_alt_bksp
+et			ee	pc105		-		terminate:ctrl_alt_bksp
+sk-qwerty		sk	pc105		-		terminate:ctrl_alt_bksp,qwerty
+sk-qwertz		sk	pc105		-		terminate:ctrl_alt_bksp
+fr-latin9		fr	pc105		latin9		terminate:ctrl_alt_bksp
+fr_CH-latin1		ch	pc105		fr		terminate:ctrl_alt_bksp
+cf			ca	pc105		-		terminate:ctrl_alt_bksp
+sv-latin1		se	pc105		-		terminate:ctrl_alt_bksp
+sr-cy			rs	pc105		-		terminate:ctrl_alt_bksp
+gr			gr,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+by			by,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+il			il	pc105		-		terminate:ctrl_alt_bksp
+kazakh			kz,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+lt.baltic		lt	pc105		-		terminate:ctrl_alt_bksp
+lt.l4                  lt	pc105		-		terminate:ctrl_alt_bksp
+lt			lt	pc105		-		terminate:ctrl_alt_bksp
+khmer			kh,us	pc105		-		terminate:ctrl_alt_bksp
diff -Naurp elogind-241.3-orig/src/locale/keymap-util.c elogind-241.3/src/locale/keymap-util.c
--- elogind-241.3-orig/src/locale/keymap-util.c	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/keymap-util.c	2019-08-25 12:15:44.281698231 -0500
@@ -0,0 +1,540 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <stdio_ext.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bus-util.h"
+#include "def.h"
+#include "env-file.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fileio-label.h"
+#include "fileio.h"
+#include "keymap-util.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tmpfile-util.h"
+
+static bool startswith_comma(const char *s, const char *prefix) {
+        s = startswith(s, prefix);
+        if (!s)
+                return false;
+
+        return IN_SET(*s, ',', '\0');
+}
+
+static const char* strnulldash(const char *s) {
+        return isempty(s) || streq(s, "-") ? NULL : s;
+}
+
+static const char* systemd_kbd_model_map(void) {
+        const char* s;
+
+        s = getenv("SYSTEMD_KBD_MODEL_MAP");
+        if (s)
+                return s;
+
+        return SYSTEMD_KBD_MODEL_MAP;
+}
+
+static const char* systemd_language_fallback_map(void) {
+        const char* s;
+
+        s = getenv("SYSTEMD_LANGUAGE_FALLBACK_MAP");
+        if (s)
+                return s;
+
+        return SYSTEMD_LANGUAGE_FALLBACK_MAP;
+}
+
+static void context_free_x11(Context *c) {
+        c->x11_layout = mfree(c->x11_layout);
+        c->x11_options = mfree(c->x11_options);
+        c->x11_model = mfree(c->x11_model);
+        c->x11_variant = mfree(c->x11_variant);
+}
+
+static void context_free_vconsole(Context *c) {
+        c->vc_keymap = mfree(c->vc_keymap);
+        c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
+}
+
+static void context_free_locale(Context *c) {
+        int p;
+
+        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+                c->locale[p] = mfree(c->locale[p]);
+}
+
+void context_clear(Context *c) {
+        context_free_locale(c);
+        context_free_x11(c);
+        context_free_vconsole(c);
+
+        sd_bus_message_unref(c->locale_cache);
+        sd_bus_message_unref(c->x11_cache);
+        sd_bus_message_unref(c->vc_cache);
+
+        bus_verify_polkit_async_registry_free(c->polkit_registry);
+};
+
+void locale_simplify(char *locale[_VARIABLE_LC_MAX]) {
+        int p;
+
+        for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++)
+                if (isempty(locale[p]) || streq_ptr(locale[VARIABLE_LANG], locale[p]))
+                        locale[p] = mfree(locale[p]);
+}
+
+int locale_read_data(Context *c, sd_bus_message *m) {
+        struct stat st;
+        int r;
+
+        /* Do not try to re-read the file within single bus operation. */
+        if (m) {
+                if (m == c->locale_cache)
+                        return 0;
+
+                sd_bus_message_unref(c->locale_cache);
+                c->locale_cache = sd_bus_message_ref(m);
+        }
+
+        r = stat("/etc/locale.conf", &st);
+        if (r < 0 && errno != ENOENT)
+                return -errno;
+
+        if (r >= 0) {
+                usec_t t;
+
+                /* If mtime is not changed, then we do not need to re-read the file. */
+                t = timespec_load(&st.st_mtim);
+                if (c->locale_mtime != USEC_INFINITY && t == c->locale_mtime)
+                        return 0;
+
+                c->locale_mtime = t;
+                context_free_locale(c);
+
+                r = parse_env_file(NULL, "/etc/locale.conf",
+                                   "LANG",              &c->locale[VARIABLE_LANG],
+                                   "LANGUAGE",          &c->locale[VARIABLE_LANGUAGE],
+                                   "LC_CTYPE",          &c->locale[VARIABLE_LC_CTYPE],
+                                   "LC_NUMERIC",        &c->locale[VARIABLE_LC_NUMERIC],
+                                   "LC_TIME",           &c->locale[VARIABLE_LC_TIME],
+                                   "LC_COLLATE",        &c->locale[VARIABLE_LC_COLLATE],
+                                   "LC_MONETARY",       &c->locale[VARIABLE_LC_MONETARY],
+                                   "LC_MESSAGES",       &c->locale[VARIABLE_LC_MESSAGES],
+                                   "LC_PAPER",          &c->locale[VARIABLE_LC_PAPER],
+                                   "LC_NAME",           &c->locale[VARIABLE_LC_NAME],
+                                   "LC_ADDRESS",        &c->locale[VARIABLE_LC_ADDRESS],
+                                   "LC_TELEPHONE",      &c->locale[VARIABLE_LC_TELEPHONE],
+                                   "LC_MEASUREMENT",    &c->locale[VARIABLE_LC_MEASUREMENT],
+                                   "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
+                if (r < 0)
+                        return r;
+        } else {
+                int p;
+
+                c->locale_mtime = USEC_INFINITY;
+                context_free_locale(c);
+
+                /* Fill in what we got passed from systemd. */
+                for (p = 0; p < _VARIABLE_LC_MAX; p++) {
+                        const char *name;
+
+                        name = locale_variable_to_string(p);
+                        assert(name);
+
+                        r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name)));
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        locale_simplify(c->locale);
+        return 0;
+}
+
+int vconsole_read_data(Context *c, sd_bus_message *m) {
+        struct stat st;
+        usec_t t;
+        int r;
+
+        /* Do not try to re-read the file within single bus operation. */
+        if (m) {
+                if (m == c->vc_cache)
+                        return 0;
+
+                sd_bus_message_unref(c->vc_cache);
+                c->vc_cache = sd_bus_message_ref(m);
+        }
+
+        c->vc_mtime = USEC_INFINITY;
+        context_free_vconsole(c);
+        return 0;
+}
+
+static char *getenv_strdup(const char *variable) {
+        const char *value = getenv(variable);
+        return value == NULL ? NULL : strdup(value);
+}
+
+int x11_read_data(Context *c, sd_bus_message *m) {
+        _cleanup_fclose_ FILE *f = NULL;
+        bool in_section = false;
+        struct stat st;
+        usec_t t;
+        int r;
+
+        /* Do not try to re-read the file within single bus operation. */
+        if (m) {
+                if (m == c->x11_cache)
+                        return 0;
+
+                sd_bus_message_unref(c->x11_cache);
+                c->x11_cache = sd_bus_message_ref(m);
+        }
+
+        c->x11_mtime = 0;
+        context_free_x11(c);
+
+        c->x11_layout = getenv_strdup("XKB_LAYOUT");
+        c->x11_model = getenv_strdup("XKB_MODEL");
+        c->x11_variant = getenv_strdup("XKB_VARIANT");
+        c->x11_options = getenv_strdup("XKB_OPTIONS");
+
+        return 0;
+}
+
+int locale_write_data(Context *c, char ***settings) {
+        return -ENOSYS;
+}
+
+int vconsole_write_data(Context *c) {
+        return -ENOSYS;
+}
+
+int x11_write_data(Context *c) {
+        return -ENOSYS;
+}
+
+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);
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                size_t length;
+                char *l, **b;
+                int r;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                (*n)++;
+
+                l = strstrip(line);
+                if (IN_SET(l[0], 0, '#'))
+                        continue;
+
+                r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES);
+                if (r < 0)
+                        return r;
+
+                length = strv_length(b);
+                if (length < min_fields || length > max_fields) {
+                        log_error("Invalid line %s:%u, ignoring.", filename, *n);
+                        strv_free(b);
+                        continue;
+
+                }
+
+                *a = b;
+                return 1;
+        }
+
+        return 0;
+}
+
+int vconsole_convert_to_x11(Context *c) {
+        const char *map;
+        int modified = -1;
+
+        map = systemd_kbd_model_map();
+
+        if (isempty(c->vc_keymap)) {
+                modified =
+                        !isempty(c->x11_layout) ||
+                        !isempty(c->x11_model) ||
+                        !isempty(c->x11_variant) ||
+                        !isempty(c->x11_options);
+
+                context_free_x11(c);
+        } else {
+                _cleanup_fclose_ FILE *f = NULL;
+                unsigned n = 0;
+
+                f = fopen(map, "re");
+                if (!f)
+                        return -errno;
+
+                for (;;) {
+                        _cleanup_strv_free_ char **a = NULL;
+                        int r;
+
+                        r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
+
+                        if (!streq(c->vc_keymap, a[0]))
+                                continue;
+
+                        if (!streq_ptr(c->x11_layout, strnulldash(a[1])) ||
+                            !streq_ptr(c->x11_model, strnulldash(a[2])) ||
+                            !streq_ptr(c->x11_variant, strnulldash(a[3])) ||
+                            !streq_ptr(c->x11_options, strnulldash(a[4]))) {
+
+                                if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 ||
+                                    free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 ||
+                                    free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 ||
+                                    free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0)
+                                        return -ENOMEM;
+
+                                modified = true;
+                        }
+
+                        break;
+                }
+        }
+
+        if (modified > 0)
+                log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
+                         strempty(c->x11_layout),
+                         strempty(c->x11_model),
+                         strempty(c->x11_variant),
+                         strempty(c->x11_options));
+        else if (modified < 0)
+                log_notice("X11 keyboard layout was not modified: no conversion found for \"%s\".",
+                           c->vc_keymap);
+        else
+                log_debug("X11 keyboard layout did not need to be modified.");
+
+        return modified > 0;
+}
+
+int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) {
+        const char *dir;
+        _cleanup_free_ char *n;
+
+        if (x11_variant)
+                n = strjoin(x11_layout, "-", x11_variant);
+        else
+                n = strdup(x11_layout);
+        if (!n)
+                return -ENOMEM;
+
+        NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
+                _cleanup_free_ char *p = NULL, *pz = NULL;
+                bool uncompressed;
+
+                p = strjoin(dir, "xkb/", n, ".map");
+                pz = strjoin(dir, "xkb/", n, ".map.gz");
+                if (!p || !pz)
+                        return -ENOMEM;
+
+                uncompressed = access(p, F_OK) == 0;
+                if (uncompressed || access(pz, F_OK) == 0) {
+                        log_debug("Found converted keymap %s at %s",
+                                  n, uncompressed ? p : pz);
+
+                        *new_keymap = TAKE_PTR(n);
+                        return 1;
+                }
+        }
+
+        return 0;
+}
+
+int find_legacy_keymap(Context *c, char **ret) {
+        const char *map;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *new_keymap = NULL;
+        unsigned n = 0;
+        unsigned best_matching = 0;
+        int r;
+
+        assert(!isempty(c->x11_layout));
+
+        map = systemd_kbd_model_map();
+
+        f = fopen(map, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                _cleanup_strv_free_ char **a = NULL;
+                unsigned matching = 0;
+
+                r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                /* Determine how well matching this entry is */
+                if (streq(c->x11_layout, a[1]))
+                        /* If we got an exact match, this is best */
+                        matching = 10;
+                else {
+                        /* We have multiple X layouts, look for an
+                         * entry that matches our key with everything
+                         * but the first layout stripped off. */
+                        if (startswith_comma(c->x11_layout, a[1]))
+                                matching = 5;
+                        else  {
+                                char *x;
+
+                                /* If that didn't work, strip off the
+                                 * other layouts from the entry, too */
+                                x = strndupa(a[1], strcspn(a[1], ","));
+                                if (startswith_comma(c->x11_layout, x))
+                                        matching = 1;
+                        }
+                }
+
+                if (matching > 0) {
+                        if (isempty(c->x11_model) || 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 >= MAX(best_matching, 1u)) {
+                        log_debug("Found legacy keymap %s with score %u",
+                                  a[0], matching);
+
+                        if (matching > best_matching) {
+                                best_matching = matching;
+
+                                r = free_and_strdup(&new_keymap, a[0]);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        }
+
+        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);
+        }
+
+        *ret = TAKE_PTR(new_keymap);
+        return (bool) *ret;
+}
+
+int find_language_fallback(const char *lang, char **language) {
+        const char *map;
+        _cleanup_fclose_ FILE *f = NULL;
+        unsigned n = 0;
+
+        assert(lang);
+        assert(language);
+
+        map = systemd_language_fallback_map();
+
+        f = fopen(map, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                _cleanup_strv_free_ char **a = NULL;
+                int r;
+
+                r = read_next_mapping(map, 2, 2, f, &n, &a);
+                if (r <= 0)
+                        return r;
+
+                if (streq(lang, a[0])) {
+                        assert(strv_length(a) == 2);
+                        *language = TAKE_PTR(a[1]);
+                        return 1;
+                }
+        }
+
+        assert_not_reached("should not be here");
+}
+
+int x11_convert_to_vconsole(Context *c) {
+        bool modified = false;
+
+        if (isempty(c->x11_layout)) {
+                modified =
+                        !isempty(c->vc_keymap) ||
+                        !isempty(c->vc_keymap_toggle);
+
+                context_free_vconsole(c);
+        } else {
+                _cleanup_free_ char *new_keymap = NULL;
+                int r;
+
+                r = find_converted_keymap(c->x11_layout, c->x11_variant, &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)
+                        /* We search for layout-variant match first, but then we also look
+                         * for anything which matches just the layout. So it's accurate to say
+                         * that we couldn't find anything which matches the layout. */
+                        log_notice("No conversion to virtual console map found for \"%s\".",
+                                   c->x11_layout);
+
+                if (!streq_ptr(c->vc_keymap, new_keymap)) {
+                        free_and_replace(c->vc_keymap, new_keymap);
+                        c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
+                        modified = true;
+                }
+        }
+
+        if (modified)
+                log_info("Changing virtual console keymap to '%s' toggle '%s'",
+                         strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
+        else
+                log_debug("Virtual console keymap was not modified.");
+
+        return modified;
+}
diff -Naurp elogind-241.3-orig/src/locale/keymap-util.h elogind-241.3/src/locale/keymap-util.h
--- elogind-241.3-orig/src/locale/keymap-util.h	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/keymap-util.h	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+
+#include "hashmap.h"
+#include "locale-util.h"
+#include "time-util.h"
+
+typedef struct Context {
+        sd_bus_message *locale_cache;
+        usec_t locale_mtime;
+        char *locale[_VARIABLE_LC_MAX];
+
+        sd_bus_message *x11_cache;
+        usec_t x11_mtime;
+        char *x11_layout;
+        char *x11_model;
+        char *x11_variant;
+        char *x11_options;
+
+        sd_bus_message *vc_cache;
+        usec_t vc_mtime;
+        char *vc_keymap;
+        char *vc_keymap_toggle;
+
+        Hashmap *polkit_registry;
+} Context;
+
+int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap);
+int find_legacy_keymap(Context *c, char **new_keymap);
+int find_language_fallback(const char *lang, char **language);
+
+int locale_read_data(Context *c, sd_bus_message *m);
+int vconsole_read_data(Context *c, sd_bus_message *m);
+int x11_read_data(Context *c, sd_bus_message *m);
+
+void context_clear(Context *c);
+int vconsole_convert_to_x11(Context *c);
+int vconsole_write_data(Context *c);
+int x11_convert_to_vconsole(Context *c);
+int x11_write_data(Context *c);
+void locale_simplify(char *locale[_VARIABLE_LC_MAX]);
+int locale_write_data(Context *c, char ***settings);
diff -Naurp elogind-241.3-orig/src/locale/language-fallback-map elogind-241.3/src/locale/language-fallback-map
--- elogind-241.3-orig/src/locale/language-fallback-map	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/language-fallback-map	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,13 @@
+csb_PL csb:pl
+en_AU en_AU:en_GB
+en_IE en_IE:en_GB
+en_NZ en_NZ:en_GB
+en_ZA en_ZA:en_GB
+fr_BE fr_BE:fr_FR
+fr_CA fr_CA:fr_FR
+fr_CH fr_CH:fr_FR
+fr_LU fr_LU:fr_FR
+it_CH it_CH:it_IT
+mai_IN mai:hi
+nds_DE nds:de
+szl_PL szl:pl
diff -Naurp elogind-241.3-orig/src/locale/localectl.c elogind-241.3/src/locale/localectl.c
--- elogind-241.3-orig/src/locale/localectl.c	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/localectl.c	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,527 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <ftw.h>
+#include <getopt.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-bus.h"
+
+#include "bus-error.h"
+#include "bus-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "locale-util.h"
+#include "main-func.h"
+#include "pager.h"
+#include "pretty-print.h"
+#include "proc-cmdline.h"
+#include "set.h"
+#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "util.h"
+#include "verbs.h"
+#include "virt.h"
+
+static PagerFlags arg_pager_flags = 0;
+static bool arg_ask_password = true;
+static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+static const char *arg_host = NULL;
+static bool arg_convert = true;
+
+typedef struct StatusInfo {
+        char **locale;
+        const char *vconsole_keymap;
+        const char *vconsole_keymap_toggle;
+        const char *x11_layout;
+        const char *x11_model;
+        const char *x11_variant;
+        const char *x11_options;
+} StatusInfo;
+
+static void status_info_clear(StatusInfo *info) {
+        if (info) {
+                strv_free(info->locale);
+                zero(*info);
+        }
+}
+
+static void print_overridden_variables(void) {
+        _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {};
+        bool print_warning = true;
+        LocaleVariable j;
+        int r;
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return;
+
+        r = proc_cmdline_get_key_many(
+                        PROC_CMDLINE_STRIP_RD_PREFIX,
+                        "locale.LANG",              &variables[VARIABLE_LANG],
+                        "locale.LANGUAGE",          &variables[VARIABLE_LANGUAGE],
+                        "locale.LC_CTYPE",          &variables[VARIABLE_LC_CTYPE],
+                        "locale.LC_NUMERIC",        &variables[VARIABLE_LC_NUMERIC],
+                        "locale.LC_TIME",           &variables[VARIABLE_LC_TIME],
+                        "locale.LC_COLLATE",        &variables[VARIABLE_LC_COLLATE],
+                        "locale.LC_MONETARY",       &variables[VARIABLE_LC_MONETARY],
+                        "locale.LC_MESSAGES",       &variables[VARIABLE_LC_MESSAGES],
+                        "locale.LC_PAPER",          &variables[VARIABLE_LC_PAPER],
+                        "locale.LC_NAME",           &variables[VARIABLE_LC_NAME],
+                        "locale.LC_ADDRESS",        &variables[VARIABLE_LC_ADDRESS],
+                        "locale.LC_TELEPHONE",      &variables[VARIABLE_LC_TELEPHONE],
+                        "locale.LC_MEASUREMENT",    &variables[VARIABLE_LC_MEASUREMENT],
+                        "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION]);
+        if (r < 0 && r != -ENOENT) {
+                log_warning_errno(r, "Failed to read /proc/cmdline: %m");
+                return;
+        }
+
+        for (j = 0; j < _VARIABLE_LC_MAX; j++)
+                if (variables[j]) {
+                        if (print_warning) {
+                                log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n"
+                                            "    Command Line: %s=%s", locale_variable_to_string(j), variables[j]);
+
+                                print_warning = false;
+                        } else
+                                log_warning("                  %s=%s", locale_variable_to_string(j), variables[j]);
+                }
+}
+
+static void print_status_info(StatusInfo *i) {
+        assert(i);
+
+        if (strv_isempty(i->locale))
+                puts("   System Locale: n/a");
+        else {
+                char **j;
+
+                printf("   System Locale: %s\n", i->locale[0]);
+                STRV_FOREACH(j, i->locale + 1)
+                        printf("                  %s\n", *j);
+        }
+
+        printf("       VC Keymap: %s\n", strna(i->vconsole_keymap));
+        if (!isempty(i->vconsole_keymap_toggle))
+                printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
+
+        printf("      X11 Layout: %s\n", strna(i->x11_layout));
+        if (!isempty(i->x11_model))
+                printf("       X11 Model: %s\n", i->x11_model);
+        if (!isempty(i->x11_variant))
+                printf("     X11 Variant: %s\n", i->x11_variant);
+        if (!isempty(i->x11_options))
+                printf("     X11 Options: %s\n", i->x11_options);
+}
+
+static int show_status(int argc, char **argv, void *userdata) {
+        _cleanup_(status_info_clear) StatusInfo info = {};
+        static const struct bus_properties_map map[]  = {
+                { "VConsoleKeymap",       "s",  NULL, offsetof(StatusInfo, vconsole_keymap) },
+                { "VConsoleKeymapToggle", "s",  NULL, offsetof(StatusInfo, vconsole_keymap_toggle) },
+                { "X11Layout",            "s",  NULL, offsetof(StatusInfo, x11_layout) },
+                { "X11Model",             "s",  NULL, offsetof(StatusInfo, x11_model) },
+                { "X11Variant",           "s",  NULL, offsetof(StatusInfo, x11_variant) },
+                { "X11Options",           "s",  NULL, offsetof(StatusInfo, x11_options) },
+                { "Locale",               "as", NULL, offsetof(StatusInfo, locale) },
+                {}
+        };
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        sd_bus *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        r = bus_map_all_properties(bus,
+                                   "org.freedesktop.locale1",
+                                   "/org/freedesktop/locale1",
+                                   map,
+                                   0,
+                                   &error,
+                                   &m,
+                                   &info);
+        if (r < 0)
+                return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
+
+        print_overridden_variables();
+        print_status_info(&info);
+
+        return r;
+}
+
+static int set_locale(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        &m,
+                        "org.freedesktop.locale1",
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "SetLocale");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, argv + 1);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "b", arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, -r));
+
+        return 0;
+}
+
+static int list_locales(int argc, char **argv, void *userdata) {
+        _cleanup_strv_free_ char **l = NULL;
+        int r;
+
+        r = get_locales(&l);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read list of locales: %m");
+
+        (void) pager_open(arg_pager_flags);
+        strv_print(l);
+
+        return 0;
+}
+
+static int set_vconsole_keymap(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *map, *toggle_map;
+        sd_bus *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+        map = argv[1];
+        toggle_map = argc > 2 ? argv[2] : "";
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.locale1",
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "SetVConsoleKeyboard",
+                        &error,
+                        NULL,
+                        "ssbb", map, toggle_map, arg_convert, arg_ask_password);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set keymap: %s", bus_error_message(&error, -r));
+
+        return 0;
+}
+
+static int list_vconsole_keymaps(int argc, char **argv, void *userdata) {
+        _cleanup_strv_free_ char **l = NULL;
+        int r;
+
+        r = get_keymaps(&l);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read list of keymaps: %m");
+
+        (void) pager_open(arg_pager_flags);
+
+        strv_print(l);
+
+        return 0;
+}
+
+static int set_x11_keymap(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        const char *layout, *model, *variant, *options;
+        sd_bus *bus = userdata;
+        int r;
+
+        polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+        layout = argv[1];
+        model = argc > 2 ? argv[2] : "";
+        variant = argc > 3 ? argv[3] : "";
+        options = argc > 4 ? argv[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)
+                return log_error_errno(r, "Failed to set keymap: %s", bus_error_message(&error, -r));
+
+        return 0;
+}
+
+static int list_x11_keymaps(int argc, char **argv, void *userdata) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_strv_free_ char **list = NULL;
+        enum {
+                NONE,
+                MODELS,
+                LAYOUTS,
+                VARIANTS,
+                OPTIONS
+        } state = NONE, look_for;
+        int r;
+
+        f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
+        if (!f)
+                return log_error_errno(errno, "Failed to open keyboard mapping list. %m");
+
+        if (streq(argv[0], "list-x11-keymap-models"))
+                look_for = MODELS;
+        else if (streq(argv[0], "list-x11-keymap-layouts"))
+                look_for = LAYOUTS;
+        else if (streq(argv[0], "list-x11-keymap-variants"))
+                look_for = VARIANTS;
+        else if (streq(argv[0], "list-x11-keymap-options"))
+                look_for = OPTIONS;
+        else
+                assert_not_reached("Wrong parameter");
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                char *l, *w;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read keyboard mapping list: %m");
+                if (r == 0)
+                        break;
+
+                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 (argc > 1) {
+                        char *e;
+
+                        if (*w == 0)
+                                continue;
+
+                        *w = 0;
+                        w++;
+                        w += strspn(w, WHITESPACE);
+
+                        e = strchr(w, ':');
+                        if (!e)
+                                continue;
+
+                        *e = 0;
+
+                        if (!streq(w, argv[1]))
+                                continue;
+                } else
+                        *w = 0;
+
+                r = strv_extend(&list, l);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        if (strv_isempty(list))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "Couldn't find any entries.");
+
+        strv_sort(list);
+        strv_uniq(list);
+
+        (void) pager_open(arg_pager_flags);
+
+        strv_print(list);
+        return 0;
+}
+
+static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("localectl", "1", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...] COMMAND ...\n\n"
+               "Query or change system locale and keyboard settings.\n\n"
+               "  -h --help                Show this help\n"
+               "     --version             Show package version\n"
+               "     --no-pager            Do not pipe output into a pager\n"
+               "     --no-ask-password     Do not prompt for password\n"
+               "  -H --host=[USER@]HOST    Operate on remote host\n"
+               "  -M --machine=CONTAINER   Operate on local container\n"
+               "     --no-convert          Don't convert keyboard mappings\n\n"
+               "Commands:\n"
+               "  status                   Show current locale settings\n"
+               "  set-locale LOCALE...     Set system locale\n"
+               "  list-locales             Show known locales\n"
+               "  set-keymap MAP [MAP]     Set console and X11 keyboard mappings\n"
+               "  list-keymaps             Show known virtual console keyboard mappings\n"
+               "  set-x11-keymap LAYOUT [MODEL [VARIANT [OPTIONS]]]\n"
+               "                           Set X11 and console keyboard mappings\n"
+               "  list-x11-keymap-models   Show known X11 keyboard mapping models\n"
+               "  list-x11-keymap-layouts  Show known X11 keyboard mapping layouts\n"
+               "  list-x11-keymap-variants [LAYOUT]\n"
+               "                           Show known X11 keyboard mapping variants\n"
+               "  list-x11-keymap-options  Show known X11 keyboard mapping options\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , link
+        );
+
+        return 0;
+}
+
+static int verb_help(int argc, char **argv, void *userdata) {
+        return help();
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_NO_PAGER,
+                ARG_NO_CONVERT,
+                ARG_NO_ASK_PASSWORD
+        };
+
+        static const struct option options[] = {
+                { "help",            no_argument,       NULL, 'h'                 },
+                { "version",         no_argument,       NULL, ARG_VERSION         },
+                { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
+                { "host",            required_argument, NULL, 'H'                 },
+                { "machine",         required_argument, NULL, 'M'                 },
+                { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
+                { "no-convert",      no_argument,       NULL, ARG_NO_CONVERT      },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
+
+                switch (c) {
+
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        return version();
+
+                case ARG_NO_CONVERT:
+                        arg_convert = false;
+                        break;
+
+                case ARG_NO_PAGER:
+                        arg_pager_flags |= PAGER_DISABLE;
+                        break;
+
+                case ARG_NO_ASK_PASSWORD:
+                        arg_ask_password = false;
+                        break;
+
+                case 'H':
+                        arg_transport = BUS_TRANSPORT_REMOTE;
+                        arg_host = optarg;
+                        break;
+
+                case 'M':
+                        arg_transport = BUS_TRANSPORT_MACHINE;
+                        arg_host = optarg;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        return 1;
+}
+
+static int localectl_main(sd_bus *bus, int argc, char *argv[]) {
+
+        static const Verb verbs[] = {
+                { "status",                   VERB_ANY, 1,        VERB_DEFAULT, show_status           },
+                { "set-locale",               2,        VERB_ANY, 0,            set_locale            },
+                { "list-locales",             VERB_ANY, 1,        0,            list_locales          },
+                { "set-keymap",               2,        3,        0,            set_vconsole_keymap   },
+                { "list-keymaps",             VERB_ANY, 1,        0,            list_vconsole_keymaps },
+                { "set-x11-keymap",           2,        5,        0,            set_x11_keymap        },
+                { "list-x11-keymap-models",   VERB_ANY, 1,        0,            list_x11_keymaps      },
+                { "list-x11-keymap-layouts",  VERB_ANY, 1,        0,            list_x11_keymaps      },
+                { "list-x11-keymap-variants", VERB_ANY, 2,        0,            list_x11_keymaps      },
+                { "list-x11-keymap-options",  VERB_ANY, 1,        0,            list_x11_keymaps      },
+                { "help",                     VERB_ANY, VERB_ANY, 0,            verb_help             }, /* Not documented, but supported since it is created. */
+                {}
+        };
+
+        return dispatch_verb(argc, argv, verbs, bus);
+}
+
+static int run(int argc, char *argv[]) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        setlocale(LC_ALL, "");
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r;
+
+        r = bus_connect_transport(arg_transport, arg_host, false, &bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create bus connection: %m");
+
+        return localectl_main(bus, argc, argv);
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff -Naurp elogind-241.3-orig/src/locale/localed.c elogind-241.3/src/locale/localed.c
--- elogind-241.3-orig/src/locale/localed.c	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/localed.c	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,758 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_XKBCOMMON
+#include <xkbcommon/xkbcommon.h>
+#include <dlfcn.h>
+#endif
+
+#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "def.h"
+#include "keymap-util.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "main-func.h"
+#include "missing_capability.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+
+static int locale_update_system_manager(Context *c, sd_bus *bus) {
+        _cleanup_free_ char **l_unset = NULL;
+        _cleanup_strv_free_ char **l_set = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        sd_bus_error error = SD_BUS_ERROR_NULL;
+        size_t c_set, c_unset;
+        LocaleVariable p;
+        int r;
+
+        assert(bus);
+
+        l_unset = new0(char*, _VARIABLE_LC_MAX);
+        if (!l_unset)
+                return log_oom();
+
+        l_set = new0(char*, _VARIABLE_LC_MAX);
+        if (!l_set)
+                return log_oom();
+
+        for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) {
+                const char *name;
+
+                name = locale_variable_to_string(p);
+                assert(name);
+
+                if (isempty(c->locale[p]))
+                        l_unset[c_set++] = (char*) name;
+                else {
+                        char *s;
+
+                        s = strjoin(name, "=", c->locale[p]);
+                        if (!s)
+                                return log_oom();
+
+                        l_set[c_unset++] = s;
+                }
+        }
+
+        assert(c_set + c_unset == _VARIABLE_LC_MAX);
+        r = sd_bus_message_new_method_call(bus, &m,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "UnsetAndSetEnvironment");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, l_unset);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append_strv(m, l_set);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to update the manager environment: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+static int vconsole_reload(sd_bus *bus) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_call_method(bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "RestartUnit",
+                        &error,
+                        NULL,
+                        "ss", "systemd-vconsole-setup.service", "replace");
+
+        if (r < 0)
+                return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
+static int vconsole_convert_to_x11_and_emit(Context *c, sd_bus_message *m) {
+        int r;
+
+        assert(m);
+
+        r = x11_read_data(c, m);
+        if (r < 0)
+                return r;
+
+        r = vconsole_convert_to_x11(c);
+        if (r <= 0)
+                return r;
+
+        /* modified */
+        r = x11_write_data(c);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write X11 keyboard layout: %m");
+
+        sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
+                                       "/org/freedesktop/locale1",
+                                       "org.freedesktop.locale1",
+                                       "X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
+
+        return 1;
+}
+
+static int x11_convert_to_vconsole_and_emit(Context *c, sd_bus_message *m) {
+        int r;
+
+        assert(m);
+
+        r = vconsole_read_data(c, m);
+        if (r < 0)
+                return r;
+
+        r = x11_convert_to_vconsole(c);
+        if (r <= 0)
+                return r;
+
+        /* modified */
+        r = vconsole_write_data(c);
+        if (r < 0)
+                log_error_errno(r, "Failed to save virtual console keymap: %m");
+
+        sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
+                                       "/org/freedesktop/locale1",
+                                       "org.freedesktop.locale1",
+                                       "VConsoleKeymap", "VConsoleKeymapToggle", NULL);
+
+        return vconsole_reload(sd_bus_message_get_bus(m));
+}
+
+static int property_get_locale(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Context *c = userdata;
+        _cleanup_strv_free_ char **l = NULL;
+        int p, q, r;
+
+        r = locale_read_data(c, reply);
+        if (r < 0)
+                return r;
+
+        l = new0(char*, _VARIABLE_LC_MAX+1);
+        if (!l)
+                return -ENOMEM;
+
+        for (p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) {
+                char *t;
+                const char *name;
+
+                name = locale_variable_to_string(p);
+                assert(name);
+
+                if (isempty(c->locale[p]))
+                        continue;
+
+                if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0)
+                        return -ENOMEM;
+
+                l[q++] = t;
+        }
+
+        return sd_bus_message_append_strv(reply, l);
+}
+
+static int property_get_vconsole(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Context *c = userdata;
+        int r;
+
+        r = vconsole_read_data(c, reply);
+        if (r < 0)
+                return r;
+
+        if (streq(property, "VConsoleKeymap"))
+                return sd_bus_message_append_basic(reply, 's', c->vc_keymap);
+        else if (streq(property, "VConsoleKeymapToggle"))
+                return sd_bus_message_append_basic(reply, 's', c->vc_keymap_toggle);
+
+        return -EINVAL;
+}
+
+static int property_get_xkb(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Context *c = userdata;
+        int r;
+
+        r = x11_read_data(c, reply);
+        if (r < 0)
+                return r;
+
+        if (streq(property, "X11Layout"))
+                return sd_bus_message_append_basic(reply, 's', c->x11_layout);
+        else if (streq(property, "X11Model"))
+                return sd_bus_message_append_basic(reply, 's', c->x11_model);
+        else if (streq(property, "X11Variant"))
+                return sd_bus_message_append_basic(reply, 's', c->x11_variant);
+        else if (streq(property, "X11Options"))
+                return sd_bus_message_append_basic(reply, 's', c->x11_options);
+
+        return -EINVAL;
+}
+
+static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {};
+        _cleanup_strv_free_ char **settings = NULL, **l = NULL;
+        Context *c = userdata;
+        bool modified = false;
+        int interactive, p, r;
+        char **i;
+
+        assert(m);
+        assert(c);
+
+        r = bus_message_read_strv_extend(m, &l);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_basic(m, 'b', &interactive);
+        if (r < 0)
+                return r;
+
+        /* If single locale without variable name is provided, then we assume it is LANG=. */
+        if (strv_length(l) == 1 && !strchr(*l, '=')) {
+                if (!locale_is_valid(*l))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
+
+                new_locale[VARIABLE_LANG] = strdup(*l);
+                if (!new_locale[VARIABLE_LANG])
+                        return -ENOMEM;
+
+                l = strv_free(l);
+        }
+
+        /* Check whether a variable is valid */
+        STRV_FOREACH(i, l) {
+                bool valid = false;
+
+                for (p = 0; p < _VARIABLE_LC_MAX; p++) {
+                        size_t k;
+                        const char *name;
+
+                        name = locale_variable_to_string(p);
+                        assert(name);
+
+                        k = strlen(name);
+                        if (startswith(*i, name) &&
+                            (*i)[k] == '=' &&
+                            locale_is_valid((*i) + k + 1)) {
+                                valid = true;
+
+                                new_locale[p] = strdup((*i) + k + 1);
+                                if (!new_locale[p])
+                                        return -ENOMEM;
+
+                                break;
+                        }
+                }
+
+                if (!valid)
+                        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 (!isempty(new_locale[VARIABLE_LANG]) &&
+            isempty(new_locale[VARIABLE_LANGUAGE])) {
+                _cleanup_free_ char *language = NULL;
+
+                (void) find_language_fallback(new_locale[VARIABLE_LANG], &language);
+                if (language) {
+                        log_debug("Converted LANG=%s to LANGUAGE=%s", new_locale[VARIABLE_LANG], language);
+                        free_and_replace(new_locale[VARIABLE_LANGUAGE], language);
+                }
+        }
+
+        r = locale_read_data(c, m);
+        if (r < 0) {
+                log_error_errno(r, "Failed to read locale data: %m");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read locale data");
+        }
+
+        /* Merge with the current settings */
+        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+                if (!isempty(c->locale[p]) && isempty(new_locale[p])) {
+                        new_locale[p] = strdup(c->locale[p]);
+                        if (!new_locale[p])
+                                return -ENOMEM;
+                }
+
+        locale_simplify(new_locale);
+
+        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+                if (!streq_ptr(c->locale[p], new_locale[p])) {
+                        modified = true;
+                        break;
+                }
+
+        if (!modified) {
+                log_debug("Locale settings were not modified.");
+                return sd_bus_reply_method_return(m, NULL);
+        }
+
+        r = bus_verify_polkit_async(
+                        m,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.locale1.set-locale",
+                        NULL,
+                        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 */
+
+        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+                free_and_replace(c->locale[p], new_locale[p]);
+
+        r = locale_write_data(c, &settings);
+        if (r < 0) {
+                log_error_errno(r, "Failed to set locale: %m");
+                return sd_bus_error_set_errnof(error, r, "Failed to set locale: %m");
+        }
+
+        (void) locale_update_system_manager(c, sd_bus_message_get_bus(m));
+
+        if (settings) {
+                _cleanup_free_ char *line;
+
+                line = strv_join(settings, ", ");
+                log_info("Changed locale to %s.", strnull(line));
+        } else
+                log_info("Changed locale to unset.");
+
+        (void) sd_bus_emit_properties_changed(
+                        sd_bus_message_get_bus(m),
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "Locale", NULL);
+
+        return sd_bus_reply_method_return(m, NULL);
+}
+
+static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        Context *c = userdata;
+        const char *keymap, *keymap_toggle;
+        int convert, interactive, r;
+
+        assert(m);
+        assert(c);
+
+        r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive);
+        if (r < 0)
+                return r;
+
+        keymap = empty_to_null(keymap);
+        keymap_toggle = empty_to_null(keymap_toggle);
+
+        r = vconsole_read_data(c, m);
+        if (r < 0) {
+                log_error_errno(r, "Failed to read virtual console keymap data: %m");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read virtual console keymap data");
+        }
+
+        if (streq_ptr(keymap, c->vc_keymap) &&
+            streq_ptr(keymap_toggle, c->vc_keymap_toggle))
+                return sd_bus_reply_method_return(m, NULL);
+
+        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_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keymap data");
+
+        r = bus_verify_polkit_async(
+                        m,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.locale1.set-keyboard",
+                        NULL,
+                        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 */
+
+        if (free_and_strdup(&c->vc_keymap, keymap) < 0 ||
+            free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0)
+                return -ENOMEM;
+
+        r = vconsole_write_data(c);
+        if (r < 0) {
+                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: %m");
+        }
+
+        log_info("Changed virtual console keymap to '%s' toggle '%s'",
+                 strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
+
+        (void) vconsole_reload(sd_bus_message_get_bus(m));
+
+        (void) sd_bus_emit_properties_changed(
+                        sd_bus_message_get_bus(m),
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "VConsoleKeymap", "VConsoleKeymapToggle", NULL);
+
+        if (convert) {
+                r = vconsole_convert_to_x11_and_emit(c, m);
+                if (r < 0)
+                        log_error_errno(r, "Failed to convert keymap data: %m");
+        }
+
+        return sd_bus_reply_method_return(m, NULL);
+}
+
+#if HAVE_XKBCOMMON
+
+_printf_(3, 0)
+static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
+        const char *fmt;
+
+        fmt = strjoina("libxkbcommon: ", format);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+        log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
+#pragma GCC diagnostic pop
+}
+
+#define LOAD_SYMBOL(symbol, dl, name)                                   \
+        ({                                                              \
+                (symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
+                (symbol) ? 0 : -EOPNOTSUPP;                             \
+        })
+
+static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+
+        /* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
+         * after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
+         * pointers to the shared library are below: */
+
+        struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL;
+        void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL;
+        void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL;
+        struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL;
+        void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL;
+
+        const struct xkb_rule_names rmlvo = {
+                .model          = model,
+                .layout         = layout,
+                .variant        = variant,
+                .options        = options,
+        };
+        struct xkb_context *ctx = NULL;
+        struct xkb_keymap *km = NULL;
+        void *dl;
+        int r;
+
+        /* Compile keymap from RMLVO information to check out its validity */
+
+        dl = dlopen("libxkbcommon.so.0", RTLD_LAZY);
+        if (!dl)
+                return -EOPNOTSUPP;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref");
+        if (r < 0)
+                goto finish;
+
+        ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+        if (!ctx) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        symbol_xkb_context_set_log_fn(ctx, log_xkb);
+
+        km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
+        if (!km) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (symbol_xkb_keymap_unref && km)
+                symbol_xkb_keymap_unref(km);
+
+        if (symbol_xkb_context_unref && ctx)
+                symbol_xkb_context_unref(ctx);
+
+        (void) dlclose(dl);
+        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_message *m, void *userdata, sd_bus_error *error) {
+        Context *c = userdata;
+        const char *layout, *model, *variant, *options;
+        int convert, interactive, r;
+
+        assert(m);
+        assert(c);
+
+        r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive);
+        if (r < 0)
+                return r;
+
+        layout = empty_to_null(layout);
+        model = empty_to_null(model);
+        variant = empty_to_null(variant);
+        options = empty_to_null(options);
+
+        r = x11_read_data(c, m);
+        if (r < 0) {
+                log_error_errno(r, "Failed to read x11 keyboard layout data: %m");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
+        }
+
+        if (streq_ptr(layout, c->x11_layout) &&
+            streq_ptr(model, c->x11_model) &&
+            streq_ptr(variant, c->x11_variant) &&
+            streq_ptr(options, c->x11_options))
+                return sd_bus_reply_method_return(m, NULL);
+
+        if ((layout && !string_is_safe(layout)) ||
+            (model && !string_is_safe(model)) ||
+            (variant && !string_is_safe(variant)) ||
+            (options && !string_is_safe(options)))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keyboard data");
+
+        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));
+
+                if (r == -EOPNOTSUPP)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
+
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
+        }
+
+        r = bus_verify_polkit_async(
+                        m,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.locale1.set-keyboard",
+                        NULL,
+                        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 */
+
+        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 = x11_write_data(c);
+        if (r < 0) {
+                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: %m");
+        }
+
+        log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
+                 strempty(c->x11_layout),
+                 strempty(c->x11_model),
+                 strempty(c->x11_variant),
+                 strempty(c->x11_options));
+
+        (void) sd_bus_emit_properties_changed(
+                        sd_bus_message_get_bus(m),
+                        "/org/freedesktop/locale1",
+                        "org.freedesktop.locale1",
+                        "X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
+
+        if (convert) {
+                r = x11_convert_to_vconsole_and_emit(c, m);
+                if (r < 0)
+                        log_error_errno(r, "Failed to convert keymap data: %m");
+        }
+
+        return sd_bus_reply_method_return(m, NULL);
+}
+
+static const sd_bus_vtable locale_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Locale", "as", property_get_locale, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("X11Layout", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("X11Model", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("X11Variant", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("X11Options", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("VConsoleKeymap", "s", property_get_vconsole, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", property_get_vconsole, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_METHOD("SetLocale", "asb", NULL, method_set_locale, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetVConsoleKeyboard", "ssbb", NULL, method_set_vc_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetX11Keyboard", "ssssbb", NULL, method_set_x11_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_VTABLE_END
+};
+
+static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        assert(c);
+        assert(event);
+        assert(_bus);
+
+        r = sd_bus_default_system(&bus);
+        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)
+                return log_error_errno(r, "Failed to register object: %m");
+
+        r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.locale1", 0, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to request name: %m");
+
+        r = sd_bus_attach_event(bus, event, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach bus to event loop: %m");
+
+        *_bus = TAKE_PTR(bus);
+
+        return 0;
+}
+
+static int run(int argc, char *argv[]) {
+        _cleanup_(context_clear) Context context = {
+                .locale_mtime = USEC_INFINITY,
+                .vc_mtime = USEC_INFINITY,
+                .x11_mtime = USEC_INFINITY,
+        };
+        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        log_setup_service();
+
+        umask(0022);
+        mac_selinux_init();
+
+        if (argc != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+
+        assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+
+        r = sd_event_default(&event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate event loop: %m");
+
+        (void) sd_event_set_watchdog(event, true);
+
+        r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to install SIGINT handler: %m");
+
+        r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to install SIGTERM handler: %m");
+
+        r = connect_bus(&context, event, &bus);
+        if (r < 0)
+                return r;
+
+        r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to run event loop: %m");
+
+        return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff -Naurp elogind-241.3-orig/src/locale/meson.build elogind-241.3/src/locale/meson.build
--- elogind-241.3-orig/src/locale/meson.build	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/meson.build	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
+systemd_localed_sources = files('''
+        localed.c
+        keymap-util.c
+        keymap-util.h
+'''.split())
+
+localectl_sources = files('localectl.c')
+
+if conf.get('ENABLE_LOCALED') == 1
+        install_data('org.freedesktop.locale1.conf',
+                     install_dir : dbuspolicydir)
+        install_data('org.freedesktop.locale1.service',
+                     install_dir : dbussystemservicedir)
+        install_data('org.freedesktop.locale1.policy',
+                     install_dir : polkitpolicydir)
+endif
+
+# If you know a way that allows the same variables to be used
+# in sources list and concatenated to a string for test_env,
+# let me know.
+kbd_model_map = join_paths(meson.current_source_dir(),  'kbd-model-map')
+language_fallback_map = join_paths(meson.current_source_dir(), 'language-fallback-map')
+
+if conf.get('ENABLE_LOCALED') == 1
+        install_data('kbd-model-map',
+                     'language-fallback-map',
+                     install_dir : pkgdatadir)
+endif
+
+tests += [
+        [['src/locale/test-keymap-util.c',
+          'src/locale/keymap-util.c',
+          'src/locale/keymap-util.h'],
+         [libshared],
+         [libdl]],
+]
diff -Naurp elogind-241.3-orig/src/locale/org.freedesktop.locale1.conf elogind-241.3/src/locale/org.freedesktop.locale1.conf
--- elogind-241.3-orig/src/locale/org.freedesktop.locale1.conf	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/org.freedesktop.locale1.conf	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,29 @@
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1+
+
+  This file is part of systemd.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+-->
+
+<busconfig>
+
+        <policy user="root">
+                <allow own="org.freedesktop.locale1"/>
+                <allow send_destination="org.freedesktop.locale1"/>
+                <allow receive_sender="org.freedesktop.locale1"/>
+        </policy>
+
+        <policy context="default">
+                <allow send_destination="org.freedesktop.locale1"/>
+                <allow receive_sender="org.freedesktop.locale1"/>
+        </policy>
+
+</busconfig>
diff -Naurp elogind-241.3-orig/src/locale/org.freedesktop.locale1.policy elogind-241.3/src/locale/org.freedesktop.locale1.policy
--- elogind-241.3-orig/src/locale/org.freedesktop.locale1.policy	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/org.freedesktop.locale1.policy	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1+
+
+  This file is part of systemd.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+        <action id="org.freedesktop.locale1.set-locale">
+                <description gettext-domain="systemd">Set system locale</description>
+                <message gettext-domain="systemd">Authentication is required to set the system locale.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.locale1.set-keyboard</annotate>
+        </action>
+
+        <action id="org.freedesktop.locale1.set-keyboard">
+                <description gettext-domain="systemd">Set system keyboard settings</description>
+                <message gettext-domain="systemd">Authentication is required to set the system keyboard settings.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+</policyconfig>
diff -Naurp elogind-241.3-orig/src/locale/org.freedesktop.locale1.service elogind-241.3/src/locale/org.freedesktop.locale1.service
--- elogind-241.3-orig/src/locale/org.freedesktop.locale1.service	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/org.freedesktop.locale1.service	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,14 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[D-BUS Service]
+Name=org.freedesktop.locale1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.locale1.service
diff -Naurp elogind-241.3-orig/src/locale/test-keymap-util.c elogind-241.3/src/locale/test-keymap-util.c
--- elogind-241.3-orig/src/locale/test-keymap-util.c	1969-12-31 18:00:00.000000000 -0600
+++ elogind-241.3/src/locale/test-keymap-util.c	2019-08-25 11:57:50.514075230 -0500
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "keymap-util.h"
+#include "log.h"
+#include "string-util.h"
+
+static void test_find_language_fallback(void) {
+        _cleanup_free_ char *ans = NULL, *ans2 = NULL;
+
+        log_info("/*** %s ***/", __func__);
+
+        assert_se(find_language_fallback("foobar", &ans) == 0);
+        assert_se(ans == NULL);
+
+        assert_se(find_language_fallback("csb", &ans) == 0);
+        assert_se(ans == NULL);
+
+        assert_se(find_language_fallback("csb_PL", &ans) == 1);
+        assert_se(streq(ans, "csb:pl"));
+
+        assert_se(find_language_fallback("szl_PL", &ans2) == 1);
+        assert_se(streq(ans2, "szl:pl"));
+}
+
+static void test_find_converted_keymap(void) {
+        _cleanup_free_ char *ans = NULL, *ans2 = NULL;
+        int r;
+
+        log_info("/*** %s ***/", __func__);
+
+        assert_se(find_converted_keymap("pl", "foobar", &ans) == 0);
+        assert_se(ans == NULL);
+
+        r = find_converted_keymap("pl", NULL, &ans);
+        if (r == 0) {
+                log_info("Skipping rest of %s: keymaps are not installed", __func__);
+                return;
+        }
+
+        assert_se(r == 1);
+        assert_se(streq(ans, "pl"));
+
+        assert_se(find_converted_keymap("pl", "dvorak", &ans2) == 1);
+        assert_se(streq(ans2, "pl-dvorak"));
+}
+
+static void test_find_legacy_keymap(void) {
+        Context c = {};
+        _cleanup_free_ char *ans = NULL, *ans2 = NULL;
+
+        log_info("/*** %s ***/", __func__);
+
+        c.x11_layout = (char*) "foobar";
+        assert_se(find_legacy_keymap(&c, &ans) == 0);
+        assert_se(ans == NULL);
+
+        c.x11_layout = (char*) "pl";
+        assert_se(find_legacy_keymap(&c, &ans) == 1);
+        assert_se(streq(ans, "pl2"));
+
+        c.x11_layout = (char*) "pl,ru";
+        assert_se(find_legacy_keymap(&c, &ans2) == 1);
+        assert_se(streq(ans, "pl2"));
+}
+
+static void test_vconsole_convert_to_x11(void) {
+        _cleanup_(context_clear) Context c = {};
+
+        log_info("/*** %s ***/", __func__);
+
+        log_info("/* test emptying first (:) */");
+        assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0);
+        assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0);
+        assert_se(vconsole_convert_to_x11(&c) == 1);
+        assert_se(c.x11_layout == NULL);
+        assert_se(c.x11_variant == NULL);
+
+        log_info("/* test emptying second (:) */");
+
+        assert_se(vconsole_convert_to_x11(&c) == 0);
+        assert_se(c.x11_layout == NULL);
+        assert_se(c.x11_variant == NULL);
+
+        log_info("/* test without variant, new mapping (es:) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "es") >= 0);
+
+        assert_se(vconsole_convert_to_x11(&c) == 1);
+        assert_se(streq(c.x11_layout, "es"));
+        assert_se(c.x11_variant == NULL);
+
+        log_info("/* test with known variant, new mapping (es:dvorak) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "es-dvorak") >= 0);
+
+        assert_se(vconsole_convert_to_x11(&c) == 0); // FIXME
+        assert_se(streq(c.x11_layout, "es"));
+        assert_se(c.x11_variant == NULL); // FIXME: "dvorak"
+
+        log_info("/* test with old mapping (fr:latin9) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "fr-latin9") >= 0);
+
+        assert_se(vconsole_convert_to_x11(&c) == 1);
+        assert_se(streq(c.x11_layout, "fr"));
+        assert_se(streq(c.x11_variant, "latin9"));
+
+        log_info("/* test with a compound mapping (ru,us) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "ru") >= 0);
+
+        assert_se(vconsole_convert_to_x11(&c) == 1);
+        assert_se(streq(c.x11_layout, "ru,us"));
+        assert_se(c.x11_variant == NULL);
+
+        log_info("/* test with a simple mapping (us) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "us") >= 0);
+
+        assert_se(vconsole_convert_to_x11(&c) == 1);
+        assert_se(streq(c.x11_layout, "us"));
+        assert_se(c.x11_variant == NULL);
+}
+
+static void test_x11_convert_to_vconsole(void) {
+        _cleanup_(context_clear) Context c = {};
+        int r;
+
+        log_info("/*** %s ***/", __func__);
+
+        log_info("/* test emptying first (:) */");
+        assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0);
+        assert_se(x11_convert_to_vconsole(&c) == 1);
+        assert_se(c.vc_keymap == NULL);
+
+        log_info("/* test emptying second (:) */");
+
+        assert_se(x11_convert_to_vconsole(&c) == 0);
+        assert_se(c.vc_keymap == NULL);
+
+        log_info("/* test without variant, new mapping (es:) */");
+        assert_se(free_and_strdup(&c.x11_layout, "es") >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 1);
+        assert_se(streq(c.vc_keymap, "es"));
+
+        log_info("/* test with unknown variant, new mapping (es:foobar) */");
+        assert_se(free_and_strdup(&c.x11_variant, "foobar") >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 0);
+        assert_se(streq(c.vc_keymap, "es"));
+
+        log_info("/* test with known variant, new mapping (es:dvorak) */");
+        assert_se(free_and_strdup(&c.x11_variant, "dvorak") >= 0);
+
+        r = x11_convert_to_vconsole(&c);
+        if (r == 0) {
+                log_info("Skipping rest of %s: keymaps are not installed", __func__);
+                return;
+        }
+
+        assert_se(r == 1);
+        assert_se(streq(c.vc_keymap, "es-dvorak"));
+
+        log_info("/* test with old mapping (fr:latin9) */");
+        assert_se(free_and_strdup(&c.x11_layout, "fr") >= 0);
+        assert_se(free_and_strdup(&c.x11_variant, "latin9") >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 1);
+        assert_se(streq(c.vc_keymap, "fr-latin9"));
+
+        log_info("/* test with a compound mapping (us,ru:) */");
+        assert_se(free_and_strdup(&c.x11_layout, "us,ru") >= 0);
+        assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 1);
+        assert_se(streq(c.vc_keymap, "us"));
+
+        log_info("/* test with a compound mapping (ru,us:) */");
+        assert_se(free_and_strdup(&c.x11_layout, "ru,us") >= 0);
+        assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 1);
+        assert_se(streq(c.vc_keymap, "ru"));
+
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1333998 */
+        log_info("/* test with a simple new mapping (ru:) */");
+        assert_se(free_and_strdup(&c.x11_layout, "ru") >= 0);
+        assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
+
+        assert_se(x11_convert_to_vconsole(&c) == 0);
+        assert_se(streq(c.vc_keymap, "ru"));
+}
+
+int main(int argc, char **argv) {
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+
+        test_find_language_fallback();
+        test_find_converted_keymap();
+        test_find_legacy_keymap();
+
+        test_vconsole_convert_to_x11();
+        test_x11_convert_to_vconsole();
+
+        return 0;
+}
diff -Naurp elogind-241.3-orig/src/shared/bus-util.c elogind-241.3/src/shared/bus-util.c
--- elogind-241.3-orig/src/shared/bus-util.c	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/src/shared/bus-util.c	2019-08-25 12:16:39.428716039 -0500
@@ -37,7 +37,6 @@
 #include "strv.h"
 #include "user-util.h"
 
-#if 0 /// UNNEEDED by elogind
 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         sd_event *e = userdata;
 
@@ -161,7 +160,6 @@ int bus_event_loop_with_idle(
 
         return code;
 }
-#endif // 0
 
 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
diff -Naurp elogind-241.3-orig/src/shared/bus-util.h elogind-241.3/src/shared/bus-util.h
--- elogind-241.3-orig/src/shared/bus-util.h	2019-04-25 01:00:28.000000000 -0500
+++ elogind-241.3/src/shared/bus-util.h	2019-08-25 12:12:11.875588649 -0500
@@ -43,15 +43,11 @@ int bus_message_map_all_properties(sd_bu
 int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map,
                            unsigned flags, sd_bus_error *error, sd_bus_message **reply, void *userdata);
 
-#if 0 /// UNNEEDED by elogind
 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
-#endif // 0
 
 typedef bool (*check_idle_t)(void *userdata);
 
-#if 0 /// UNNEEDED by elogind
 int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout, check_idle_t check_idle, void *userdata);
-#endif // 0
 
 int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
 
