localed.c revision 6203e07a83214a55bb1f88508fcda2005c601dea
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek This file is part of systemd.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek Copyright 2011 Lennart Poettering
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek Copyright 2013 Kay Sievers
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek (at your option) any later version.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2cf4172a71860c6e44edd27a3b68047ae062d7fcLennart Poettering /* We don't list LC_ALL here on purpose. People should be
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek * using LANG instead. */
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic const char * const names[_LOCALE_MAX] = {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek [LOCALE_LC_NUMERIC] = "LC_NUMERIC",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek [LOCALE_LC_COLLATE] = "LC_COLLATE",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek [LOCALE_LC_MONETARY] = "LC_MONETARY",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek [LOCALE_LC_MESSAGES] = "LC_MESSAGES",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek [LOCALE_LC_ADDRESS] = "LC_ADDRESS",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int free_and_copy(char **s, const char *v) {
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek r = strdup_or_null(isempty(v) ? NULL : v, &t);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidtstatic void free_and_replace(char **s, char *v) {
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmekstatic void context_free_x11(Context *c) {
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_layout, NULL);
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_model, NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_variant, NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_options, NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic void context_free_vconsole(Context *c) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek free_and_replace(&c->vc_keymap, NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek free_and_replace(&c->vc_keymap_toggle, NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic void context_free_locale(Context *c) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek for (p = 0; p < _LOCALE_MAX; p++)
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek free_and_replace(&c->locale[p], NULL);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic void context_free(Context *c, sd_bus *bus) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic void locale_simplify(Context *c) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++)
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekstatic int locale_read_data(Context *c) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek r = parse_env_file("/etc/locale.conf", NEWLINE,
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LANG", &c->locale[LOCALE_LANG],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LANGUAGE", &c->locale[LOCALE_LANGUAGE],
36d4739a68c3edafe4d145d525a26de4ef0b8e5aZbigniew Jędrzejewski-Szmek "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE],
36d4739a68c3edafe4d145d525a26de4ef0b8e5aZbigniew Jędrzejewski-Szmek "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC],
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY],
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES],
36d4739a68c3edafe4d145d525a26de4ef0b8e5aZbigniew Jędrzejewski-Szmek "LC_PAPER", &c->locale[LOCALE_LC_PAPER],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LC_NAME", &c->locale[LOCALE_LC_NAME],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT],
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION],
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek /* Fill in what we got passed from systemd. */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (p = 0; p < _LOCALE_MAX; p++) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = free_and_copy(&c->locale[p], getenv(names[p]));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int vconsole_read_data(Context *c) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = parse_env_file("/etc/vconsole.conf", NEWLINE,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "KEYMAP_TOGGLE", &c->vc_keymap_toggle,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int x11_read_data(Context *c) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek return errno == ENOENT ? 0 : -errno;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek while (fgets(line, sizeof(line), f)) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (l[0] == 0 || l[0] == '#')
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (in_section && first_word(l, "Option")) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_layout, a[2]);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek } else if (streq(a[1], "XkbModel")) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_model, a[2]);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek } else if (streq(a[1], "XkbVariant")) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_variant, a[2]);
799a8f39d8eb9ea725e85a598c0f5dbd658c8ba7Zbigniew Jędrzejewski-Szmek } else if (streq(a[1], "XkbOptions")) {
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek free_and_replace(&c->x11_options, a[2]);
8847551bcbfa8265bae04f567bb1aadc7b480325Zbigniew Jędrzejewski-Szmek } else if (!in_section && first_word(l, "Section")) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (strv_length(a) == 2 && streq(a[1], "InputClass"))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek } else if (in_section && first_word(l, "EndSection"))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int context_read_data(Context *c) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek return r < 0 ? r : q < 0 ? q : p;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int locale_write_data(Context *c) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = load_env_file("/etc/locale.conf", NULL, &l);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (p = 0; p < _LOCALE_MAX; p++) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek l = strv_env_unset(l, names[p]);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (unlink("/etc/locale.conf") < 0)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek return errno == ENOENT ? 0 : -errno;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = write_env_file_label("/etc/locale.conf", l);
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmekstatic int locale_update_system_manager(Context *c, sd_bus *bus) {
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek _cleanup_free_ char **l_unset = NULL;
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l_set = NULL;
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek sd_bus_error error = SD_BUS_ERROR_NULL;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek l_unset = new0(char*, _LOCALE_MAX);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek l_set = new0(char*, _LOCALE_MAX);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek l_unset[c_set++] = (char*) names[p];
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "UnsetAndSetEnvironment", &m);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_bus_message_append_strv(m, l_unset);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek r = sd_bus_message_append_strv(m, l_set);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek r = sd_bus_call(bus, m, 0, &error, NULL);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek log_error("Failed to update the manager environment: %s", strerror(-r));
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmekstatic int vconsole_write_data(Context *c) {
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek r = load_env_file("/etc/vconsole.conf", NULL, &l);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT)
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek l = strv_env_unset(l, "KEYMAP");
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek s = strappend("KEYMAP=", c->vc_keymap);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (isempty(c->vc_keymap_toggle))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek l = strv_env_unset(l, "KEYMAP_TOGGLE");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle);
50a0b0717563d08c027a16a896bff8d7754eab9eZbigniew Jędrzejewski-Szmek if (unlink("/etc/vconsole.conf") < 0)
50a0b0717563d08c027a16a896bff8d7754eab9eZbigniew Jędrzejewski-Szmek return errno == ENOENT ? 0 : -errno;
5bc891206dd8eb4e4df58f502b0184b8426caf22Zbigniew Jędrzejewski-Szmek r = write_env_file_label("/etc/vconsole.conf", l);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int write_data_x11(Context *c) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek return errno == ENOENT ? 0 : -errno;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "# manually too freely.\n"
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "Section \"InputClass\"\n"
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek " Identifier \"system-keyboard\"\n"
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek " MatchIsKeyboard \"on\"\n", f);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options);
30776485c5bc2d9c356e875f2aee874d22c393b7Zbigniew Jędrzejewski-Szmek if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int vconsole_reload(sd_bus *bus) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "ss", "systemd-vconsole-setup.service", "replace");
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic char *strnulldash(const char *s) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s;
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmekstatic int read_next_mapping(FILE *f, unsigned *n, char ***a) {
bf257aed057efd113f1b84e037fde09ffeed32eeJosh Triplett char *l, **b;
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek if (!fgets(line, sizeof(line), f)) {
1af719edc5958c01c19204fb68d6fc45c9eea85cZbigniew Jędrzejewski-Szmek if (l[0] == 0 || l[0] == '#')
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = read_next_mapping(f, &n, &a);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (!streq_ptr(c->x11_layout, strnulldash(a[1])) ||
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek !streq_ptr(c->x11_model, strnulldash(a[2])) ||
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek !streq_ptr(c->x11_variant, strnulldash(a[3])) ||
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek !streq_ptr(c->x11_options, strnulldash(a[4]))) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (free_and_copy(&c->x11_layout, strnulldash(a[1])) < 0 ||
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek free_and_copy(&c->x11_model, strnulldash(a[2])) < 0 ||
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek free_and_copy(&c->x11_variant, strnulldash(a[3])) < 0 ||
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek free_and_copy(&c->x11_options, strnulldash(a[4])) < 0)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek sd_bus_emit_properties_changed(bus,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "org.freedesktop.locale1",
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek "X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmekstatic int find_converted_keymap(Context *c, char **new_keymap) {
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek n = strjoin(c->x11_layout, "-", c->x11_variant, NULL);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *p = NULL, *pz = NULL;
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek p = strjoin(dir, "xkb/", n, ".map", NULL);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek pz = strjoin(dir, "xkb/", n, ".map.gz", NULL);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int find_legacy_keymap(Context *c, char **new_keymap) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **a = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = read_next_mapping(f, &n, &a);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* Determine how well matching this entry is */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (streq_ptr(c->x11_layout, a[1]))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* If we got an exact match, this is best */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek x = strcspn(c->x11_layout, ",");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* We have multiple X layouts, look for an
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek * entry that matches our key with everything
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek * but the first layout stripped off. */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* If that didn't work, strip off the
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek * other layouts from the entry, too */
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (x > 0 && x == w &&
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek memcmp(c->x11_layout, a[1], x) == 0)
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek /* The best matching entry so far, then let's save that */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = find_converted_keymap(c, &new_keymap);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek else if (r == 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = find_legacy_keymap(c, &new_keymap);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (!streq_ptr(c->vc_keymap, new_keymap)) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek free_and_replace(&c->vc_keymap, new_keymap);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek free_and_replace(&c->vc_keymap_toggle, NULL);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_error("Failed to set virtual console keymap: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek sd_bus_emit_properties_changed(bus,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "org.freedesktop.locale1",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "VConsoleKeymap", "VConsoleKeymapToggle", NULL);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek for (p = 0, q = 0; p < _LOCALE_MAX; p++) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0)
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek return sd_bus_message_append_strv(reply, l);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek _cleanup_strv_free_ char **l = NULL;
36d4739a68c3edafe4d145d525a26de4ef0b8e5aZbigniew Jędrzejewski-Szmek r = bus_message_read_strv_extend(m, &l);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_bus_message_read_basic(m, 'b', &interactive);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek /* Check whether a variable changed and if so valid */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (p = 0; p < _LOCALE_MAX; p++) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (*i)[k] == '=' &&
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (!streq_ptr(*i + k + 1, c->locale[p]))
af4ec4309e8f82aad87a8d574785c12f8763d5f8Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
af4ec4309e8f82aad87a8d574785c12f8763d5f8Lennart Poettering /* Check whether a variable is unset */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (p = 0; p < _LOCALE_MAX; p++)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (!isempty(c->locale[p]) && !passed[p]) {
if (modified) {
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
STRV_FOREACH(i, l) {
for (p = 0; p < _LOCALE_MAX; p++) {
size_t k;
return -ENOMEM;
c->locale[p] = t;
for (p = 0; p < _LOCALE_MAX; p++) {
if (passed[p])
locale_simplify(c);
r = locale_write_data(c);
"/org/freedesktop/locale1",
static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
"org.freedesktop.locale1.set-keyboard",
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
return -ENOMEM;
r = vconsole_write_data(c);
"/org/freedesktop/locale1",
if (convert) {
static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
"org.freedesktop.locale1.set-keyboard",
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
return -ENOMEM;
r = write_data_x11(c);
"/org/freedesktop/locale1",
if (convert) {
SD_BUS_PROPERTY("X11Layout", "s", NULL, offsetof(Context, x11_layout), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Model", "s", NULL, offsetof(Context, x11_model), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Variant", "s", NULL, offsetof(Context, x11_variant), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Options", "s", NULL, offsetof(Context, x11_options), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("VConsoleKeymap", "s", NULL, offsetof(Context, vc_keymap), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", NULL, offsetof(Context, vc_keymap_toggle), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
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),
assert(c);
r = sd_bus_add_object_vtable(bus, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
log_open();
r = -EINVAL;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;