localectl.c revision 7c2d80944afb4196f2eff614e8da1450dffcbeaa
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/***
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering This file is part of systemd.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Copyright 2012 Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is free software; you can redistribute it and/or modify it
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering under the terms of the GNU Lesser General Public License as published by
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (at your option) any later version.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is distributed in the hope that it will be useful, but
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Lesser General Public License for more details.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering You should have received a copy of the GNU Lesser General Public License
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering***/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <locale.h>
4ad7f2761da661853dcc29d542efb4727abb1101Nick Owens#include <stdlib.h>
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering#include <stdbool.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <unistd.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <getopt.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <string.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <ftw.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <sys/mman.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <fcntl.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "dbus-common.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "util.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "spawn-polkit-agent.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "build.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "strv.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "pager.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "set.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "path-util.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_no_pager = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic enum transport {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering TRANSPORT_NORMAL,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering TRANSPORT_SSH,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering TRANSPORT_POLKIT
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering} arg_transport = TRANSPORT_NORMAL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_ask_password = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic const char *arg_host = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_convert = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void pager_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (arg_no_pager)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering pager_open();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Open the polkit agent as a child process if necessary */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!arg_ask_password)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering polkit_agent_open();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringtypedef struct StatusInfo {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering char **locale;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering const char *vconsole_keymap;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering const char *vconsole_keymap_toggle;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *x11_layout;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *x11_model;
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering const char *x11_variant;
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering const char *x11_options;
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering} StatusInfo;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poetteringstatic void print_status_info(StatusInfo *i) {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering assert(i);
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (strv_isempty(i->locale))
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering puts(" System Locale: n/a\n");
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering else {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering char **j;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" System Locale: %s\n", i->locale[0]);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering STRV_FOREACH(j, i->locale + 1)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" %s\n", *j);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering if (!isempty(i->vconsole_keymap_toggle))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Layout: %s\n", strna(i->x11_layout));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!isempty(i->x11_model))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Model: %s\n", i->x11_model);
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (!isempty(i->x11_variant))
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering printf(" X11 Variant: %s\n", i->x11_variant);
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (!isempty(i->x11_options))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Options: %s\n", i->x11_options);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int status_property(const char *name, DBusMessageIter *iter, StatusInfo *i) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(name);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(iter);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering switch (dbus_message_iter_get_arg_type(iter)) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering case DBUS_TYPE_STRING: {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dbus_message_iter_get_basic(iter, &s);
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (!isempty(s)) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (streq(name, "VConsoleKeymap"))
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering i->vconsole_keymap = s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (streq(name, "VConsoleKeymapToggle"))
5d27351f8546530cf779847b0b04b0172c09f9d0Tom Gundersen i->vconsole_keymap_toggle = s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (streq(name, "X11Layout"))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering i->x11_layout = s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (streq(name, "X11Model"))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering i->x11_model = s;
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering else if (streq(name, "X11Variant"))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering i->x11_variant = s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (streq(name, "X11Options"))
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering i->x11_options = s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering break;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering case DBUS_TYPE_ARRAY:
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char **l;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = bus_parse_strv_iter(iter, &l);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (streq(name, "Locale")) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering strv_free(i->locale);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering i->locale = l;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering l = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering strv_free(l);
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering }
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering }
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering return 0;
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering}
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poetteringstatic int show_status(DBusConnection *bus, char **args, unsigned n) {
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering const char *interface = "";
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering DBusMessageIter iter, sub, sub2, sub3;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering StatusInfo info;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(args);
6a21960c0be378799db51a2735ff68474e5e21f8Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering r = bus_method_call_with_reply(
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering bus,
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "org.freedesktop.locale1",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "/org/freedesktop/locale1",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "org.freedesktop.DBus.Properties",
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering "GetAll",
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering &reply,
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering NULL,
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering DBUS_TYPE_STRING, &interface,
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering DBUS_TYPE_INVALID);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (r < 0)
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering return r;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering log_error("Failed to parse reply.");
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering return -EIO;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering zero(info);
b6800689e03456efd0430d171ebf962f64b94eb0Lennart Poettering dbus_message_iter_recurse(&iter, &sub);
b6800689e03456efd0430d171ebf962f64b94eb0Lennart Poettering
b6800689e03456efd0430d171ebf962f64b94eb0Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering const char *name;
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering log_error("Failed to parse reply.");
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering return -EIO;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_recurse(&sub, &sub2);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering log_error("Failed to parse reply.");
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering return -EIO;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering log_error("Failed to parse reply.");
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering return -EIO;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_recurse(&sub2, &sub3);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering r = status_property(name, &sub3, &info);
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen if (r < 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to parse reply.");
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dbus_message_iter_next(&sub);
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering print_status_info(&info);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering strv_free(info.locale);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering}
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poetteringstatic int set_locale(DBusConnection *bus, char **args, unsigned n) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering dbus_bool_t interactive = true;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering DBusError error;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering DBusMessageIter iter;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering int r;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering assert(bus);
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering assert(args);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering dbus_error_init(&error);
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering polkit_agent_open_if_enabled();
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering m = dbus_message_new_method_call(
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "org.freedesktop.locale1",
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "/org/freedesktop/locale1",
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "org.freedesktop.locale1",
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering "SetLocale");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!m)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_oom();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dbus_message_iter_init_append(m, &iter);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = bus_append_strv_iter(&iter, args + 1);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_oom();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &interactive))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_oom();
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!reply) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to issue method call: %s", bus_error_message(&error));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = -EIO;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering goto finish;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringfinish:
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dbus_error_free(&error);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int add_locales_from_archive(Set *locales) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Stolen from glibc... */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering struct locarhead {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering uint32_t magic;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Serial number. */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering uint32_t serial;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Name hash table. */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering uint32_t namehash_offset;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering uint32_t namehash_used;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering uint32_t namehash_size;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* String table. */
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering uint32_t string_offset;
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering uint32_t string_used;
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering uint32_t string_size;
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering /* Table with locale records. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t locrectab_offset;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t locrectab_used;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t locrectab_size;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* MD5 sum hash table. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t sumhash_offset;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t sumhash_used;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t sumhash_size;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering };
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering struct namehashent {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Hash value of the name. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t hashval;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Offset of the name in the string table. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t name_offset;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Offset of the locale record. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint32_t locrec_offset;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering };
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const struct locarhead *h;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const struct namehashent *e;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const void *p = MAP_FAILED;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering _cleanup_close_ int fd = -1;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering size_t sz = 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering struct stat st;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering unsigned i;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering int r;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (fd < 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (errno != ENOENT)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to open locale archive: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -errno;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (fstat(fd, &st) < 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("fstat() failed: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -errno;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (!S_ISREG(st.st_mode)) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Archive file is not regular");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -EBADMSG;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (st.st_size < (off_t) sizeof(struct locarhead)) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Archive has invalid size");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -EBADMSG;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (p == MAP_FAILED) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to map archive: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -errno;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h = (const struct locarhead *) p;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (h->magic != 0xde020109 ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->namehash_offset + h->namehash_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->string_offset + h->string_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->locrectab_offset + h->locrectab_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->sumhash_offset + h->sumhash_size > st.st_size) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Invalid archive file.");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = -EBADMSG;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering for (i = 0; i < h->namehash_size; i++) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering char *z;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (e[i].locrec_offset == 0)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering continue;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering z = strdup((char*) p + e[i].name_offset);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (!z) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = log_oom();
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = set_put(locales, z);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r < 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering free(z);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to add locale: %s", strerror(-r));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering goto finish;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = 0;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering finish:
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (p != MAP_FAILED)
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering munmap((void*) p, sz);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return r;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering}
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poetteringstatic int add_locales_from_libdir (Set *locales) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering DIR _cleanup_closedir_ *dir;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering struct dirent *entry;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering int r;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering dir = opendir("/usr/lib/locale");
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (!dir) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to open locale directory: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return -errno;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering }
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering errno = 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering while ((entry = readdir(dir))) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering char *z;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (entry->d_type != DT_DIR)
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering continue;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (ignore_file(entry->d_name))
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering continue;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering z = strdup(entry->d_name);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (!z)
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return log_oom();
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering r = set_put(locales, z);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (r < 0) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering free(z);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (r != -EEXIST) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering log_error("Failed to add locale: %s", strerror(-r));
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return r;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering }
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering }
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering errno = 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering }
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (errno != 0) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering log_error("Failed to read locale directory: %m");
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return -errno;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering }
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering return 0;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering}
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poetteringstatic int list_locales(DBusConnection *bus, char **args, unsigned n) {
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering _cleanup_set_free_ Set *locales;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering _cleanup_strv_free_ char **l = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering int r;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering locales = set_new(string_hash_func, string_compare_func);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (!locales)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return log_oom();
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = add_locales_from_archive(locales);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r < 0 && r != -ENOENT)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return r;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = add_locales_from_libdir(locales);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r < 0)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return r;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering l = set_get_strv(locales);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (!l)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return log_oom();
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering strv_sort(l);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering pager_open_if_enabled();
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering strv_print(l);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return 0;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering}
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int set_vconsole_keymap(DBusConnection *bus, char **args, unsigned n) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
dbus_bool_t interactive = true, b;
const char *map, *toggle_map;
assert(bus);
assert(args);
if (n > 3) {
log_error("Too many arguments.");
return -EINVAL;
}
polkit_agent_open_if_enabled();
map = args[1];
toggle_map = n > 2 ? args[2] : "";
b = arg_convert;
return bus_method_call_with_reply(
bus,
"org.freedesktop.locale1",
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"SetVConsoleKeyboard",
&reply,
NULL,
DBUS_TYPE_STRING, &map,
DBUS_TYPE_STRING, &toggle_map,
DBUS_TYPE_BOOLEAN, &b,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID);
}
static Set *keymaps = NULL;
static int nftw_cb(
const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf) {
char *p, *e;
int r;
if (tflag != FTW_F)
return 0;
if (!endswith(fpath, ".map") &&
!endswith(fpath, ".map.gz"))
return 0;
p = strdup(path_get_file_name(fpath));
if (!p)
return log_oom();
e = endswith(p, ".map");
if (e)
*e = 0;
e = endswith(p, ".map.gz");
if (e)
*e = 0;
r = set_put(keymaps, p);
if (r == -EEXIST)
free(p);
else if (r < 0) {
log_error("Can't add keymap: %s", strerror(-r));
free(p);
return r;
}
return 0;
}
static int list_vconsole_keymaps(DBusConnection *bus, char **args, unsigned n) {
char _cleanup_strv_free_ **l = NULL;
keymaps = set_new(string_hash_func, string_compare_func);
if (!keymaps)
return log_oom();
nftw("/usr/share/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
nftw("/usr/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
nftw("/lib/kbd/keymaps/", 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(DBusConnection *bus, char **args, unsigned n) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
dbus_bool_t interactive = true, b;
const char *layout, *model, *variant, *options;
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] : "";
b = arg_convert;
return bus_method_call_with_reply(
bus,
"org.freedesktop.locale1",
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"SetX11Keyboard",
&reply,
NULL,
DBUS_TYPE_STRING, &layout,
DBUS_TYPE_STRING, &model,
DBUS_TYPE_STRING, &variant,
DBUS_TYPE_STRING, &options,
DBUS_TYPE_BOOLEAN, &b,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID);
}
static int help(void) {
printf("%s [OPTIONS...] COMMAND ...\n\n"
"Query or change system time and date settings.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-convert Don't convert keyboard mappings\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\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",
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' },
{ "privileged", no_argument, NULL, 'P' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "no-convert", no_argument, NULL, ARG_NO_CONVERT },
{ NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "has:H:P", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case 'P':
arg_transport = TRANSPORT_POLKIT;
break;
case 'H':
arg_transport = TRANSPORT_SSH;
arg_host = optarg;
break;
case ARG_NO_CONVERT:
arg_convert = false;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
return 1;
}
static int localectl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
static const struct {
const char* verb;
const enum {
MORE,
LESS,
EQUAL
} argc_cmp;
const int argc;
int (* const dispatch)(DBusConnection *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 },
};
int left;
unsigned i;
assert(argc >= 0);
assert(argv);
assert(error);
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.");
}
if (!bus) {
log_error("Failed to get D-Bus connection: %s", error->message);
return -EIO;
}
return verbs[i].dispatch(bus, argv + optind, left);
}
int main(int argc, char *argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
DBusError error;
dbus_error_init(&error);
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r < 0)
goto finish;
else if (r == 0) {
retval = EXIT_SUCCESS;
goto finish;
}
if (arg_transport == TRANSPORT_NORMAL)
bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
else if (arg_transport == TRANSPORT_POLKIT)
bus_connect_system_polkit(&bus, &error);
else if (arg_transport == TRANSPORT_SSH)
bus_connect_system_ssh(NULL, arg_host, &bus, &error);
else
assert_not_reached("Uh, invalid transport...");
r = localectl_main(bus, argc, argv, &error);
retval = r < 0 ? EXIT_FAILURE : r;
finish:
if (bus) {
dbus_connection_flush(bus);
dbus_connection_close(bus);
dbus_connection_unref(bus);
}
dbus_error_free(&error);
dbus_shutdown();
pager_close();
return retval;
}