diff options
-rw-r--r-- | src/locale/.gitignore | 1 | ||||
l--------- | src/locale/Makefile | 1 | ||||
-rw-r--r-- | src/locale/kbd-model-map | 68 | ||||
-rw-r--r-- | src/locale/language-fallback-map | 9 | ||||
-rw-r--r-- | src/locale/localectl.c | 684 | ||||
-rw-r--r-- | src/locale/localed.c | 1305 | ||||
-rw-r--r-- | src/locale/org.freedesktop.locale1.conf | 27 | ||||
-rw-r--r-- | src/locale/org.freedesktop.locale1.policy.in | 40 | ||||
-rw-r--r-- | src/locale/org.freedesktop.locale1.service | 12 |
9 files changed, 0 insertions, 2147 deletions
diff --git a/src/locale/.gitignore b/src/locale/.gitignore deleted file mode 100644 index b1e0ba755e..0000000000 --- a/src/locale/.gitignore +++ /dev/null @@ -1 +0,0 @@ -org.freedesktop.locale1.policy diff --git a/src/locale/Makefile b/src/locale/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/locale/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/locale/kbd-model-map b/src/locale/kbd-model-map deleted file mode 100644 index 8fa984f83b..0000000000 --- a/src/locale/kbd-model-map +++ /dev/null @@ -1,68 +0,0 @@ -# Generated from system-config-keyboard's model list -# consolelayout xlayout xmodel xvariant xoptions -sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp -nl nl pc105 - terminate:ctrl_alt_bksp -mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -trq tr pc105 - terminate:ctrl_alt_bksp -uk gb pc105 - terminate:ctrl_alt_bksp -is-latin1 is pc105 - terminate:ctrl_alt_bksp -de de pc105 - terminate:ctrl_alt_bksp -la-latin1 latam pc105 - terminate:ctrl_alt_bksp -us us pc105+inet - terminate:ctrl_alt_bksp -ko kr pc105 - terminate:ctrl_alt_bksp -ro-std ro pc105 std terminate:ctrl_alt_bksp -de-latin1 de pc105 - terminate:ctrl_alt_bksp -slovene si pc105 - terminate:ctrl_alt_bksp -hu101 hu pc105 qwerty terminate:ctrl_alt_bksp -jp106 jp jp106 - terminate:ctrl_alt_bksp -croat hr pc105 - terminate:ctrl_alt_bksp -it2 it pc105 - terminate:ctrl_alt_bksp -hu hu pc105 - terminate:ctrl_alt_bksp -sr-latin rs pc105 latin terminate:ctrl_alt_bksp -fi fi pc105 - terminate:ctrl_alt_bksp -fr_CH ch pc105 fr terminate:ctrl_alt_bksp -dk-latin1 dk pc105 - terminate:ctrl_alt_bksp -fr fr pc105 - terminate:ctrl_alt_bksp -it it pc105 - terminate:ctrl_alt_bksp -ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -fr-latin1 fr pc105 - terminate:ctrl_alt_bksp -sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp -be-latin1 be pc105 - terminate:ctrl_alt_bksp -dk dk pc105 - terminate:ctrl_alt_bksp -fr-pc fr pc105 - terminate:ctrl_alt_bksp -bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -it-ibm it pc105 - terminate:ctrl_alt_bksp -cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -br-abnt2 br abnt2 - terminate:ctrl_alt_bksp -ro ro pc105 - terminate:ctrl_alt_bksp -us-acentos us pc105 intl terminate:ctrl_alt_bksp -pt-latin1 pt pc105 - terminate:ctrl_alt_bksp -ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp -tj_alt-UTF8 tj pc105 - terminate:ctrl_alt_bksp -de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp -no no pc105 - terminate:ctrl_alt_bksp -bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -dvorak us pc105 dvorak terminate:ctrl_alt_bksp -dvorak us pc105 dvorak-alt-intl terminate:ctrl_alt_bksp -ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp -pl2 pl pc105 - terminate:ctrl_alt_bksp -es es pc105 - terminate:ctrl_alt_bksp -ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp -ie ie pc105 - terminate:ctrl_alt_bksp -et ee pc105 - terminate:ctrl_alt_bksp -sk-qwerty sk pc105 - terminate:ctrl_alt_bksp,qwerty -sk-qwertz sk pc105 - terminate:ctrl_alt_bksp -fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp -fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp -cf ca pc105 - terminate:ctrl_alt_bksp -sv-latin1 se pc105 - terminate:ctrl_alt_bksp -sr-cy rs pc105 - terminate:ctrl_alt_bksp -gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -by by,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -il il pc105 - terminate:ctrl_alt_bksp -kazakh kz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -lt.baltic lt pc105 - terminate:ctrl_alt_bksp -lt.l4 lt pc105 - terminate:ctrl_alt_bksp -lt lt pc105 - terminate:ctrl_alt_bksp -khmer kh,us pc105 - terminate:ctrl_alt_bksp diff --git a/src/locale/language-fallback-map b/src/locale/language-fallback-map deleted file mode 100644 index 6aadda091a..0000000000 --- a/src/locale/language-fallback-map +++ /dev/null @@ -1,9 +0,0 @@ -csb_PL csb:pl -en_AU en_AU:en_GB -en_IE en_IE:en_GB -en_NZ en_NZ:en_GB -en_ZA en_ZA:en_GB -it_CH it_CH:it_IT -mai_IN mai:hi -nds_DE nds:de -szl_PL szl:pl diff --git a/src/locale/localectl.c b/src/locale/localectl.c deleted file mode 100644 index 515fca540a..0000000000 --- a/src/locale/localectl.c +++ /dev/null @@ -1,684 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - Copyright 2013 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <locale.h> -#include <stdlib.h> -#include <stdbool.h> -#include <getopt.h> -#include <string.h> -#include <ftw.h> - -#include "sd-bus.h" -#include "bus-util.h" -#include "bus-error.h" -#include "util.h" -#include "spawn-polkit-agent.h" -#include "build.h" -#include "strv.h" -#include "pager.h" -#include "set.h" -#include "def.h" -#include "virt.h" -#include "fileio.h" -#include "locale-util.h" - -static bool arg_no_pager = false; -static bool arg_ask_password = true; -static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; -static char *arg_host = NULL; -static bool arg_convert = true; - -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - -static void polkit_agent_open_if_enabled(void) { - - /* Open the polkit agent as a child process if necessary */ - if (!arg_ask_password) - return; - - if (arg_transport != BUS_TRANSPORT_LOCAL) - return; - - polkit_agent_open(); -} - -typedef struct StatusInfo { - char **locale; - const char *vconsole_keymap; - const char *vconsole_keymap_toggle; - const char *x11_layout; - const char *x11_model; - const char *x11_variant; - const char *x11_options; -} StatusInfo; - -static void print_overriden_variables(void) { - int r; - char *variables[_VARIABLE_LC_MAX] = {}; - LocaleVariable j; - bool print_warning = true; - - if (detect_container(NULL) > 0 || arg_host) - return; - - r = parse_env_file("/proc/cmdline", WHITESPACE, - "locale.LANG", &variables[VARIABLE_LANG], - "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], - "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "locale.LC_TIME", &variables[VARIABLE_LC_TIME], - "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], - "locale.LC_NAME", &variables[VARIABLE_LC_NAME], - "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL); - - if (r < 0 && r != -ENOENT) { - log_warning_errno(r, "Failed to read /proc/cmdline: %m"); - goto finish; - } - - for (j = 0; j < _VARIABLE_LC_MAX; j++) - if (variables[j]) { - if (print_warning) { - log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" - " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); - - print_warning = false; - } else - log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); - } - finish: - for (j = 0; j < _VARIABLE_LC_MAX; j++) - free(variables[j]); -} - -static void print_status_info(StatusInfo *i) { - assert(i); - - if (strv_isempty(i->locale)) - puts(" System Locale: n/a\n"); - else { - char **j; - - printf(" System Locale: %s\n", i->locale[0]); - STRV_FOREACH(j, i->locale + 1) - printf(" %s\n", *j); - } - - printf(" VC Keymap: %s\n", strna(i->vconsole_keymap)); - if (!isempty(i->vconsole_keymap_toggle)) - printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle); - - printf(" X11 Layout: %s\n", strna(i->x11_layout)); - if (!isempty(i->x11_model)) - printf(" X11 Model: %s\n", i->x11_model); - if (!isempty(i->x11_variant)) - printf(" X11 Variant: %s\n", i->x11_variant); - if (!isempty(i->x11_options)) - printf(" X11 Options: %s\n", i->x11_options); -} - -static int show_status(sd_bus *bus, char **args, unsigned n) { - StatusInfo info = {}; - static const struct bus_properties_map map[] = { - { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) }, - { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) }, - { "VConsoleKeymapToggle", "s", NULL, offsetof(StatusInfo, vconsole_keymap_toggle) }, - { "X11Layout", "s", NULL, offsetof(StatusInfo, x11_layout) }, - { "X11Model", "s", NULL, offsetof(StatusInfo, x11_model) }, - { "X11Variant", "s", NULL, offsetof(StatusInfo, x11_variant) }, - { "X11Options", "s", NULL, offsetof(StatusInfo, x11_options) }, - { "Locale", "as", NULL, offsetof(StatusInfo, locale) }, - {} - }; - int r; - - assert(bus); - - r = bus_map_all_properties(bus, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - map, - &info); - if (r < 0) { - log_error_errno(r, "Could not get properties: %m"); - goto fail; - } - - print_overriden_variables(); - print_status_info(&info); - -fail: - strv_free(info.locale); - return r; -} - -static int set_locale(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - int r; - - assert(bus); - assert(args); - - polkit_agent_open_if_enabled(); - - r = sd_bus_message_new_method_call( - bus, - &m, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "SetLocale"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(m, args + 1); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "b", arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_call(bus, m, 0, &error, NULL); - if (r < 0) { - log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); - return r; - } - - return 0; -} - -static int list_locales(sd_bus *bus, char **args, unsigned n) { - _cleanup_strv_free_ char **l = NULL; - int r; - - assert(args); - - r = get_locales(&l); - if (r < 0) - return log_error_errno(r, "Failed to read list of locales: %m"); - - pager_open_if_enabled(); - strv_print(l); - - return 0; -} - -static int set_vconsole_keymap(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - const char *map, *toggle_map; - int r; - - assert(bus); - assert(args); - - if (n > 3) { - log_error("Too many arguments."); - return -EINVAL; - } - - polkit_agent_open_if_enabled(); - - map = args[1]; - toggle_map = n > 2 ? args[2] : ""; - - r = sd_bus_call_method( - bus, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "SetVConsoleKeyboard", - &error, - NULL, - "ssbb", map, toggle_map, arg_convert, arg_ask_password); - if (r < 0) - log_error("Failed to set keymap: %s", bus_error_message(&error, -r)); - - return r; -} - -static Set *keymaps = NULL; - -static int nftw_cb( - const char *fpath, - const struct stat *sb, - int tflag, - struct FTW *ftwbuf) { - - char *p, *e; - int r; - - if (tflag != FTW_F) - return 0; - - if (!endswith(fpath, ".map") && - !endswith(fpath, ".map.gz")) - return 0; - - p = strdup(basename(fpath)); - if (!p) - return log_oom(); - - e = endswith(p, ".map"); - if (e) - *e = 0; - - e = endswith(p, ".map.gz"); - if (e) - *e = 0; - - r = set_consume(keymaps, p); - if (r < 0 && r != -EEXIST) - return log_error_errno(r, "Can't add keymap: %m"); - - return 0; -} - -static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { - _cleanup_strv_free_ char **l = NULL; - const char *dir; - - keymaps = set_new(&string_hash_ops); - if (!keymaps) - return log_oom(); - - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) - nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS); - - l = set_get_strv(keymaps); - if (!l) { - set_free_free(keymaps); - return log_oom(); - } - - set_free(keymaps); - - if (strv_isempty(l)) { - log_error("Couldn't find any console keymaps."); - return -ENOENT; - } - - strv_sort(l); - - pager_open_if_enabled(); - - strv_print(l); - - return 0; -} - -static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - const char *layout, *model, *variant, *options; - int r; - - assert(bus); - assert(args); - - if (n > 5) { - log_error("Too many arguments."); - return -EINVAL; - } - - polkit_agent_open_if_enabled(); - - layout = args[1]; - model = n > 2 ? args[2] : ""; - variant = n > 3 ? args[3] : ""; - options = n > 4 ? args[4] : ""; - - r = sd_bus_call_method( - bus, - "org.freedesktop.locale1", - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "SetX11Keyboard", - &error, - NULL, - "ssssbb", layout, model, variant, options, - arg_convert, arg_ask_password); - if (r < 0) - log_error("Failed to set keymap: %s", bus_error_message(&error, -r)); - - return r; -} - -static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_strv_free_ char **list = NULL; - char line[LINE_MAX]; - enum { - NONE, - MODELS, - LAYOUTS, - VARIANTS, - OPTIONS - } state = NONE, look_for; - int r; - - if (n > 2) { - log_error("Too many arguments."); - return -EINVAL; - } - - f = fopen("/usr/share/X11/xkb/rules/base.lst", "re"); - if (!f) - return log_error_errno(errno, "Failed to open keyboard mapping list. %m"); - - if (streq(args[0], "list-x11-keymap-models")) - look_for = MODELS; - else if (streq(args[0], "list-x11-keymap-layouts")) - look_for = LAYOUTS; - else if (streq(args[0], "list-x11-keymap-variants")) - look_for = VARIANTS; - else if (streq(args[0], "list-x11-keymap-options")) - look_for = OPTIONS; - else - assert_not_reached("Wrong parameter"); - - FOREACH_LINE(line, f, break) { - char *l, *w; - - l = strstrip(line); - - if (isempty(l)) - continue; - - if (l[0] == '!') { - if (startswith(l, "! model")) - state = MODELS; - else if (startswith(l, "! layout")) - state = LAYOUTS; - else if (startswith(l, "! variant")) - state = VARIANTS; - else if (startswith(l, "! option")) - state = OPTIONS; - else - state = NONE; - - continue; - } - - if (state != look_for) - continue; - - w = l + strcspn(l, WHITESPACE); - - if (n > 1) { - char *e; - - if (*w == 0) - continue; - - *w = 0; - w++; - w += strspn(w, WHITESPACE); - - e = strchr(w, ':'); - if (!e) - continue; - - *e = 0; - - if (!streq(w, args[1])) - continue; - } else - *w = 0; - - r = strv_extend(&list, l); - if (r < 0) - return log_oom(); - } - - if (strv_isempty(list)) { - log_error("Couldn't find any entries."); - return -ENOENT; - } - - strv_sort(list); - strv_uniq(list); - - pager_open_if_enabled(); - - strv_print(list); - return 0; -} - -static void help(void) { - printf("%s [OPTIONS...] COMMAND ...\n\n" - "Query or change system locale and keyboard settings.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-pager Do not pipe output into a pager\n" - " --no-ask-password Do not prompt for password\n" - " -H --host=[USER@]HOST Operate on remote host\n" - " -M --machine=CONTAINER Operate on local container\n" - " --no-convert Don't convert keyboard mappings\n\n" - "Commands:\n" - " status Show current locale settings\n" - " set-locale LOCALE... Set system locale\n" - " list-locales Show known locales\n" - " set-keymap MAP [MAP] Set console and X11 keyboard mappings\n" - " list-keymaps Show known virtual console keyboard mappings\n" - " set-x11-keymap LAYOUT [MODEL [VARIANT [OPTIONS]]]\n" - " Set X11 and console keyboard mappings\n" - " list-x11-keymap-models Show known X11 keyboard mapping models\n" - " list-x11-keymap-layouts Show known X11 keyboard mapping layouts\n" - " list-x11-keymap-variants [LAYOUT]\n" - " Show known X11 keyboard mapping variants\n" - " list-x11-keymap-options Show known X11 keyboard mapping options\n" - , program_invocation_short_name); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_NO_PAGER, - ARG_NO_CONVERT, - ARG_NO_ASK_PASSWORD - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "host", required_argument, NULL, 'H' }, - { "machine", required_argument, NULL, 'M' }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "no-convert", no_argument, NULL, ARG_NO_CONVERT }, - {} - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; - - case ARG_NO_CONVERT: - arg_convert = false; - break; - - case ARG_NO_PAGER: - arg_no_pager = true; - break; - - case ARG_NO_ASK_PASSWORD: - arg_ask_password = false; - break; - - case 'H': - arg_transport = BUS_TRANSPORT_REMOTE; - arg_host = optarg; - break; - - case 'M': - arg_transport = BUS_TRANSPORT_MACHINE; - arg_host = optarg; - break; - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - return 1; -} - -static int localectl_main(sd_bus *bus, int argc, char *argv[]) { - - static const struct { - const char* verb; - const enum { - MORE, - LESS, - EQUAL - } argc_cmp; - const int argc; - int (* const dispatch)(sd_bus *bus, char **args, unsigned n); - } verbs[] = { - { "status", LESS, 1, show_status }, - { "set-locale", MORE, 2, set_locale }, - { "list-locales", EQUAL, 1, list_locales }, - { "set-keymap", MORE, 2, set_vconsole_keymap }, - { "list-keymaps", EQUAL, 1, list_vconsole_keymaps }, - { "set-x11-keymap", MORE, 2, set_x11_keymap }, - { "list-x11-keymap-models", EQUAL, 1, list_x11_keymaps }, - { "list-x11-keymap-layouts", EQUAL, 1, list_x11_keymaps }, - { "list-x11-keymap-variants", LESS, 2, list_x11_keymaps }, - { "list-x11-keymap-options", EQUAL, 1, list_x11_keymaps }, - }; - - int left; - unsigned i; - - assert(argc >= 0); - assert(argv); - - left = argc - optind; - - if (left <= 0) - /* Special rule: no arguments means "status" */ - i = 0; - else { - if (streq(argv[optind], "help")) { - help(); - return 0; - } - - for (i = 0; i < ELEMENTSOF(verbs); i++) - if (streq(argv[optind], verbs[i].verb)) - break; - - if (i >= ELEMENTSOF(verbs)) { - log_error("Unknown operation %s", argv[optind]); - return -EINVAL; - } - } - - switch (verbs[i].argc_cmp) { - - case EQUAL: - if (left != verbs[i].argc) { - log_error("Invalid number of arguments."); - return -EINVAL; - } - - break; - - case MORE: - if (left < verbs[i].argc) { - log_error("Too few arguments."); - return -EINVAL; - } - - break; - - case LESS: - if (left > verbs[i].argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - break; - - default: - assert_not_reached("Unknown comparison operator."); - } - - return verbs[i].dispatch(bus, argv + optind, left); -} - -int main(int argc, char*argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; - int r; - - setlocale(LC_ALL, ""); - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = bus_open_transport(arg_transport, arg_host, false, &bus); - if (r < 0) { - log_error_errno(r, "Failed to create bus connection: %m"); - goto finish; - } - - r = localectl_main(bus, argc, argv); - -finish: - pager_close(); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/locale/localed.c b/src/locale/localed.c deleted file mode 100644 index fd0eb2db55..0000000000 --- a/src/locale/localed.c +++ /dev/null @@ -1,1305 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - Copyright 2013 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> -#include <string.h> -#include <unistd.h> - -#include "sd-bus.h" - -#include "util.h" -#include "mkdir.h" -#include "strv.h" -#include "def.h" -#include "env-util.h" -#include "fileio.h" -#include "fileio-label.h" -#include "bus-util.h" -#include "bus-error.h" -#include "bus-message.h" -#include "event-util.h" -#include "locale-util.h" -#include "selinux-util.h" - -#ifdef HAVE_XKBCOMMON -#include <xkbcommon/xkbcommon.h> -#endif - -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - LOCALE_LANG, - LOCALE_LANGUAGE, - LOCALE_LC_CTYPE, - LOCALE_LC_NUMERIC, - LOCALE_LC_TIME, - LOCALE_LC_COLLATE, - LOCALE_LC_MONETARY, - LOCALE_LC_MESSAGES, - LOCALE_LC_PAPER, - LOCALE_LC_NAME, - LOCALE_LC_ADDRESS, - LOCALE_LC_TELEPHONE, - LOCALE_LC_MEASUREMENT, - LOCALE_LC_IDENTIFICATION, - _LOCALE_MAX -}; - -static const char * const names[_LOCALE_MAX] = { - [LOCALE_LANG] = "LANG", - [LOCALE_LANGUAGE] = "LANGUAGE", - [LOCALE_LC_CTYPE] = "LC_CTYPE", - [LOCALE_LC_NUMERIC] = "LC_NUMERIC", - [LOCALE_LC_TIME] = "LC_TIME", - [LOCALE_LC_COLLATE] = "LC_COLLATE", - [LOCALE_LC_MONETARY] = "LC_MONETARY", - [LOCALE_LC_MESSAGES] = "LC_MESSAGES", - [LOCALE_LC_PAPER] = "LC_PAPER", - [LOCALE_LC_NAME] = "LC_NAME", - [LOCALE_LC_ADDRESS] = "LC_ADDRESS", - [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE", - [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT", - [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; - -typedef struct Context { - char *locale[_LOCALE_MAX]; - - char *x11_layout; - char *x11_model; - char *x11_variant; - char *x11_options; - - char *vc_keymap; - char *vc_keymap_toggle; - - Hashmap *polkit_registry; -} Context; - -static const char* nonempty(const char *s) { - return isempty(s) ? NULL : s; -} - -static void free_and_replace(char **s, char *v) { - free(*s); - *s = v; -} - -static bool startswith_comma(const char *s, const char *prefix) { - const char *t; - - return s && (t = startswith(s, prefix)) && (*t == ','); -} - -static void context_free_x11(Context *c) { - free_and_replace(&c->x11_layout, NULL); - free_and_replace(&c->x11_model, NULL); - free_and_replace(&c->x11_variant, NULL); - free_and_replace(&c->x11_options, NULL); -} - -static void context_free_vconsole(Context *c) { - free_and_replace(&c->vc_keymap, NULL); - free_and_replace(&c->vc_keymap_toggle, NULL); -} - -static void context_free_locale(Context *c) { - int p; - - for (p = 0; p < _LOCALE_MAX; p++) - free_and_replace(&c->locale[p], NULL); -} - -static void context_free(Context *c) { - context_free_locale(c); - context_free_x11(c); - context_free_vconsole(c); - - bus_verify_polkit_async_registry_free(c->polkit_registry); -}; - -static void locale_simplify(Context *c) { - int p; - - for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) - if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) - free_and_replace(&c->locale[p], NULL); -} - -static int locale_read_data(Context *c) { - int r; - - context_free_locale(c); - - r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &c->locale[LOCALE_LANG], - "LANGUAGE", &c->locale[LOCALE_LANGUAGE], - "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE], - "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC], - "LC_TIME", &c->locale[LOCALE_LC_TIME], - "LC_COLLATE", &c->locale[LOCALE_LC_COLLATE], - "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY], - "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES], - "LC_PAPER", &c->locale[LOCALE_LC_PAPER], - "LC_NAME", &c->locale[LOCALE_LC_NAME], - "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS], - "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE], - "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION], - NULL); - - if (r == -ENOENT) { - int p; - - /* Fill in what we got passed from systemd. */ - for (p = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); - - r = free_and_strdup(&c->locale[p], - nonempty(getenv(names[p]))); - if (r < 0) - return r; - } - - r = 0; - } - - locale_simplify(c); - return r; -} - -static int vconsole_read_data(Context *c) { - int r; - - context_free_vconsole(c); - - r = parse_env_file("/etc/vconsole.conf", NEWLINE, - "KEYMAP", &c->vc_keymap, - "KEYMAP_TOGGLE", &c->vc_keymap_toggle, - NULL); - - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static int x11_read_data(Context *c) { - _cleanup_fclose_ FILE *f; - char line[LINE_MAX]; - bool in_section = false; - int r; - - context_free_x11(c); - - f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); - if (!f) - return errno == ENOENT ? 0 : -errno; - - while (fgets(line, sizeof(line), f)) { - char *l; - - char_array_0(line); - l = strstrip(line); - - if (l[0] == 0 || l[0] == '#') - continue; - - if (in_section && first_word(l, "Option")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_quoted(&a, l, 0); - if (r < 0) - return r; - - if (strv_length(a) == 3) { - if (streq(a[1], "XkbLayout")) { - free_and_replace(&c->x11_layout, a[2]); - a[2] = NULL; - } else if (streq(a[1], "XkbModel")) { - free_and_replace(&c->x11_model, a[2]); - a[2] = NULL; - } else if (streq(a[1], "XkbVariant")) { - free_and_replace(&c->x11_variant, a[2]); - a[2] = NULL; - } else if (streq(a[1], "XkbOptions")) { - free_and_replace(&c->x11_options, a[2]); - a[2] = NULL; - } - } - - } else if (!in_section && first_word(l, "Section")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_quoted(&a, l, 0); - if (r < 0) - return -ENOMEM; - - if (strv_length(a) == 2 && streq(a[1], "InputClass")) - in_section = true; - - } else if (in_section && first_word(l, "EndSection")) - in_section = false; - } - - return 0; -} - -static int context_read_data(Context *c) { - int r, q, p; - - r = locale_read_data(c); - q = vconsole_read_data(c); - p = x11_read_data(c); - - return r < 0 ? r : q < 0 ? q : p; -} - -static int locale_write_data(Context *c, char ***settings) { - int r, p; - _cleanup_strv_free_ char **l = NULL; - - /* Set values will be returned as strv in *settings on success. */ - - r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 0; p < _LOCALE_MAX; p++) { - _cleanup_free_ char *t = NULL; - char **u; - - assert(names[p]); - - if (isempty(c->locale[p])) { - l = strv_env_unset(l, names[p]); - continue; - } - - if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) - return -ENOMEM; - - u = strv_env_set(l, t); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/locale.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file_label("/etc/locale.conf", l); - if (r < 0) - return r; - - *settings = l; - l = NULL; - return 0; -} - -static int locale_update_system_manager(Context *c, sd_bus *bus) { - _cleanup_free_ char **l_unset = NULL; - _cleanup_strv_free_ char **l_set = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - sd_bus_error error = SD_BUS_ERROR_NULL; - unsigned c_set, c_unset, p; - int r; - - assert(bus); - - l_unset = new0(char*, _LOCALE_MAX); - if (!l_unset) - return -ENOMEM; - - l_set = new0(char*, _LOCALE_MAX); - if (!l_set) - return -ENOMEM; - - for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); - - if (isempty(c->locale[p])) - l_unset[c_set++] = (char*) names[p]; - else { - char *s; - - if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0) - return -ENOMEM; - - l_set[c_unset++] = s; - } - } - - assert(c_set + c_unset == _LOCALE_MAX); - r = sd_bus_message_new_method_call(bus, &m, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "UnsetAndSetEnvironment"); - if (r < 0) - return r; - - r = sd_bus_message_append_strv(m, l_unset); - if (r < 0) - return r; - - r = sd_bus_message_append_strv(m, l_set); - if (r < 0) - return r; - - r = sd_bus_call(bus, m, 0, &error, NULL); - if (r < 0) - log_error_errno(r, "Failed to update the manager environment: %m"); - - return 0; -} - -static int vconsole_write_data(Context *c) { - int r; - _cleanup_strv_free_ char **l = NULL; - - r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - if (isempty(c->vc_keymap)) - l = strv_env_unset(l, "KEYMAP"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP=", c->vc_keymap); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (isempty(c->vc_keymap_toggle)) - l = strv_env_unset(l, "KEYMAP_TOGGLE"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/vconsole.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - return write_env_file_label("/etc/vconsole.conf", l); -} - -static int x11_write_data(Context *c) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *temp_path = NULL; - int r; - - if (isempty(c->x11_layout) && - isempty(c->x11_model) && - isempty(c->x11_variant) && - isempty(c->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(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; -} diff --git a/src/locale/org.freedesktop.locale1.conf b/src/locale/org.freedesktop.locale1.conf deleted file mode 100644 index 79d0ecd2bb..0000000000 --- a/src/locale/org.freedesktop.locale1.conf +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0"?> <!--*-nxml-*--> -<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" - "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> - -<!-- - This file is part of systemd. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. ---> - -<busconfig> - - <policy user="root"> - <allow own="org.freedesktop.locale1"/> - <allow send_destination="org.freedesktop.locale1"/> - <allow receive_sender="org.freedesktop.locale1"/> - </policy> - - <policy context="default"> - <allow send_destination="org.freedesktop.locale1"/> - <allow receive_sender="org.freedesktop.locale1"/> - </policy> - -</busconfig> diff --git a/src/locale/org.freedesktop.locale1.policy.in b/src/locale/org.freedesktop.locale1.policy.in deleted file mode 100644 index df63845e9b..0000000000 --- a/src/locale/org.freedesktop.locale1.policy.in +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*--> -<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" - "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd"> - -<!-- - This file is part of systemd. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. ---> - -<policyconfig> - - <vendor>The systemd Project</vendor> - <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url> - - <action id="org.freedesktop.locale1.set-locale"> - <_description>Set system locale</_description> - <_message>Authentication is required to set the system locale.</_message> - <defaults> - <allow_any>auth_admin_keep</allow_any> - <allow_inactive>auth_admin_keep</allow_inactive> - <allow_active>auth_admin_keep</allow_active> - </defaults> - <annotate key="org.freedesktop.policykit.imply">org.freedesktop.locale1.set-keyboard</annotate> - </action> - - <action id="org.freedesktop.locale1.set-keyboard"> - <_description>Set system keyboard settings</_description> - <_message>Authentication is required to set the system keyboard settings.</_message> - <defaults> - <allow_any>auth_admin_keep</allow_any> - <allow_inactive>auth_admin_keep</allow_inactive> - <allow_active>auth_admin_keep</allow_active> - </defaults> - </action> - -</policyconfig> diff --git a/src/locale/org.freedesktop.locale1.service b/src/locale/org.freedesktop.locale1.service deleted file mode 100644 index 025f9a0fc2..0000000000 --- a/src/locale/org.freedesktop.locale1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.locale1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.locale1.service |