localectl.c revision 7568345034f2890af745747783c5abfbf6eccf0f
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2013 Kay Sievers
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <locale.h>
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen#include <stdlib.h>
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen#include <stdbool.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <unistd.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <getopt.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <string.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <ftw.h>
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering#include <sys/mman.h>
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering#include <fcntl.h>
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering#include "sd-bus.h"
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering#include "bus-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "bus-error.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "bus-message.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "util.h"
51323288fc628a5cac50914df915545d685b793eLennart Poettering#include "spawn-polkit-agent.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "build.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "strv.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "pager.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "set.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "path-util.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "utf8.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "def.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include "locale-util.h"
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_no_pager = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_ask_password = true;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic char *arg_host = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_convert = true;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void pager_open_if_enabled(void) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (arg_no_pager)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return;
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering pager_open(false);
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering}
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering /* Open the polkit agent as a child process if necessary */
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering if (!arg_ask_password)
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return;
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (arg_transport != BUS_TRANSPORT_LOCAL)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering polkit_agent_open();
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringtypedef struct StatusInfo {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char **locale;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *vconsole_keymap;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *vconsole_keymap_toggle;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *x11_layout;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *x11_model;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering const char *x11_variant;
dc61b7e45d89a69f0469ab7b3289cdde7fcc55abTorstein Husebø const char *x11_options;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering} StatusInfo;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic void print_status_info(StatusInfo *i) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(i);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering if (strv_isempty(i->locale))
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering puts(" System Locale: n/a\n");
f6a5fec6b971e2a8c69d92ab20ed13693be82ddbLennart Poettering else {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char **j;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf(" System Locale: %s\n", i->locale[0]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering STRV_FOREACH(j, i->locale + 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf(" %s\n", *j);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!isempty(i->vconsole_keymap_toggle))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf(" X11 Layout: %s\n", strna(i->x11_layout));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!isempty(i->x11_model))
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering printf(" X11 Model: %s\n", i->x11_model);
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering if (!isempty(i->x11_variant))
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering printf(" X11 Variant: %s\n", i->x11_variant);
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack if (!isempty(i->x11_options))
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering printf(" X11 Options: %s\n", i->x11_options);
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack}
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mackstatic int show_status(sd_bus *bus, char **args, unsigned n) {
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack StatusInfo info = {};
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack static const struct bus_properties_map map[] = {
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) },
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) },
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack { "VConsoleKeymapToggle", "s", NULL, offsetof(StatusInfo, vconsole_keymap_toggle) },
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack { "X11Layout", "s", NULL, offsetof(StatusInfo, x11_layout) },
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack { "X11Model", "s", NULL, offsetof(StatusInfo, x11_model) },
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering { "X11Variant", "s", NULL, offsetof(StatusInfo, x11_variant) },
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering { "X11Options", "s", NULL, offsetof(StatusInfo, x11_options) },
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering { "Locale", "as", NULL, offsetof(StatusInfo, locale) },
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering {}
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering };
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering int r;
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering assert(bus);
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering r = bus_map_all_properties(bus,
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering "org.freedesktop.locale1",
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering "/org/freedesktop/locale1",
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering map,
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering &info);
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering if (r < 0) {
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering log_error("Could not get properties: %s", strerror(-r));
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering goto fail;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering }
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering print_status_info(&info);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poetteringfail:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering strv_free(info.locale);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int set_locale(sd_bus *bus, char **args, unsigned n) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(bus);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(args);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering polkit_agent_open_if_enabled();
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_new_method_call(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bus,
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering &m,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "org.freedesktop.locale1",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "/org/freedesktop/locale1",
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek "org.freedesktop.locale1",
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek "SetLocale");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return bus_log_create_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append_strv(m, args + 1);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return bus_log_create_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(m, "b", arg_ask_password);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek return bus_log_create_error(r);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_bus_call(bus, m, 0, &error, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering return r;
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int list_locales(sd_bus *bus, char **args, unsigned n) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_strv_free_ char **l = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(args);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = get_locales(&l);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to read list of locales: %s", strerror(-r));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering pager_open_if_enabled();
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering strv_print(l);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int set_vconsole_keymap(sd_bus *bus, char **args, unsigned n) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *map, *toggle_map;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(bus);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering assert(args);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (n > 3) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering log_error("Too many arguments.");
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek polkit_agent_open_if_enabled();
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek map = args[1];
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek toggle_map = n > 2 ? args[2] : "";
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek r = sd_bus_call_method(
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek bus,
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek "org.freedesktop.locale1",
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek "/org/freedesktop/locale1",
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek "org.freedesktop.locale1",
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek "SetVConsoleKeyboard",
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek &error,
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek NULL,
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek "ssbb", map, toggle_map, arg_convert, arg_ask_password);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (r < 0)
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek return r;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek}
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmekstatic Set *keymaps = NULL;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmekstatic int nftw_cb(
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek const char *fpath,
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek const struct stat *sb,
51323288fc628a5cac50914df915545d685b793eLennart Poettering int tflag,
51323288fc628a5cac50914df915545d685b793eLennart Poettering struct FTW *ftwbuf) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering
51323288fc628a5cac50914df915545d685b793eLennart Poettering char *p, *e;
51323288fc628a5cac50914df915545d685b793eLennart Poettering int r;
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack if (tflag != FTW_F)
51323288fc628a5cac50914df915545d685b793eLennart Poettering return 0;
51323288fc628a5cac50914df915545d685b793eLennart Poettering
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack if (!endswith(fpath, ".map") &&
51323288fc628a5cac50914df915545d685b793eLennart Poettering !endswith(fpath, ".map.gz"))
51323288fc628a5cac50914df915545d685b793eLennart Poettering return 0;
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack p = strdup(basename(fpath));
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack if (!p)
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack return log_oom();
51323288fc628a5cac50914df915545d685b793eLennart Poettering
51323288fc628a5cac50914df915545d685b793eLennart Poettering e = endswith(p, ".map");
if (e)
*e = 0;
e = endswith(p, ".map.gz");
if (e)
*e = 0;
r = set_consume(keymaps, p);
if (r < 0 && r != -EEXIST) {
log_error("Can't add keymap: %s", strerror(-r));
return r;
}
return 0;
}
static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
_cleanup_strv_free_ char **l = NULL;
const char *dir;
keymaps = set_new(string_hash_func, string_compare_func);
if (!keymaps)
return log_oom();
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)
nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
l = set_get_strv(keymaps);
if (!l) {
set_free_free(keymaps);
return log_oom();
}
set_free(keymaps);
if (strv_isempty(l)) {
log_error("Couldn't find any console keymaps.");
return -ENOENT;
}
strv_sort(l);
pager_open_if_enabled();
strv_print(l);
return 0;
}
static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *layout, *model, *variant, *options;
int r;
assert(bus);
assert(args);
if (n > 5) {
log_error("Too many arguments.");
return -EINVAL;
}
polkit_agent_open_if_enabled();
layout = args[1];
model = n > 2 ? args[2] : "";
variant = n > 3 ? args[3] : "";
options = n > 4 ? args[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)
log_error("Failed to set keymap: %s", bus_error_message(&error, -r));
return r;
}
static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **list = NULL;
char line[LINE_MAX];
enum {
NONE,
MODELS,
LAYOUTS,
VARIANTS,
OPTIONS
} state = NONE, look_for;
int r;
if (n > 2) {
log_error("Too many arguments.");
return -EINVAL;
}
f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
if (!f) {
log_error("Failed to open keyboard mapping list. %m");
return -errno;
}
if (streq(args[0], "list-x11-keymap-models"))
look_for = MODELS;
else if (streq(args[0], "list-x11-keymap-layouts"))
look_for = LAYOUTS;
else if (streq(args[0], "list-x11-keymap-variants"))
look_for = VARIANTS;
else if (streq(args[0], "list-x11-keymap-options"))
look_for = OPTIONS;
else
assert_not_reached("Wrong parameter");
FOREACH_LINE(line, f, break) {
char *l, *w;
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 (n > 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, args[1]))
continue;
} else
*w = 0;
r = strv_extend(&list, l);
if (r < 0)
return log_oom();
}
if (strv_isempty(list)) {
log_error("Couldn't find any entries.");
return -ENOENT;
}
strv_sort(list);
strv_uniq(list);
pager_open_if_enabled();
strv_print(list);
return 0;
}
static int help(void) {
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 virtual console keyboard mapping\n"
" list-keymaps Show known virtual console keyboard mappings\n"
" set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS]\n"
" Set X11 keyboard mapping\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",
program_invocation_short_name);
return 0;
}
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:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case ARG_NO_CONVERT:
arg_convert = false;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
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_CONTAINER;
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 struct {
const char* verb;
const enum {
MORE,
LESS,
EQUAL
} argc_cmp;
const int argc;
int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
} verbs[] = {
{ "status", LESS, 1, show_status },
{ "set-locale", MORE, 2, set_locale },
{ "list-locales", EQUAL, 1, list_locales },
{ "set-keymap", MORE, 2, set_vconsole_keymap },
{ "list-keymaps", EQUAL, 1, list_vconsole_keymaps },
{ "set-x11-keymap", MORE, 2, set_x11_keymap },
{ "list-x11-keymap-models", EQUAL, 1, list_x11_keymaps },
{ "list-x11-keymap-layouts", EQUAL, 1, list_x11_keymaps },
{ "list-x11-keymap-variants", LESS, 2, list_x11_keymaps },
{ "list-x11-keymap-options", EQUAL, 1, list_x11_keymaps },
};
int left;
unsigned i;
assert(argc >= 0);
assert(argv);
left = argc - optind;
if (left <= 0)
/* Special rule: no arguments means "status" */
i = 0;
else {
if (streq(argv[optind], "help")) {
help();
return 0;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;
if (i >= ELEMENTSOF(verbs)) {
log_error("Unknown operation %s", argv[optind]);
return -EINVAL;
}
}
switch (verbs[i].argc_cmp) {
case EQUAL:
if (left != verbs[i].argc) {
log_error("Invalid number of arguments.");
return -EINVAL;
}
break;
case MORE:
if (left < verbs[i].argc) {
log_error("Too few arguments.");
return -EINVAL;
}
break;
case LESS:
if (left > verbs[i].argc) {
log_error("Too many arguments.");
return -EINVAL;
}
break;
default:
assert_not_reached("Unknown comparison operator.");
}
return verbs[i].dispatch(bus, argv + optind, left);
}
int main(int argc, char*argv[]) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error("Failed to create bus connection: %s", strerror(-r));
goto finish;
}
r = localectl_main(bus, argc, argv);
finish:
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}