localectl.c revision 63229aa1abdb98aa69fda9819ed2f40c8082762b
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt Copyright 2012 Lennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Copyright 2013 Kay Sievers
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstatic bool arg_no_pager = false;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstatic bool arg_ask_password = true;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flyktstatic bool arg_convert = true;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic void pager_open_if_enabled(void) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic void polkit_agent_open_if_enabled(void) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Open the polkit agent as a child process if necessary */
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykttypedef struct StatusInfo {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic void print_overriden_variables(void) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = parse_env_file("/proc/cmdline", WHITESPACE,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_TIME", &variables[VARIABLE_LC_TIME],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_NAME", &variables[VARIABLE_LC_NAME],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt if (r < 0 && r != -ENOENT) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt for (j = 0; j < _VARIABLE_LC_MAX; j++)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt printf("Warning: Settings on Kernel Command Line override system locale settings in /etc/locale.conf\n");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt printf(" Command Line: %s=%s\n", locale_variable_to_string(j), variables[j]);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt printf(" %s=%s\n", locale_variable_to_string(j), variables[j]);
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt for (j = 0; j < _VARIABLE_LC_MAX; j++)
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams printf(" X11 Layout: %s\n", strna(i->x11_layout));
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstatic int show_status(sd_bus *bus, char **args, unsigned n) {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams static const struct bus_properties_map map[] = {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) },
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) },
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt { "VConsoleKeymapToggle", "s", NULL, offsetof(StatusInfo, vconsole_keymap_toggle) },
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt { "X11Layout", "s", NULL, offsetof(StatusInfo, x11_layout) },
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering { "X11Model", "s", NULL, offsetof(StatusInfo, x11_model) },
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller { "X11Variant", "s", NULL, offsetof(StatusInfo, x11_variant) },
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller { "X11Options", "s", NULL, offsetof(StatusInfo, x11_options) },
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering { "Locale", "as", NULL, offsetof(StatusInfo, locale) },
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams "org.freedesktop.locale1",
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt if (r < 0) {
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt log_error("Could not get properties: %s", strerror(-r));
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersenstatic int set_locale(sd_bus *bus, char **args, unsigned n) {
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen "org.freedesktop.locale1",
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams "org.freedesktop.locale1",
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams "SetLocale");
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = sd_bus_message_append(m, "b", arg_ask_password);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (r < 0) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int list_locales(sd_bus *bus, char **args, unsigned n) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (r < 0) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt log_error("Failed to read list of locales: %s", strerror(-r));
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int set_vconsole_keymap(sd_bus *bus, char **args, unsigned n) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (n > 3) {
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt "org.freedesktop.locale1",
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt "org.freedesktop.locale1",
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt "SetVConsoleKeyboard",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt "ssbb", map, toggle_map, arg_convert, arg_ask_password);
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt char *p, *e;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0 && r != -EEXIST) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt log_error("Can't add keymap: %s", strerror(-r));
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flyktstatic int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *dir;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_error("Couldn't find any console keymaps.");
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flyktstatic int set_x11_keymap(sd_bus *bus, char **args, unsigned n) {
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen const char *layout, *model, *variant, *options;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (n > 5) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt "org.freedesktop.locale1",
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt "org.freedesktop.locale1",
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt "SetX11Keyboard",
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flyktstatic int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (n > 2) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt log_error("Failed to open keyboard mapping list. %m");
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt else if (streq(args[0], "list-x11-keymap-layouts"))
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt else if (streq(args[0], "list-x11-keymap-variants"))
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt else if (streq(args[0], "list-x11-keymap-options"))
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt char *l, *w;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (l[0] == '!') {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (n > 1) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (*w == 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic void help(void) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt "Query or change system locale and keyboard settings.\n\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " -h --help Show this help\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " --version Show package version\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " --no-pager Do not pipe output into a pager\n"
4b4923e65423e60d755841b5b264730e8f3deab3Tom Gundersen " --no-ask-password Do not prompt for password\n"
5e91345094a9e983e7abb2313334e7808bcd2cc2Tom Gundersen " -H --host=[USER@]HOST Operate on remote host\n"
513a6fa8679510ea1b55967bdb482dd5f8a39f21Ronny Chevalier " -M --machine=CONTAINER Operate on local container\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " --no-convert Don't convert keyboard mappings\n\n"
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt "Commands:\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " status Show current locale settings\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " set-locale LOCALE... Set system locale\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " list-locales Show known locales\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " set-keymap MAP [MAP] Set virtual console keyboard mapping\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " list-keymaps Show known virtual console keyboard mappings\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS]\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " Set X11 keyboard mapping\n"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt " list-x11-keymap-models Show known X11 keyboard mapping models\n"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt " list-x11-keymap-layouts Show known X11 keyboard mapping layouts\n"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt " list-x11-keymap-variants [LAYOUT]\n"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt " Show known X11 keyboard mapping variants\n"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt " list-x11-keymap-options Show known X11 keyboard mapping options\n"
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt { "no-pager", no_argument, NULL, ARG_NO_PAGER },
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt { "no-convert", no_argument, NULL, ARG_NO_CONVERT },
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt switch (c) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int localectl_main(sd_bus *bus, int argc, char *argv[]) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt static const struct {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt const char* verb;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt const enum {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "set-keymap", MORE, 2, set_vconsole_keymap },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "list-keymaps", EQUAL, 1, list_vconsole_keymaps },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "list-x11-keymap-models", EQUAL, 1, list_x11_keymaps },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "list-x11-keymap-layouts", EQUAL, 1, list_x11_keymaps },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "list-x11-keymap-variants", LESS, 2, list_x11_keymaps },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt { "list-x11-keymap-options", EQUAL, 1, list_x11_keymaps },
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* Special rule: no arguments means "status" */
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen log_error("Unknown operation %s", argv[optind]);
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek assert_not_reached("Unknown comparison operator.");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return verbs[i].dispatch(bus, argv + optind, left);
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmekint main(int argc, char*argv[]) {
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek _cleanup_bus_close_unref_ sd_bus *bus = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = bus_open_transport(arg_transport, arg_host, false, &bus);
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams if (r < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Failed to create bus connection: %s", strerror(-r));