localed.c revision 4034a06ddb82ec9868cd52496fef2f5faa25575f
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 Copyright 2013 Kay Sievers
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***/
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <string.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <unistd.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-bus.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
afc5dbf37fd2399d37976388d9dd9ab470ecf446Lennart Poettering#include "mkdir.h"
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include "strv.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "def.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "env-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fileio.h"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen#include "fileio-label.h"
0b452006de98294d1690f045f6ea2f7f6630ec3bRonny Chevalier#include "bus-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "bus-error.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "bus-message.h"
15a5e95075a7f6007dd97b2a165c8ed16fe683dfLennart Poettering#include "event-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "locale-util.h"
7ccbd1ae843d77275f2c542582a9a80e5e058a70Lennart Poettering#include "selinux-util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#ifdef HAVE_XKBCOMMON
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include <xkbcommon/xkbcommon.h>
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#endif
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekenum {
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering /* We don't list LC_ALL here on purpose. People should be
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek * using LANG instead. */
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LANG,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LANGUAGE,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LC_CTYPE,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LC_NUMERIC,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LC_TIME,
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering LOCALE_LC_COLLATE,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LC_MONETARY,
f8294e4175918117ca6c131720bcf287eadcd029Josh Triplett LOCALE_LC_MESSAGES,
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek LOCALE_LC_PAPER,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOCALE_LC_NAME,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOCALE_LC_ADDRESS,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOCALE_LC_TELEPHONE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOCALE_LC_MEASUREMENT,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOCALE_LC_IDENTIFICATION,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _LOCALE_MAX
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic const char * const names[_LOCALE_MAX] = {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LANG] = "LANG",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LANGUAGE] = "LANGUAGE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_CTYPE] = "LC_CTYPE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_NUMERIC] = "LC_NUMERIC",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_TIME] = "LC_TIME",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_COLLATE] = "LC_COLLATE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_MONETARY] = "LC_MONETARY",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_MESSAGES] = "LC_MESSAGES",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_PAPER] = "LC_PAPER",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_NAME] = "LC_NAME",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_ADDRESS] = "LC_ADDRESS",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringtypedef struct Context {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *locale[_LOCALE_MAX];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *x11_layout;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *x11_model;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *x11_variant;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *x11_options;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering char *vc_keymap;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *vc_keymap_toggle;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Hashmap *polkit_registry;
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler} Context;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic const char* nonempty(const char *s) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return isempty(s) ? NULL : s;
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler}
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void free_and_replace(char **s, char *v) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free(*s);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *s = v;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic bool startswith_comma(const char *s, const char *prefix) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *t;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return s && (t = startswith(s, prefix)) && (*t == ',');
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poetteringstatic void context_free_x11(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_layout, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_model, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_variant, NULL);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt free_and_replace(&c->x11_options, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poetteringstatic void context_free_vconsole(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->vc_keymap, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->vc_keymap_toggle, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void context_free_locale(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0; p < _LOCALE_MAX; p++)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->locale[p], NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void context_free(Context *c) {
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering context_free_locale(c);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering context_free_x11(c);
3b97fcbd28f92a1e51887fef5de8844a89bde523Lennart Poettering context_free_vconsole(c);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bus_verify_polkit_async_registry_free(c->polkit_registry);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void locale_simplify(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p]))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->locale[p], NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int locale_read_data(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek context_free_locale(c);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = parse_env_file("/etc/locale.conf", NEWLINE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LANG", &c->locale[LOCALE_LANG],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LANGUAGE", &c->locale[LOCALE_LANGUAGE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_TIME", &c->locale[LOCALE_LC_TIME],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_COLLATE", &c->locale[LOCALE_LC_COLLATE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_PAPER", &c->locale[LOCALE_LC_PAPER],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_NAME", &c->locale[LOCALE_LC_NAME],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek if (r == -ENOENT) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* Fill in what we got passed from systemd. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0; p < _LOCALE_MAX; p++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = free_and_strdup(&c->locale[p],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering nonempty(getenv(names[p])));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering locale_simplify(c);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int vconsole_read_data(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering context_free_vconsole(c);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = parse_env_file("/etc/vconsole.conf", NEWLINE,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "KEYMAP", &c->vc_keymap,
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek "KEYMAP_TOGGLE", &c->vc_keymap_toggle,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0 && r != -ENOENT)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int x11_read_data(Context *c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_fclose_ FILE *f;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char line[LINE_MAX];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bool in_section = false;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering context_free_x11(c);
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!f)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return errno == ENOENT ? 0 : -errno;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (fgets(line, sizeof(line), f)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *l;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char_array_0(line);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = strstrip(line);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (l[0] == 0 || l[0] == '#')
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (in_section && first_word(l, "Option")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_strv_free_ char **a = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = strv_split_quoted(&a, l, 0);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (strv_length(a) == 3) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (streq(a[1], "XkbLayout")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_layout, a[2]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering a[2] = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (streq(a[1], "XkbModel")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_model, a[2]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering a[2] = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering } else if (streq(a[1], "XkbVariant")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_variant, a[2]);
ec5ff4445cca6a1d786b8da36cf6fe0acc0b94c8Filipe Brandenburger a[2] = NULL;
ec5ff4445cca6a1d786b8da36cf6fe0acc0b94c8Filipe Brandenburger } else if (streq(a[1], "XkbOptions")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering free_and_replace(&c->x11_options, a[2]);
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek a[2] = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (!in_section && first_word(l, "Section")) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_strv_free_ char **a = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = strv_split_quoted(&a, l, 0);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (strv_length(a) == 2 && streq(a[1], "InputClass"))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering in_section = true;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (in_section && first_word(l, "EndSection"))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering in_section = false;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int context_read_data(Context *c) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r, q, p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = locale_read_data(c);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering q = vconsole_read_data(c);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering p = x11_read_data(c);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r < 0 ? r : q < 0 ? q : p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int locale_write_data(Context *c, char ***settings) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r, p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_strv_free_ char **l = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* Set values will be returned as strv in *settings on success. */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = load_env_file(NULL, "/etc/locale.conf", NULL, &l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0 && r != -ENOENT)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (p = 0; p < _LOCALE_MAX; p++) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_free_ char *t = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char **u;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(names[p]);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (isempty(c->locale[p])) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l = strv_env_unset(l, names[p]);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering continue;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering u = strv_env_set(l, t);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!u)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return -ENOMEM;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering strv_free(l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering l = u;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (strv_isempty(l)) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (unlink("/etc/locale.conf") < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return errno == ENOENT ? 0 : -errno;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = write_env_file_label("/etc/locale.conf", l);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering *settings = l;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = NULL;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering return 0;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int locale_update_system_manager(Context *c, sd_bus *bus) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char **l_unset = NULL;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering _cleanup_strv_free_ char **l_set = NULL;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering sd_bus_error error = SD_BUS_ERROR_NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned c_set, c_unset, p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering assert(bus);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_unset = new0(char*, _LOCALE_MAX);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!l_unset)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_set = new0(char*, _LOCALE_MAX);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek if (!l_set)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(names[p]);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (isempty(c->locale[p]))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l_unset[c_set++] = (char*) names[p];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *s;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen l_set[c_unset++] = s;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen }
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(c_set + c_unset == _LOCALE_MAX);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering r = sd_bus_message_new_method_call(bus, &m,
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering "org.freedesktop.systemd1",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "/org/freedesktop/systemd1",
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering "org.freedesktop.systemd1.Manager",
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering "UnsetAndSetEnvironment");
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering if (r < 0)
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append_strv(m, l_unset);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append_strv(m, l_set);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_call(bus, m, 0, &error, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_error_errno(r, "Failed to update the manager environment: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int vconsole_write_data(Context *c) {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_strv_free_ char **l = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l);
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering if (r < 0 && r != -ENOENT)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (isempty(c->vc_keymap))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = strv_env_unset(l, "KEYMAP");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else {
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering _cleanup_free_ char *s = NULL;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek char **u;
03ee5c38cb0da193dd08733fb4c0c2809cee6a99Lennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek s = strappend("KEYMAP=", c->vc_keymap);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!s)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt u = strv_env_set(l, s);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!u)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt l = u;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4a61c3e51e96a747c30598d78ee3a24e7c569e9fZbigniew Jędrzejewski-Szmek if (isempty(c->vc_keymap_toggle))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = strv_env_unset(l, "KEYMAP_TOGGLE");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *s = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char **u;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!s)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return -ENOMEM;
6baa7db00812437bbc87e73faa1a11b6cf631958Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering u = strv_env_set(l, s);
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering if (!u)
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt return -ENOMEM;
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strv_free(l);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering l = u;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (strv_isempty(l)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (unlink("/etc/vconsole.conf") < 0)
8531ae707d4d0203e83304d4af948b8169a5fce1Lennart Poettering return errno == ENOENT ? 0 : -errno;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return write_env_file_label("/etc/vconsole.conf", l);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering}
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poetteringstatic int x11_write_data(Context *c) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering _cleanup_free_ char *temp_path = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering int r;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (isempty(c->x11_layout) &&
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering isempty(c->x11_model) &&
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering isempty(c->x11_variant) &&
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering isempty(c->x11_options)) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return errno == ENOENT ? 0 : -errno;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return 0;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
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(c->x11_layout))
fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
if (!isempty(c->x11_model))
fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model);
if (!isempty(c->x11_variant))
fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant);
if (!isempty(c->x11_options))
fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->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);
return r;
} else
return 0;
}
static int vconsole_reload(sd_bus *bus) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"RestartUnit",
&error,
NULL,
"ss", "systemd-vconsole-setup.service", "replace");
if (r < 0)
log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
return r;
}
static const char* strnulldash(const char *s) {
return isempty(s) || streq(s, "-") ? NULL : s;
}
static int read_next_mapping(const char* filename,
unsigned min_fields, unsigned max_fields,
FILE *f, unsigned *n, char ***a) {
assert(f);
assert(n);
assert(a);
for (;;) {
char line[LINE_MAX];
char *l, **b;
int r;
size_t length;
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;
r = strv_split_quoted(&b, l, 0);
if (r < 0)
return r;
length = strv_length(b);
if (length < min_fields || length > max_fields) {
log_error("Invalid line %s:%u, ignoring.", filename, *n);
strv_free(b);
continue;
}
*a = b;
return 1;
}
}
static int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
bool modified = false;
assert(bus);
if (isempty(c->vc_keymap)) {
modified =
!isempty(c->x11_layout) ||
!isempty(c->x11_model) ||
!isempty(c->x11_variant) ||
!isempty(c->x11_options);
context_free_x11(c);
} else {
_cleanup_fclose_ FILE *f = NULL;
unsigned n = 0;
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
if (!f)
return -errno;
for (;;) {
_cleanup_strv_free_ char **a = NULL;
int r;
r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
if (r < 0)
return r;
if (r == 0)
break;
if (!streq(c->vc_keymap, a[0]))
continue;
if (!streq_ptr(c->x11_layout, strnulldash(a[1])) ||
!streq_ptr(c->x11_model, strnulldash(a[2])) ||
!streq_ptr(c->x11_variant, strnulldash(a[3])) ||
!streq_ptr(c->x11_options, strnulldash(a[4]))) {
if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 ||
free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 ||
free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 ||
free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0)
return -ENOMEM;
modified = true;
}
break;
}
}
if (modified) {
int r;
r = x11_write_data(c);
if (r < 0)
return log_error_errno(r, "Failed to set X11 keyboard layout: %m");
log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
strempty(c->x11_layout),
strempty(c->x11_model),
strempty(c->x11_variant),
strempty(c->x11_options));
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
} else
log_debug("X11 keyboard layout was not modified.");
return 0;
}
static int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) {
const char *dir;
_cleanup_free_ char *n;
if (x11_variant)
n = strjoin(x11_layout, "-", x11_variant, NULL);
else
n = strdup(x11_layout);
if (!n)
return -ENOMEM;
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
_cleanup_free_ char *p = NULL, *pz = NULL;
bool uncompressed;
p = strjoin(dir, "xkb/", n, ".map", NULL);
pz = strjoin(dir, "xkb/", n, ".map.gz", NULL);
if (!p || !pz)
return -ENOMEM;
uncompressed = access(p, F_OK) == 0;
if (uncompressed || access(pz, F_OK) == 0) {
log_debug("Found converted keymap %s at %s",
n, uncompressed ? p : pz);
*new_keymap = n;
n = NULL;
return 1;
}
}
return 0;
}
static int find_legacy_keymap(Context *c, char **new_keymap) {
_cleanup_fclose_ FILE *f;
unsigned n = 0;
unsigned best_matching = 0;
int r;
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
if (!f)
return -errno;
for (;;) {
_cleanup_strv_free_ char **a = NULL;
unsigned matching = 0;
r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a);
if (r < 0)
return r;
if (r == 0)
break;
/* Determine how well matching this entry is */
if (streq_ptr(c->x11_layout, a[1]))
/* If we got an exact match, this is best */
matching = 10;
else {
/* We have multiple X layouts, look for an
* entry that matches our key with everything
* but the first layout stripped off. */
if (startswith_comma(c->x11_layout, a[1]))
matching = 5;
else {
char *x;
/* If that didn't work, strip off the
* other layouts from the entry, too */
x = strndupa(a[1], strcspn(a[1], ","));
if (startswith_comma(c->x11_layout, x))
matching = 1;
}
}
if (matching > 0) {
if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) {
matching++;
if (streq_ptr(c->x11_variant, a[3])) {
matching++;
if (streq_ptr(c->x11_options, a[4]))
matching++;
}
}
}
/* The best matching entry so far, then let's save that */
if (matching >= MAX(best_matching, 1u)) {
log_debug("Found legacy keymap %s with score %u",
a[0], matching);
if (matching > best_matching) {
best_matching = matching;
r = free_and_strdup(new_keymap, a[0]);
if (r < 0)
return r;
}
}
}
if (best_matching < 10 && c->x11_layout) {
/* The best match is only the first part of the X11
* keymap. Check if we have a converted map which
* matches just the first layout.
*/
char *l, *v = NULL, *converted;
l = strndupa(c->x11_layout, strcspn(c->x11_layout, ","));
if (c->x11_variant)
v = strndupa(c->x11_variant, strcspn(c->x11_variant, ","));
r = find_converted_keymap(l, v, &converted);
if (r < 0)
return r;
if (r > 0)
free_and_replace(new_keymap, converted);
}
return 0;
}
static int find_language_fallback(const char *lang, char **language) {
_cleanup_fclose_ FILE *f = NULL;
unsigned n = 0;
assert(language);
f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re");
if (!f)
return -errno;
for (;;) {
_cleanup_strv_free_ char **a = NULL;
int r;
r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a);
if (r <= 0)
return r;
if (streq(lang, a[0])) {
assert(strv_length(a) == 2);
*language = a[1];
a[1] = NULL;
return 1;
}
}
assert_not_reached("should not be here");
}
static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
bool modified = false;
int r;
assert(bus);
if (isempty(c->x11_layout)) {
modified =
!isempty(c->vc_keymap) ||
!isempty(c->vc_keymap_toggle);
context_free_x11(c);
} else {
char *new_keymap = NULL;
r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap);
if (r < 0)
return r;
else if (r == 0) {
r = find_legacy_keymap(c, &new_keymap);
if (r < 0)
return r;
}
if (!streq_ptr(c->vc_keymap, new_keymap)) {
free_and_replace(&c->vc_keymap, new_keymap);
free_and_replace(&c->vc_keymap_toggle, NULL);
modified = true;
} else
free(new_keymap);
}
if (modified) {
r = vconsole_write_data(c);
if (r < 0)
log_error_errno(r, "Failed to set virtual console keymap: %m");
log_info("Changed virtual console keymap to '%s' toggle '%s'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap", "VConsoleKeymapToggle", NULL);
return vconsole_reload(bus);
} else
log_debug("Virtual console keymap was not modified.");
return 0;
}
static int property_get_locale(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Context *c = userdata;
_cleanup_strv_free_ char **l = NULL;
int p, q;
l = new0(char*, _LOCALE_MAX+1);
if (!l)
return -ENOMEM;
for (p = 0, q = 0; p < _LOCALE_MAX; p++) {
char *t;
if (isempty(c->locale[p]))
continue;
if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0)
return -ENOMEM;
l[q++] = t;
}
return sd_bus_message_append_strv(reply, l);
}
static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
_cleanup_strv_free_ char **l = NULL;
char **i;
const char *lang = NULL;
int interactive;
bool modified = false;
bool have[_LOCALE_MAX] = {};
int p;
int r;
r = bus_message_read_strv_extend(m, &l);
if (r < 0)
return r;
r = sd_bus_message_read_basic(m, 'b', &interactive);
if (r < 0)
return r;
/* Check whether a variable changed and if it is valid */
STRV_FOREACH(i, l) {
bool valid = false;
for (p = 0; p < _LOCALE_MAX; p++) {
size_t k;
k = strlen(names[p]);
if (startswith(*i, names[p]) &&
(*i)[k] == '=' &&
locale_is_valid((*i) + k + 1)) {
valid = true;
have[p] = true;
if (p == LOCALE_LANG)
lang = (*i) + k + 1;
if (!streq_ptr(*i + k + 1, c->locale[p]))
modified = true;
break;
}
}
if (!valid)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
}
/* If LANG was specified, but not LANGUAGE, check if we should
* set it based on the language fallback table. */
if (have[LOCALE_LANG] && !have[LOCALE_LANGUAGE]) {
_cleanup_free_ char *language = NULL;
assert(lang);
(void) find_language_fallback(lang, &language);
if (language) {
log_debug("Converted LANG=%s to LANGUAGE=%s", lang, language);
if (!streq_ptr(language, c->locale[LOCALE_LANGUAGE])) {
r = strv_extendf(&l, "LANGUAGE=%s", language);
if (r < 0)
return r;
have[LOCALE_LANGUAGE] = true;
modified = true;
}
}
}
/* Check whether a variable is unset */
if (!modified)
for (p = 0; p < _LOCALE_MAX; p++)
if (!isempty(c->locale[p]) && !have[p]) {
modified = true;
break;
}
if (modified) {
_cleanup_strv_free_ char **settings = NULL;
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-locale",
interactive,
UID_INVALID,
&c->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
STRV_FOREACH(i, l)
for (p = 0; p < _LOCALE_MAX; p++) {
size_t k;
k = strlen(names[p]);
if (startswith(*i, names[p]) && (*i)[k] == '=') {
r = free_and_strdup(&c->locale[p], *i + k + 1);
if (r < 0)
return r;
break;
}
}
for (p = 0; p < _LOCALE_MAX; p++) {
if (have[p])
continue;
free_and_replace(&c->locale[p], NULL);
}
locale_simplify(c);
r = locale_write_data(c, &settings);
if (r < 0) {
log_error_errno(r, "Failed to set locale: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r));
}
locale_update_system_manager(c, bus);
if (settings) {
_cleanup_free_ char *line;
line = strv_join(settings, ", ");
log_info("Changed locale to %s.", strnull(line));
} else
log_info("Changed locale to unset.");
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"Locale", NULL);
} else
log_debug("Locale settings were not modified.");
return sd_bus_reply_method_return(m, NULL);
}
static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *keymap, *keymap_toggle;
int convert, interactive;
int r;
r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive);
if (r < 0)
return r;
if (isempty(keymap))
keymap = NULL;
if (isempty(keymap_toggle))
keymap_toggle = NULL;
if (!streq_ptr(keymap, c->vc_keymap) ||
!streq_ptr(keymap_toggle, c->vc_keymap_toggle)) {
if ((keymap && (!filename_is_valid(keymap) || !string_is_safe(keymap))) ||
(keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle))))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data");
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-keyboard",
interactive,
UID_INVALID,
&c->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
if (free_and_strdup(&c->vc_keymap, keymap) < 0 ||
free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0)
return -ENOMEM;
r = vconsole_write_data(c);
if (r < 0) {
log_error_errno(r, "Failed to set virtual console keymap: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r));
}
log_info("Changed virtual console keymap to '%s' toggle '%s'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
r = vconsole_reload(bus);
if (r < 0)
log_error_errno(r, "Failed to request keymap reload: %m");
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap", "VConsoleKeymapToggle", NULL);
if (convert) {
r = vconsole_convert_to_x11(c, bus);
if (r < 0)
log_error_errno(r, "Failed to convert keymap data: %m");
}
}
return sd_bus_reply_method_return(m, NULL);
}
#ifdef HAVE_XKBCOMMON
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
const char *fmt;
fmt = strjoina("libxkbcommon: ", format);
log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
}
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
const struct xkb_rule_names rmlvo = {
.model = model,
.layout = layout,
.variant = variant,
.options = options,
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
int r;
/* compile keymap from RMLVO information to check out its validity */
ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
if (!ctx) {
r = -ENOMEM;
goto exit;
}
xkb_context_set_log_fn(ctx, log_xkb);
km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!km) {
r = -EINVAL;
goto exit;
}
r = 0;
exit:
xkb_keymap_unref(km);
xkb_context_unref(ctx);
return r;
}
#else
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
return 0;
}
#endif
static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *layout, *model, *variant, *options;
int convert, interactive;
int r;
r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive);
if (r < 0)
return r;
if (isempty(layout))
layout = NULL;
if (isempty(model))
model = NULL;
if (isempty(variant))
variant = NULL;
if (isempty(options))
options = NULL;
if (!streq_ptr(layout, c->x11_layout) ||
!streq_ptr(model, c->x11_model) ||
!streq_ptr(variant, c->x11_variant) ||
!streq_ptr(options, c->x11_options)) {
if ((layout && !string_is_safe(layout)) ||
(model && !string_is_safe(model)) ||
(variant && !string_is_safe(variant)) ||
(options && !string_is_safe(options)))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data");
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-keyboard",
interactive,
UID_INVALID,
&c->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = verify_xkb_rmlvo(model, layout, variant, options);
if (r < 0) {
log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
strempty(model), strempty(layout), strempty(variant), strempty(options));
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
}
if (free_and_strdup(&c->x11_layout, layout) < 0 ||
free_and_strdup(&c->x11_model, model) < 0 ||
free_and_strdup(&c->x11_variant, variant) < 0 ||
free_and_strdup(&c->x11_options, options) < 0)
return -ENOMEM;
r = x11_write_data(c);
if (r < 0) {
log_error_errno(r, "Failed to set X11 keyboard layout: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r));
}
log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
strempty(c->x11_layout),
strempty(c->x11_model),
strempty(c->x11_variant),
strempty(c->x11_options));
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
if (convert) {
r = x11_convert_to_vconsole(c, bus);
if (r < 0)
log_error_errno(r, "Failed to convert keymap data: %m");
}
}
return sd_bus_reply_method_return(m, NULL);
}
static const sd_bus_vtable locale_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Locale", "as", property_get_locale, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Layout", "s", NULL, offsetof(Context, x11_layout), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Model", "s", NULL, offsetof(Context, x11_model), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Variant", "s", NULL, offsetof(Context, x11_variant), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("X11Options", "s", NULL, offsetof(Context, x11_options), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("VConsoleKeymap", "s", NULL, offsetof(Context, vc_keymap), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", NULL, offsetof(Context, vc_keymap_toggle), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD("SetLocale", "asb", NULL, method_set_locale, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetVConsoleKeyboard", "ssbb", NULL, method_set_vc_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetX11Keyboard", "ssssbb", NULL, method_set_x11_keyboard, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
int r;
assert(c);
assert(event);
assert(_bus);
r = sd_bus_default_system(&bus);
if (r < 0)
return log_error_errno(r, "Failed to get system bus connection: %m");
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
if (r < 0)
return log_error_errno(r, "Failed to register object: %m");
r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0);
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
*_bus = bus;
bus = NULL;
return 0;
}
int main(int argc, char *argv[]) {
_cleanup_(context_free) Context context = {};
_cleanup_event_unref_ sd_event *event = NULL;
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
umask(0022);
mac_selinux_init("/etc");
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto finish;
}
r = sd_event_default(&event);
if (r < 0) {
log_error_errno(r, "Failed to allocate event loop: %m");
goto finish;
}
sd_event_set_watchdog(event, true);
r = connect_bus(&context, event, &bus);
if (r < 0)
goto finish;
r = context_read_data(&context);
if (r < 0) {
log_error_errno(r, "Failed to read locale data: %m");
goto finish;
}
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}