localectl.c revision 7c2d80944afb4196f2eff614e8da1450dffcbeaa
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering This file is part of systemd.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Copyright 2012 Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is free software; you can redistribute it and/or modify it
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering under the terms of the GNU Lesser General Public License as published by
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (at your option) any later version.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is distributed in the hope that it will be useful, but
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Lesser General Public License for more details.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering You should have received a copy of the GNU Lesser General Public License
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_no_pager = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_ask_password = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_convert = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void pager_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Open the polkit agent as a child process if necessary */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringtypedef struct StatusInfo {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poetteringstatic void print_status_info(StatusInfo *i) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" System Locale: %s\n", i->locale[0]);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" VC Keymap: %s\n", strna(i->vconsole_keymap));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Layout: %s\n", strna(i->x11_layout));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Model: %s\n", i->x11_model);
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering printf(" X11 Variant: %s\n", i->x11_variant);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" X11 Options: %s\n", i->x11_options);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int status_property(const char *name, DBusMessageIter *iter, StatusInfo *i) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering switch (dbus_message_iter_get_arg_type(iter)) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else if (streq(name, "VConsoleKeymapToggle"))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poetteringstatic int show_status(DBusConnection *bus, char **args, unsigned n) {
0f7091e624fdba6c0bf281f2a9a23cd3e9ca93fbLennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "org.freedesktop.locale1",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "org.freedesktop.DBus.Properties",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
b6800689e03456efd0430d171ebf962f64b94eb0Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poetteringstatic int set_locale(DBusConnection *bus, char **args, unsigned n) {
8013e860b6344cb109e68208a3a91b0fc3cb9ed1Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "org.freedesktop.locale1",
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "org.freedesktop.locale1",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = bus_append_strv_iter(&iter, args + 1);
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &interactive))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to issue method call: %s", bus_error_message(&error));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int add_locales_from_archive(Set *locales) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Stolen from glibc... */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Serial number. */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Name hash table. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* String table. */
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering /* Table with locale records. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* MD5 sum hash table. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Hash value of the name. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Offset of the name in the string table. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Offset of the locale record. */
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const struct locarhead *h;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const struct namehashent *e;
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering const void *p = MAP_FAILED;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to open locale archive: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Archive file is not regular");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (st.st_size < (off_t) sizeof(struct locarhead)) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h = (const struct locarhead *) p;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->namehash_offset + h->namehash_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->string_offset + h->string_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->locrectab_offset + h->locrectab_size > st.st_size ||
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering h->sumhash_offset + h->sumhash_size > st.st_size) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering for (i = 0; i < h->namehash_size; i++) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering z = strdup((char*) p + e[i].name_offset);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to add locale: %s", strerror(-r));
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poetteringstatic int add_locales_from_libdir (Set *locales) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to open locale directory: %m");
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering log_error("Failed to add locale: %s", strerror(-r));
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poettering log_error("Failed to read locale directory: %m");
23b298bce75a0d1f4f15f34458af9678b4a30c3aLennart Poetteringstatic int list_locales(DBusConnection *bus, char **args, unsigned n) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering locales = set_new(string_hash_func, string_compare_func);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r < 0 && r != -ENOENT)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int set_vconsole_keymap(DBusConnection *bus, char **args, unsigned n) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
return -EINVAL;
b = arg_convert;
return bus_method_call_with_reply(
bus,
"/org/freedesktop/locale1",
&reply,
NULL,
DBUS_TYPE_BOOLEAN, &b,
static int nftw_cb(
const char *fpath,
int tflag,
return log_oom();
if (r == -EEXIST)
free(p);
free(p);
if (!keymaps)
return log_oom();
return log_oom();
if (strv_isempty(l)) {
return -ENOENT;
strv_sort(l);
strv_print(l);
return -EINVAL;
b = arg_convert;
return bus_method_call_with_reply(
bus,
"/org/freedesktop/locale1",
&reply,
NULL,
DBUS_TYPE_BOOLEAN, &b,
static int help(void) {
help();
case ARG_VERSION:
case ARG_NO_CONVERT:
arg_convert = false;
case ARG_NO_PAGER:
arg_no_pager = true;
return -EINVAL;
return -EINVAL;
const char* verb;
MORE,
LESS,
} argc_cmp;
const int argc;
} verbs[] = {
int left;
if (left <= 0)
help();
return -EINVAL;
case EQUAL:
return -EINVAL;
case MORE:
return -EINVAL;
case LESS:
return -EINVAL;
if (!bus) {
return -EIO;
log_open();
goto finish;
goto finish;
if (bus) {
pager_close();
return retval;