1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers This file is part of systemd.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Copyright 2011 Lennart Poettering
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers Copyright 2013 Kay Sievers
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers (at your option) any later version.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers systemd is distributed in the hope that it will be useful, but
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* We don't list LC_ALL here on purpose. People should be
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers * using LANG instead. */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmekstatic const char* nonempty(const char *s) {
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmekstatic bool startswith_comma(const char *s, const char *prefix) {
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek return s && (t = startswith(s, prefix)) && (*t == ',');
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++)
36e34057a202d389263e98030fbd775b28b28af6Stef Walter bus_verify_polkit_async_registry_free(c->polkit_registry);
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p]))
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE],
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT],
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION],
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* Fill in what we got passed from systemd. */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++) {
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek r = free_and_strdup(&c->locale[p],
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = parse_env_file("/etc/vconsole.conf", NEWLINE,
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0 && r != -ENOENT)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (l[0] == 0 || l[0] == '#')
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers } else if (!in_section && first_word(l, "Section")) {
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (strv_length(a) == 2 && streq(a[1], "InputClass"))
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers } else if (in_section && first_word(l, "EndSection"))
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers int r, q, p;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers return r < 0 ? r : q < 0 ? q : p;
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmekstatic int locale_write_data(Context *c, char ***settings) {
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek /* Set values will be returned as strv in *settings on success. */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = load_env_file(NULL, "/etc/locale.conf", NULL, &l);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0 && r != -ENOENT)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++) {
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0)
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek r = write_env_file_label("/etc/locale.conf", l);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic int locale_update_system_manager(Context *c, sd_bus *bus) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0)
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering r = sd_bus_message_new_method_call(bus, &m,
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "org.freedesktop.systemd1.Manager",
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering "UnsetAndSetEnvironment");
c49b30a23583ff39daaa26696bcab478d2fee0bbLennart Poettering r = sd_bus_call(bus, m, 0, &error, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to update the manager environment: %m");
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0 && r != -ENOENT)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle);
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek return write_env_file_label("/etc/vconsole.conf", l);
e78af5ffe53a0d24854d721d1166a60f8ed0dfb6Zbigniew Jędrzejewski-Szmekstatic int x11_write_data(Context *c) {
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *temp_path = NULL;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
9a9bb3ca1eddc8caa2d7aa3e6e27d270e296923fMichał Bartoszkiewicz mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers "# manually too freely.\n"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers "Section \"InputClass\"\n"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers " Identifier \"system-keyboard\"\n"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers " MatchIsKeyboard \"on\"\n", f);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers "org.freedesktop.systemd1.Manager",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "RestartUnit",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "ss", "systemd-vconsole-setup.service", "replace");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmekstatic const char* strnulldash(const char *s) {
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek return isempty(s) || streq(s, "-") ? NULL : s;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmekstatic int read_next_mapping(const char* filename,
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek unsigned min_fields, unsigned max_fields,
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek FILE *f, unsigned *n, char ***a) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers char *l, **b;
f5e5c28f42a2f6d006785ec8b5e98c11a71bb039Zbigniew Jędrzejewski-Szmek return errno > 0 ? -errno : -EIO;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (l[0] == 0 || l[0] == '#')
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek if (length < min_fields || length > max_fields) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek log_error("Invalid line %s:%u, ignoring.", filename, *n);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers unsigned n = 0;
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek if (!streq(c->vc_keymap, a[0]))
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (!streq_ptr(c->x11_layout, strnulldash(a[1])) ||
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers !streq_ptr(c->x11_variant, strnulldash(a[3])) ||
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers !streq_ptr(c->x11_options, strnulldash(a[4]))) {
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to set X11 keyboard layout: %m");
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers "org.freedesktop.locale1",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_debug("X11 keyboard layout was not modified.");
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmekstatic int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) {
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek n = strjoin(x11_layout, "-", x11_variant, NULL);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *p = NULL, *pz = NULL;
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek p = strjoin(dir, "xkb/", n, ".map", NULL);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek pz = strjoin(dir, "xkb/", n, ".map.gz", NULL);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek uncompressed = access(p, F_OK) == 0;
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek if (uncompressed || access(pz, F_OK) == 0) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_debug("Found converted keymap %s at %s",
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmekstatic int find_legacy_keymap(Context *c, char **new_keymap) {
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* Determine how well matching this entry is */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek if (streq_ptr(c->x11_layout, a[1]))
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* If we got an exact match, this is best */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* We have multiple X layouts, look for an
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek * entry that matches our key with everything
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek * but the first layout stripped off. */
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek if (startswith_comma(c->x11_layout, a[1]))
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* If that didn't work, strip off the
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek * other layouts from the entry, too */
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek x = strndupa(a[1], strcspn(a[1], ","));
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek if (startswith_comma(c->x11_layout, x))
387066c2e5bda159201896b194711965b52f34a9Michal Sekletar if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) {
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* The best matching entry so far, then let's save that */
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek if (matching >= MAX(best_matching, 1u)) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_debug("Found legacy keymap %s with score %u",
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek if (matching > best_matching) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek r = free_and_strdup(new_keymap, a[0]);
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek if (best_matching < 10 && c->x11_layout) {
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek /* The best match is only the first part of the X11
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek * keymap. Check if we have a converted map which
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek * matches just the first layout.
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek char *l, *v = NULL, *converted;
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek l = strndupa(c->x11_layout, strcspn(c->x11_layout, ","));
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek v = strndupa(c->x11_variant, strcspn(c->x11_variant, ","));
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek r = find_converted_keymap(l, v, &converted);
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack if (r > 0) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmekstatic int find_language_fallback(const char *lang, char **language) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re");
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek assert_not_reached("should not be here");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek else if (r == 0) {
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek r = find_legacy_keymap(c, &new_keymap);
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to set virtual console keymap: %m");
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed virtual console keymap to '%s' toggle '%s'",
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers "org.freedesktop.locale1",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "VConsoleKeymap", "VConsoleKeymapToggle", NULL);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_debug("Virtual console keymap was not modified.");
b47d419c25ecc735615a1088060c1ec8bef1e41fZbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0, q = 0; p < _LOCALE_MAX; p++) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers r = sd_bus_message_read_basic(m, 'b', &interactive);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek /* Check whether a variable changed and if it is valid */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers (*i)[k] == '=' &&
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek /* If LANG was specified, but not LANGUAGE, check if we should
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * set it based on the language fallback table. */
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek if (have[LOCALE_LANG] && !have[LOCALE_LANGUAGE]) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *language = NULL;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek (void) find_language_fallback(lang, &language);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek log_debug("Converted LANG=%s to LANGUAGE=%s", lang, language);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek if (!streq_ptr(language, c->locale[LOCALE_LANGUAGE])) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek r = strv_extendf(&l, "LANGUAGE=%s", language);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* Check whether a variable is unset */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++)
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek if (!isempty(c->locale[p]) && !have[p]) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **settings = NULL;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (startswith(*i, names[p]) && (*i)[k] == '=') {
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek r = free_and_strdup(&c->locale[p], *i + k + 1);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (p = 0; p < _LOCALE_MAX; p++) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek r = locale_write_data(c, &settings);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to set locale: %m");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering locale_update_system_manager(c, sd_bus_message_get_bus(m));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek line = strv_join(settings, ", ");
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed locale to %s.", strnull(line));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed locale to unset.");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "org.freedesktop.locale1",
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_debug("Locale settings were not modified.");
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering return sd_bus_reply_method_return(m, NULL);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers !streq_ptr(keymap_toggle, c->vc_keymap_toggle)) {
ae6c3cc009a21df4b51851fb8fe3fde0b7d6d8f0Lennart Poettering if ((keymap && (!filename_is_valid(keymap) || !string_is_safe(keymap))) ||
ae6c3cc009a21df4b51851fb8fe3fde0b7d6d8f0Lennart Poettering (keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle))))
d14ab08b29d5b0b3ead6e63ac8be472f273011f9Lennart Poettering return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if (free_and_strdup(&c->vc_keymap, keymap) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to set virtual console keymap: %m");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed virtual console keymap to '%s' toggle '%s'",
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = vconsole_reload(sd_bus_message_get_bus(m));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to request keymap reload: %m");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "org.freedesktop.locale1",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "VConsoleKeymap", "VConsoleKeymapToggle", NULL);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = vconsole_convert_to_x11(c, sd_bus_message_get_bus(m));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to convert keymap data: %m");
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering return sd_bus_reply_method_return(m, NULL);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmannstatic void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering fmt = strjoina("libxkbcommon: ", format);
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmannstatic int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann /* compile keymap from RMLVO information to check out its validity */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmannstatic int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive);
d14ab08b29d5b0b3ead6e63ac8be472f273011f9Lennart Poettering return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
8623d3a3b2e3463fa6e4ded734323483540c3ed4David Herrmann r = verify_xkb_rmlvo(model, layout, variant, options);
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek if (r < 0) {
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek strempty(model), strempty(layout), strempty(variant), strempty(options));
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if (free_and_strdup(&c->x11_layout, layout) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_model, model) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_variant, variant) < 0 ||
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek free_and_strdup(&c->x11_options, options) < 0)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to set X11 keyboard layout: %m");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers "org.freedesktop.locale1",
c168eb6785bacc2042687bf879259dfc27d5a523David Herrmann "X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = x11_convert_to_vconsole(c, sd_bus_message_get_bus(m));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to convert keymap data: %m");
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering return sd_bus_reply_method_return(m, NULL);
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("Locale", "as", property_get_locale, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("X11Layout", "s", NULL, offsetof(Context, x11_layout), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("X11Model", "s", NULL, offsetof(Context, x11_model), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("X11Variant", "s", NULL, offsetof(Context, x11_variant), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("X11Options", "s", NULL, offsetof(Context, x11_options), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("VConsoleKeymap", "s", NULL, offsetof(Context, vc_keymap), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6d1bd3b2bbae29dbd3862fdb9af2b472b01c480eLennart Poettering SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", NULL, offsetof(Context, vc_keymap_toggle), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering SD_BUS_METHOD("SetLocale", "asb", NULL, method_set_locale, SD_BUS_VTABLE_UNPRIVILEGED),
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering SD_BUS_METHOD("SetVConsoleKeyboard", "ssbb", NULL, method_set_vc_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering SD_BUS_METHOD("SetX11Keyboard", "ssssbb", NULL, method_set_x11_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to get system bus connection: %m");
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to register object: %m");
5bb658a1784a0fd4f0f32adb4b1fb636ff503f7dKay Sievers r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to register name: %m");
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to attach bus to event loop: %m");
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek _cleanup_(context_free) Context context = {};
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_event_unrefp) sd_event *event = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to allocate event loop: %m");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to read locale data: %m");
37224a5ff522a366b353e8a01e2c2eee1e5416e5Lennart Poettering r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to run event loop: %m");