localed.c revision 7914d6bba47a21b98617d04c992a9075ff5af4c0
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2011 Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <dbus/dbus.h>
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <errno.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <string.h>
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include <unistd.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering#include "util.h"
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek#include "mkdir.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "strv.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "dbus-common.h"
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include "polkit.h"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen#include "def.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "env-util.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "fileio.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "fileio-label.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "label.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek#define INTERFACE \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <interface name=\"org.freedesktop.locale1\">\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"Locale\" type=\"as\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"VConsoleKeymap\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"VConsoleKeymapToggle\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"X11Layout\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"X11Model\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"X11Variant\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <property name=\"X11Options\" type=\"s\" access=\"read\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <method name=\"SetLocale\">\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n" \
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " </method>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <method name=\"SetVConsoleKeyboard\">\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"keymap\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"keymap_toggle\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " </method>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <method name=\"SetX11Keyboard\">\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"layout\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"model\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"variant\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"options\" type=\"s\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " </method>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering " </interface>\n"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#define INTROSPECTION \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "<node>\n" \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering INTERFACE \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering BUS_PROPERTIES_INTERFACE \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering BUS_INTROSPECTABLE_INTERFACE \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering BUS_PEER_INTERFACE \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "</node>\n"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#define INTERFACES_LIST \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering BUS_GENERIC_INTERFACES_LIST \
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "org.freedesktop.locale1\0"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringconst char locale_interface[] _introspect_("locale1") = INTERFACE;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poetteringenum {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering /* We don't list LC_ALL here on purpose. People should be
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * using LANG instead. */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LANG,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LANGUAGE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_CTYPE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_NUMERIC,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_TIME,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_COLLATE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_MONETARY,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_MESSAGES,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_PAPER,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_NAME,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_ADDRESS,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_TELEPHONE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_MEASUREMENT,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering PROP_LC_IDENTIFICATION,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _PROP_MAX
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering};
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic const char * const names[_PROP_MAX] = {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering [PROP_LANG] = "LANG",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LANGUAGE] = "LANGUAGE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_CTYPE] = "LC_CTYPE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_NUMERIC] = "LC_NUMERIC",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_TIME] = "LC_TIME",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_COLLATE] = "LC_COLLATE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_MONETARY] = "LC_MONETARY",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_MESSAGES] = "LC_MESSAGES",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_PAPER] = "LC_PAPER",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_NAME] = "LC_NAME",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_ADDRESS] = "LC_ADDRESS",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_TELEPHONE] = "LC_TELEPHONE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_MEASUREMENT] = "LC_MEASUREMENT",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [PROP_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic char *data[_PROP_MAX] = {};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringtypedef struct State {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *x11_layout, *x11_model, *x11_variant, *x11_options;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *vc_keymap, *vc_keymap_toggle;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering} State;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic State state;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic usec_t remain_until = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int free_and_set(char **s, const char *v) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *t;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(s);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = strdup_or_null(isempty(v) ? NULL : v, &t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(*s);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *s = t;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void free_data_locale(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0; p < _PROP_MAX; p++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(data[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering data[p] = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void free_data_x11(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.x11_layout);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.x11_model);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.x11_variant);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.x11_options);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering state.x11_layout = state.x11_model = state.x11_variant = state.x11_options = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void free_data_vconsole(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.vc_keymap);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(state.vc_keymap_toggle);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering state.vc_keymap = state.vc_keymap_toggle = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void simplify(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 1; p < _PROP_MAX; p++)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (isempty(data[p]) || streq_ptr(data[PROP_LANG], data[p])) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(data[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering data[p] = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int read_data_locale(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_data_locale();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = parse_env_file("/etc/locale.conf", NEWLINE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LANG", &data[PROP_LANG],
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek "LANGUAGE", &data[PROP_LANGUAGE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_CTYPE", &data[PROP_LC_CTYPE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_NUMERIC", &data[PROP_LC_NUMERIC],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_TIME", &data[PROP_LC_TIME],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_COLLATE", &data[PROP_LC_COLLATE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MONETARY", &data[PROP_LC_MONETARY],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MESSAGES", &data[PROP_LC_MESSAGES],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_PAPER", &data[PROP_LC_PAPER],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_NAME", &data[PROP_LC_NAME],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_ADDRESS", &data[PROP_LC_ADDRESS],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_TELEPHONE", &data[PROP_LC_TELEPHONE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MEASUREMENT", &data[PROP_LC_MEASUREMENT],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_IDENTIFICATION", &data[PROP_LC_IDENTIFICATION],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r == -ENOENT) {
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Fill in what we got passed from systemd. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0; p < _PROP_MAX; p++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *e, *d;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering e = getenv(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (e) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering d = strdup(e);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!d)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering d = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(data[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering data[p] = d;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering simplify();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void free_data(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_data_locale();
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek free_data_vconsole();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_data_x11();
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int read_data_vconsole(void) {
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek int r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free_data_vconsole();
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = parse_env_file("/etc/vconsole.conf", NEWLINE,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering "KEYMAP", &state.vc_keymap,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering "KEYMAP_TOGGLE", &state.vc_keymap_toggle,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering NULL);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0 && r != -ENOENT)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int read_data_x11(void) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering FILE *f;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char line[LINE_MAX];
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering bool in_section = false;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free_data_x11();
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!f)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return errno == ENOENT ? 0 : -errno;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering while (fgets(line, sizeof(line), f)) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *l;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek char_array_0(line);
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek l = strstrip(line);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (l[0] == 0 || l[0] == '#')
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek continue;
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek if (in_section && first_word(l, "Option")) {
ac50788b0f5aeee09e7d45db28ae8ab7f39cd52eZbigniew Jędrzejewski-Szmek char **a;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a = strv_split_quoted(l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!a) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering fclose(f);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (strv_length(a) == 3) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (streq(a[1], "XkbLayout")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(state.x11_layout);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering state.x11_layout = a[2];
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a[2] = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (streq(a[1], "XkbModel")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(state.x11_model);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering state.x11_model = a[2];
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a[2] = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (streq(a[1], "XkbVariant")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(state.x11_variant);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering state.x11_variant = a[2];
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a[2] = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (streq(a[1], "XkbOptions")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering free(state.x11_options);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering state.x11_options = a[2];
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a[2] = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering strv_free(a);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (!in_section && first_word(l, "Section")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char **a;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering a = strv_split_quoted(l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!a) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering fclose(f);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (strv_length(a) == 2 && streq(a[1], "InputClass"))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering in_section = true;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering strv_free(a);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (in_section && first_word(l, "EndSection"))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering in_section = false;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering fclose(f);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int read_data(void) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r, q, p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = read_data_locale();
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering q = read_data_vconsole();
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering p = read_data_x11();
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r < 0 ? r : q < 0 ? q : p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int write_data_locale(void) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r, p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char **l = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = load_env_file("/etc/locale.conf", NULL, &l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0 && r != -ENOENT)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (p = 0; p < _PROP_MAX; p++) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *t, **u;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (isempty(data[p])) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = strv_env_unset(l, names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering u = strv_env_set(l, t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(t);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!u)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek l = u;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (strv_isempty(l)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (unlink("/etc/locale.conf") < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return errno == ENOENT ? 0 : -errno;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = write_env_file_label("/etc/locale.conf", l);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen return r;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void push_data(DBusConnection *bus) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char **l_set = NULL, **l_unset = NULL, **t;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int c_set = 0, c_unset = 0, p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBusError error;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBusMessage *m = NULL, *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering DBusMessageIter iter, sub;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_error_init(&error);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(bus);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_set = new0(char*, _PROP_MAX);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_unset = new0(char*, _PROP_MAX);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!l_set || !l_unset) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0; p < _PROP_MAX; p++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (isempty(data[p]))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_unset[c_set++] = (char*) names[p];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek char *s;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (asprintf(&s, "%s=%s", names[p], data[p]) < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_set[c_unset++] = s;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(c_set + c_unset == _PROP_MAX);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!m) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error("Could not allocate message.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek dbus_message_iter_init_append(m, &iter);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering STRV_FOREACH(t, l_unset)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_close_container(&iter, &sub) ||
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering STRV_FOREACH(t, l_set)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!dbus_message_iter_close_container(&iter, &sub)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_oom();
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering goto finish;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering if (!reply) {
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering log_error("Failed to set locale information: %s", bus_error_message(&error));
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering goto finish;
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering }
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringfinish:
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (m)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_unref(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (reply)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_message_unref(reply);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering dbus_error_free(&error);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering strv_free(l_set);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering free(l_unset);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering}
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int write_data_vconsole(void) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char **l = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering r = load_env_file("/etc/vconsole.conf", NULL, &l);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (r < 0 && r != -ENOENT)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return r;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (isempty(state.vc_keymap))
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering l = strv_env_unset(l, "KEYMAP");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering else {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering char *s, **u;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering s = strappend("KEYMAP=", state.vc_keymap);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (!s) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering strv_free(l);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return -ENOMEM;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering u = strv_env_set(l, s);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering free(s);
strv_free(l);
if (!u)
return -ENOMEM;
l = u;
}
if (isempty(state.vc_keymap_toggle))
l = strv_env_unset(l, "KEYMAP_TOGGLE");
else {
char *s, **u;
s = strappend("KEYMAP_TOGGLE=", state.vc_keymap_toggle);
if (!s) {
strv_free(l);
return -ENOMEM;
}
u = strv_env_set(l, s);
free(s);
strv_free(l);
if (!u)
return -ENOMEM;
l = u;
}
if (strv_isempty(l)) {
strv_free(l);
if (unlink("/etc/vconsole.conf") < 0)
return errno == ENOENT ? 0 : -errno;
return 0;
}
r = write_env_file_label("/etc/vconsole.conf", l);
strv_free(l);
return r;
}
static int write_data_x11(void) {
FILE *f;
char *temp_path;
int r;
if (isempty(state.x11_layout) &&
isempty(state.x11_model) &&
isempty(state.x11_variant) &&
isempty(state.x11_options)) {
if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
return errno == ENOENT ? 0 : -errno;
return 0;
}
mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
if (r < 0)
return r;
fchmod(fileno(f), 0644);
fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
"# manually too freely.\n"
"Section \"InputClass\"\n"
" Identifier \"system-keyboard\"\n"
" MatchIsKeyboard \"on\"\n", f);
if (!isempty(state.x11_layout))
fprintf(f, " Option \"XkbLayout\" \"%s\"\n", state.x11_layout);
if (!isempty(state.x11_model))
fprintf(f, " Option \"XkbModel\" \"%s\"\n", state.x11_model);
if (!isempty(state.x11_variant))
fprintf(f, " Option \"XkbVariant\" \"%s\"\n", state.x11_variant);
if (!isempty(state.x11_options))
fprintf(f, " Option \"XkbOptions\" \"%s\"\n", state.x11_options);
fputs("EndSection\n", f);
fflush(f);
if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
r = -errno;
unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
unlink(temp_path);
} else
r = 0;
fclose(f);
free(temp_path);
return r;
}
static int load_vconsole_keymap(DBusConnection *bus, DBusError *error) {
DBusMessage *m = NULL, *reply = NULL;
const char *name = "systemd-vconsole-setup.service", *mode = "replace";
int r;
DBusError _error;
assert(bus);
if (!error) {
dbus_error_init(&_error);
error = &_error;
}
m = dbus_message_new_method_call(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"RestartUnit");
if (!m) {
log_error("Could not allocate message.");
r = -ENOMEM;
goto finish;
}
if (!dbus_message_append_args(m,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID)) {
log_error("Could not append arguments to message.");
r = -ENOMEM;
goto finish;
}
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
if (!reply) {
log_error("Failed to issue method call: %s", bus_error_message(error));
r = -EIO;
goto finish;
}
r = 0;
finish:
if (m)
dbus_message_unref(m);
if (reply)
dbus_message_unref(reply);
if (error == &_error)
dbus_error_free(error);
return r;
}
static char *strnulldash(const char *s) {
return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s;
}
static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
assert(f);
assert(n);
assert(a);
for (;;) {
char line[LINE_MAX];
char *l, **b;
errno = 0;
if (!fgets(line, sizeof(line), f)) {
if (ferror(f))
return errno ? -errno : -EIO;
return 0;
}
(*n) ++;
l = strstrip(line);
if (l[0] == 0 || l[0] == '#')
continue;
b = strv_split_quoted(l);
if (!b)
return -ENOMEM;
if (strv_length(b) < 5) {
log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
strv_free(b);
continue;
}
*a = b;
return 1;
}
}
static int convert_vconsole_to_x11(DBusConnection *connection) {
bool modified = false;
assert(connection);
if (isempty(state.vc_keymap)) {
modified =
!isempty(state.x11_layout) ||
!isempty(state.x11_model) ||
!isempty(state.x11_variant) ||
!isempty(state.x11_options);
free_data_x11();
} else {
FILE *f;
unsigned n = 0;
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
if (!f)
return -errno;
for (;;) {
char **a;
int r;
r = read_next_mapping(f, &n, &a);
if (r < 0) {
fclose(f);
return r;
}
if (r == 0)
break;
if (!streq(state.vc_keymap, a[0])) {
strv_free(a);
continue;
}
if (!streq_ptr(state.x11_layout, strnulldash(a[1])) ||
!streq_ptr(state.x11_model, strnulldash(a[2])) ||
!streq_ptr(state.x11_variant, strnulldash(a[3])) ||
!streq_ptr(state.x11_options, strnulldash(a[4]))) {
if (free_and_set(&state.x11_layout, strnulldash(a[1])) < 0 ||
free_and_set(&state.x11_model, strnulldash(a[2])) < 0 ||
free_and_set(&state.x11_variant, strnulldash(a[3])) < 0 ||
free_and_set(&state.x11_options, strnulldash(a[4])) < 0) {
strv_free(a);
fclose(f);
return -ENOMEM;
}
modified = true;
}
strv_free(a);
break;
}
fclose(f);
}
if (modified) {
dbus_bool_t b;
DBusMessage *changed;
int r;
r = write_data_x11();
if (r < 0)
log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
changed = bus_properties_changed_new(
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"X11Layout\0"
"X11Model\0"
"X11Variant\0"
"X11Options\0");
if (!changed)
return -ENOMEM;
b = dbus_connection_send(connection, changed, NULL);
dbus_message_unref(changed);
if (!b)
return -ENOMEM;
}
return 0;
}
static int convert_x11_to_vconsole(DBusConnection *connection) {
bool modified = false;
assert(connection);
if (isempty(state.x11_layout)) {
modified =
!isempty(state.vc_keymap) ||
!isempty(state.vc_keymap_toggle);
free_data_x11();
} else {
FILE *f;
unsigned n = 0;
unsigned best_matching = 0;
char *new_keymap = NULL;
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
if (!f)
return -errno;
for (;;) {
char **a;
unsigned matching = 0;
int r;
r = read_next_mapping(f, &n, &a);
if (r < 0) {
fclose(f);
return r;
}
if (r == 0)
break;
/* Determine how well matching this entry is */
if (streq_ptr(state.x11_layout, a[1]))
/* If we got an exact match, this is best */
matching = 10;
else {
size_t x;
x = strcspn(state.x11_layout, ",");
/* We have multiple X layouts, look
* for an entry that matches our key
* with the everything but the first
* layout stripped off. */
if (x > 0 &&
strlen(a[1]) == x &&
strneq(state.x11_layout, a[1], x))
matching = 5;
else {
size_t w;
/* If that didn't work, strip
* off the other layouts from
* the entry, too */
w = strcspn(a[1], ",");
if (x > 0 && x == w &&
memcmp(state.x11_layout, a[1], x) == 0)
matching = 1;
}
}
if (matching > 0 &&
streq_ptr(state.x11_model, a[2])) {
matching++;
if (streq_ptr(state.x11_variant, a[3])) {
matching++;
if (streq_ptr(state.x11_options, a[4]))
matching++;
}
}
/* The best matching entry so far, then let's
* save that */
if (matching > best_matching) {
best_matching = matching;
free(new_keymap);
new_keymap = strdup(a[0]);
if (!new_keymap) {
strv_free(a);
fclose(f);
return -ENOMEM;
}
}
strv_free(a);
}
fclose(f);
if (!streq_ptr(state.vc_keymap, new_keymap)) {
free(state.vc_keymap);
state.vc_keymap = new_keymap;
free(state.vc_keymap_toggle);
state.vc_keymap_toggle = NULL;
modified = true;
} else
free(new_keymap);
}
if (modified) {
dbus_bool_t b;
DBusMessage *changed;
int r;
r = write_data_vconsole();
if (r < 0)
log_error("Failed to set virtual console keymap: %s", strerror(-r));
changed = bus_properties_changed_new(
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap\0"
"VConsoleKeymapToggle\0");
if (!changed)
return -ENOMEM;
b = dbus_connection_send(connection, changed, NULL);
dbus_message_unref(changed);
if (!b)
return -ENOMEM;
return load_vconsole_keymap(connection, NULL);
}
return 0;
}
static int append_locale(DBusMessageIter *i, const char *property, void *userdata) {
int r, c = 0, p;
char **l;
l = new0(char*, _PROP_MAX+1);
if (!l)
return -ENOMEM;
for (p = 0; p < _PROP_MAX; p++) {
char *t;
if (isempty(data[p]))
continue;
if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) {
strv_free(l);
return -ENOMEM;
}
l[c++] = t;
}
r = bus_property_append_strv(i, property, (void*) l);
strv_free(l);
return r;
}
static const BusProperty bus_locale_properties[] = {
{ "Locale", append_locale, "as", 0 },
{ "X11Layout", bus_property_append_string, "s", offsetof(State, x11_layout), true },
{ "X11Model", bus_property_append_string, "s", offsetof(State, x11_model), true },
{ "X11Variant", bus_property_append_string, "s", offsetof(State, x11_variant), true },
{ "X11Options", bus_property_append_string, "s", offsetof(State, x11_options), true },
{ "VConsoleKeymap", bus_property_append_string, "s", offsetof(State, vc_keymap), true },
{ "VConsoleKeymapToggle", bus_property_append_string, "s", offsetof(State, vc_keymap_toggle), true },
{ NULL, }
};
static const BusBoundProperties bps[] = {
{ "org.freedesktop.locale1", bus_locale_properties, &state },
{ NULL, }
};
static DBusHandlerResult locale_message_handler(
DBusConnection *connection,
DBusMessage *message,
void *userdata) {
DBusMessage *reply = NULL, *changed = NULL;
DBusError error;
int r;
assert(connection);
assert(message);
dbus_error_init(&error);
if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetLocale")) {
char **l = NULL, **i;
dbus_bool_t interactive;
DBusMessageIter iter;
bool modified = false;
bool passed[_PROP_MAX] = {};
int p;
if (!dbus_message_iter_init(message, &iter))
return bus_send_error_reply(connection, message, NULL, -EINVAL);
r = bus_parse_strv_iter(&iter, &l);
if (r < 0) {
if (r == -ENOMEM)
goto oom;
return bus_send_error_reply(connection, message, NULL, r);
}
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
strv_free(l);
return bus_send_error_reply(connection, message, NULL, -EINVAL);
}
dbus_message_iter_get_basic(&iter, &interactive);
/* Check whether a variable changed and if so valid */
STRV_FOREACH(i, l) {
bool valid = false;
for (p = 0; p < _PROP_MAX; p++) {
size_t k;
k = strlen(names[p]);
if (startswith(*i, names[p]) &&
(*i)[k] == '=' &&
string_is_safe((*i) + k + 1)) {
valid = true;
passed[p] = true;
if (!streq_ptr(*i + k + 1, data[p]))
modified = true;
break;
}
}
if (!valid) {
strv_free(l);
return bus_send_error_reply(connection, message, NULL, -EINVAL);
}
}
/* Check whether a variable is unset */
if (!modified) {
for (p = 0; p < _PROP_MAX; p++)
if (!isempty(data[p]) && !passed[p]) {
modified = true;
break;
}
}
if (modified) {
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, NULL, &error);
if (r < 0) {
strv_free(l);
return bus_send_error_reply(connection, message, &error, r);
}
STRV_FOREACH(i, l) {
for (p = 0; p < _PROP_MAX; p++) {
size_t k;
k = strlen(names[p]);
if (startswith(*i, names[p]) && (*i)[k] == '=') {
char *t;
t = strdup(*i + k + 1);
if (!t) {
strv_free(l);
goto oom;
}
free(data[p]);
data[p] = t;
break;
}
}
}
strv_free(l);
for (p = 0; p < _PROP_MAX; p++) {
if (passed[p])
continue;
free(data[p]);
data[p] = NULL;
}
simplify();
r = write_data_locale();
if (r < 0) {
log_error("Failed to set locale: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
}
push_data(connection);
log_info("Changed locale information.");
changed = bus_properties_changed_new(
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"Locale\0");
if (!changed)
goto oom;
} else
strv_free(l);
} else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetVConsoleKeyboard")) {
const char *keymap, *keymap_toggle;
dbus_bool_t convert, interactive;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_STRING, &keymap,
DBUS_TYPE_STRING, &keymap_toggle,
DBUS_TYPE_BOOLEAN, &convert,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
if (isempty(keymap))
keymap = NULL;
if (isempty(keymap_toggle))
keymap_toggle = NULL;
if (!streq_ptr(keymap, state.vc_keymap) ||
!streq_ptr(keymap_toggle, state.vc_keymap_toggle)) {
if ((keymap && (!filename_is_safe(keymap) || !string_is_safe(keymap))) ||
(keymap_toggle && (!filename_is_safe(keymap_toggle) || !string_is_safe(keymap_toggle))))
return bus_send_error_reply(connection, message, NULL, -EINVAL);
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
if (free_and_set(&state.vc_keymap, keymap) < 0 ||
free_and_set(&state.vc_keymap_toggle, keymap_toggle) < 0)
goto oom;
r = write_data_vconsole();
if (r < 0) {
log_error("Failed to set virtual console keymap: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
}
log_info("Changed virtual console keymap to '%s'", strempty(state.vc_keymap));
r = load_vconsole_keymap(connection, NULL);
if (r < 0)
log_error("Failed to request keymap reload: %s", strerror(-r));
changed = bus_properties_changed_new(
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap\0"
"VConsoleKeymapToggle\0");
if (!changed)
goto oom;
if (convert) {
r = convert_vconsole_to_x11(connection);
if (r < 0)
log_error("Failed to convert keymap data: %s", strerror(-r));
}
}
} else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetX11Keyboard")) {
const char *layout, *model, *variant, *options;
dbus_bool_t convert, interactive;
if (!dbus_message_get_args(
message,
&error,
DBUS_TYPE_STRING, &layout,
DBUS_TYPE_STRING, &model,
DBUS_TYPE_STRING, &variant,
DBUS_TYPE_STRING, &options,
DBUS_TYPE_BOOLEAN, &convert,
DBUS_TYPE_BOOLEAN, &interactive,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
if (isempty(layout))
layout = NULL;
if (isempty(model))
model = NULL;
if (isempty(variant))
variant = NULL;
if (isempty(options))
options = NULL;
if (!streq_ptr(layout, state.x11_layout) ||
!streq_ptr(model, state.x11_model) ||
!streq_ptr(variant, state.x11_variant) ||
!streq_ptr(options, state.x11_options)) {
if ((layout && !string_is_safe(layout)) ||
(model && !string_is_safe(model)) ||
(variant && !string_is_safe(variant)) ||
(options && !string_is_safe(options)))
return bus_send_error_reply(connection, message, NULL, -EINVAL);
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
if (free_and_set(&state.x11_layout, layout) < 0 ||
free_and_set(&state.x11_model, model) < 0 ||
free_and_set(&state.x11_variant, variant) < 0 ||
free_and_set(&state.x11_options, options) < 0)
goto oom;
r = write_data_x11();
if (r < 0) {
log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
return bus_send_error_reply(connection, message, NULL, r);
}
log_info("Changed X11 keyboard layout to '%s'", strempty(state.x11_layout));
changed = bus_properties_changed_new(
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"X11Layout\0"
"X11Model\0"
"X11Variant\0"
"X11Options\0");
if (!changed)
goto oom;
if (convert) {
r = convert_x11_to_vconsole(connection);
if (r < 0)
log_error("Failed to convert keymap data: %s", strerror(-r));
}
}
} else
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
if (!bus_maybe_send_reply(connection, message, reply))
goto oom;
dbus_message_unref(reply);
reply = NULL;
if (changed) {
if (!dbus_connection_send(connection, changed, NULL))
goto oom;
dbus_message_unref(changed);
}
return DBUS_HANDLER_RESULT_HANDLED;
oom:
if (reply)
dbus_message_unref(reply);
if (changed)
dbus_message_unref(changed);
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static int connect_bus(DBusConnection **_bus) {
static const DBusObjectPathVTable locale_vtable = {
.message_function = locale_message_handler
};
DBusError error;
DBusConnection *bus = NULL;
int r;
assert(_bus);
dbus_error_init(&error);
bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
if (!bus) {
log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
r = -ECONNREFUSED;
goto fail;
}
dbus_connection_set_exit_on_disconnect(bus, FALSE);
if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL) ||
!dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) {
r = log_oom();
goto fail;
}
r = dbus_bus_request_name(bus, "org.freedesktop.locale1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
if (dbus_error_is_set(&error)) {
log_error("Failed to register name on bus: %s", bus_error_message(&error));
r = -EEXIST;
goto fail;
}
if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
log_error("Failed to acquire name.");
r = -EEXIST;
goto fail;
}
if (_bus)
*_bus = bus;
return 0;
fail:
dbus_connection_close(bus);
dbus_connection_unref(bus);
dbus_error_free(&error);
return r;
}
int main(int argc, char *argv[]) {
int r;
DBusConnection *bus = NULL;
bool exiting = false;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
label_init("/etc");
umask(0022);
if (argc == 2 && streq(argv[1], "--introspect")) {
fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
"<node>\n", stdout);
fputs(locale_interface, stdout);
fputs("</node>\n", stdout);
return 0;
}
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto finish;
}
r = read_data();
if (r < 0) {
log_error("Failed to read locale data: %s", strerror(-r));
goto finish;
}
r = connect_bus(&bus);
if (r < 0)
goto finish;
remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
for (;;) {
if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
break;
if (!exiting && remain_until < now(CLOCK_MONOTONIC)) {
exiting = true;
bus_async_unregister_and_exit(bus, "org.freedesktop.locale1");
}
}
r = 0;
finish:
free_data();
if (bus) {
dbus_connection_flush(bus);
dbus_connection_close(bus);
dbus_connection_unref(bus);
}
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}