localectl.c revision 7ca7021a9e0c443d40d0af5e9a7e1962d8032229
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering This file is part of systemd.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2012 Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (at your option) any later version.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is distributed in the hope that it will be useful, but
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Lesser General Public License for more details.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic bool arg_no_pager = false;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic bool arg_ask_password = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic bool arg_convert = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic void pager_open_if_enabled(void) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Open the polkit agent as a child process if necessary */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringtypedef struct StatusInfo {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poetteringstatic void print_status_info(StatusInfo *i) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf(" System Locale: %s\n", i->locale[0]);
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf(" X11 Layout: %s\n", strna(i->x11_layout));
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf(" X11 Model: %s\n", i->x11_model);
13790add4bf648fed816361794d8277a75253410Lennart Poettering printf(" X11 Variant: %s\n", i->x11_variant);
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek printf(" X11 Options: %s\n", i->x11_options);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int status_property(const char *name, DBusMessageIter *iter, StatusInfo *i) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering switch (dbus_message_iter_get_arg_type(iter)) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering const char *s;
13790add4bf648fed816361794d8277a75253410Lennart Poettering else if (streq(name, "VConsoleKeymapToggle"))
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int show_status(DBusConnection *bus, char **args, unsigned n) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
13790add4bf648fed816361794d8277a75253410Lennart Poettering "org.freedesktop.locale1",
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering "org.freedesktop.DBus.Properties",
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
13790add4bf648fed816361794d8277a75253410Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
13790add4bf648fed816361794d8277a75253410Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int set_locale(DBusConnection *bus, char **args, unsigned n) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "org.freedesktop.locale1",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "org.freedesktop.locale1",
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek r = bus_append_strv_iter(&iter, args + 1);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &interactive))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to issue method call: %s", bus_error_message(&error));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int list_locales(DBusConnection *bus, char **args, unsigned n) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Stolen from glibc... */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Serial number. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Name hash table. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* String table. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Table with locale records. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* MD5 sum hash table. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Hash value of the name. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Offset of the name in the string table. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Offset of the locale record. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const struct locarhead *h;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const struct namehashent *e;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const void *p = MAP_FAILED;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering locales = set_new(string_hash_func, string_compare_func);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to open locale archive: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Archive file is not regular");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (st.st_size < (off_t) sizeof(struct locarhead)) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering h = (const struct locarhead *) p;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering h->namehash_offset + h->namehash_size > st.st_size ||
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering h->string_offset + h->string_size > st.st_size ||
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering h->locrectab_offset + h->locrectab_size > st.st_size ||
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering h->sumhash_offset + h->sumhash_size > st.st_size) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering for (i = 0; i < h->namehash_size; i++) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering z = strdup((char*) p + e[i].name_offset);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Failed to add locale: %s", strerror(-r));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int set_vconsole_keymap(DBusConnection *bus, char **args, unsigned n) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering "org.freedesktop.locale1",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "org.freedesktop.locale1",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "SetVConsoleKeyboard",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else if (r < 0) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_error("Can't add keymap: %s", strerror(-r));
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int list_vconsole_keymaps(DBusConnection *bus, char **args, unsigned n) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering keymaps = set_new(string_hash_func, string_compare_func);
13790add4bf648fed816361794d8277a75253410Lennart Poettering nftw("/usr/share/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
13790add4bf648fed816361794d8277a75253410Lennart Poettering nftw("/usr/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
13790add4bf648fed816361794d8277a75253410Lennart Poettering nftw("/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Couldn't find any console keymaps.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int set_x11_keymap(DBusConnection *bus, char **args, unsigned n) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt const char *layout, *model, *variant, *options;
13790add4bf648fed816361794d8277a75253410Lennart Poettering "org.freedesktop.locale1",
13790add4bf648fed816361794d8277a75253410Lennart Poettering "org.freedesktop.locale1",
13790add4bf648fed816361794d8277a75253410Lennart Poettering "SetX11Keyboard",
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int help(void) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering "Query or change system time and date settings.\n\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " -h --help Show this help\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " --version Show package version\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " --no-convert Don't convert keyboard mappings\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " --no-pager Do not pipe output into a pager\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " --no-ask-password Do not prompt for password\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " -H --host=[USER@]HOST Operate on remote host\n\n"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering " status Show current locale settings\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " set-locale LOCALE... Set system locale\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " list-locales Show known locales\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " set-keymap MAP [MAP] Set virtual console keyboard mapping\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " list-keymaps Show known virtual console keyboard mappings\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS]\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering " Set X11 keyboard mapping\n",
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int parse_argv(int argc, char *argv[]) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "version", no_argument, NULL, ARG_VERSION },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "no-pager", no_argument, NULL, ARG_NO_PAGER },
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering { "host", required_argument, NULL, 'H' },
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering { "privileged", no_argument, NULL, 'P' },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "no-convert", no_argument, NULL, ARG_NO_CONVERT },
13790add4bf648fed816361794d8277a75253410Lennart Poettering while ((c = getopt_long(argc, argv, "has:H:P", options, NULL)) >= 0) {
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int localectl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering static const struct {
13790add4bf648fed816361794d8277a75253410Lennart Poettering int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "list-locales", EQUAL, 1, list_locales },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "set-keymap", MORE, 2, set_vconsole_keymap },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "list-keymaps", EQUAL, 1, list_vconsole_keymaps },
13790add4bf648fed816361794d8277a75253410Lennart Poettering { "set-x11-keymap", MORE, 2, set_x11_keymap },
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering /* Special rule: no arguments means "status" */
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek log_error("Unknown operation %s", argv[optind]);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Invalid number of arguments.");
if (!bus) {
return -EIO;
log_open();
goto finish;
goto finish;
if (bus) {
pager_close();
return retval;