localed.c revision 5430f7f2bc7330f3088b894166bf3524a067e3d8
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa This file is part of systemd.
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa Copyright 2011 Lennart Poettering
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa systemd is free software; you can redistribute it and/or modify it
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa under the terms of the GNU Lesser General Public License as published by
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa the Free Software Foundation; either version 2.1 of the License, or
0fe5514fdf12b7559c1a470cf22d89737d55b0a0Eugen Kuksa (at your option) any later version.
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa systemd is distributed in the hope that it will be useful, but
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa WITHOUT ANY WARRANTY; without even the implied warranty of
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa Lesser General Public License for more details.
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa You should have received a copy of the GNU Lesser General Public License
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa along with systemd; If not, see <http://www.gnu.org/licenses/>.
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <interface name=\"org.freedesktop.locale1\">\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"Locale\" type=\"as\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"VConsoleKeymap\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"VConsoleKeymapToggle\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"X11Layout\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"X11Model\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"X11Variant\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <property name=\"X11Options\" type=\"s\" access=\"read\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <method name=\"SetLocale\">\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " </method>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <method name=\"SetVConsoleKeyboard\">\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"keymap\" type=\"s\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"keymap_toggle\" type=\"s\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " </method>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <method name=\"SetX11Keyboard\">\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"layout\" type=\"s\" direction=\"in\"/>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa " <arg name=\"model\" type=\"s\" direction=\"in\"/>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " <arg name=\"variant\" type=\"s\" direction=\"in\"/>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " <arg name=\"options\" type=\"s\" direction=\"in\"/>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " </method>\n" \
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder " </interface>\n"
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa "<node>\n" \
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksa "org.freedesktop.locale1\0"
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksaconst char locale_interface[] _introspect_("locale1") = INTERFACE;
800663e7e87d81818fa8e161c99687540d27f75fMihai Codescu /* We don't list LC_ALL here on purpose. People should be
800663e7e87d81818fa8e161c99687540d27f75fMihai Codescu * using LANG instead. */
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maederstatic const char * const names[_PROP_MAX] = {
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder [PROP_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maedertypedef struct State {
94e112d16f89130a688db8b03ad3224903f5e97eChristian Maeder char *x11_layout, *x11_model, *x11_variant, *x11_options;
64dcce858b74fca0c1c408a249fde7a9db8a8798Eugen Kuksastatic int free_and_set(char **s, const char *v) {
free(*s);
static void free_data_locale(void) {
for (p = 0; p < _PROP_MAX; p++) {
static void free_data_x11(void) {
static void free_data_vconsole(void) {
static void simplify(void) {
static int read_data_locale(void) {
NULL);
if (r == -ENOENT) {
for (p = 0; p < _PROP_MAX; p++) {
d = strdup(e);
return -ENOMEM;
d = NULL;
data[p] = d;
simplify();
static void free_data(void) {
static int read_data_vconsole(void) {
NULL);
if (r < 0 && r != -ENOENT)
static int read_data_x11(void) {
FILE *f;
bool in_section = false;
#ifdef TARGET_FEDORA
return -errno;
return -errno;
a = strv_split_quoted(l);
fclose(f);
return -ENOMEM;
strv_free(a);
a = strv_split_quoted(l);
fclose(f);
return -ENOMEM;
in_section = true;
strv_free(a);
in_section = false;
fclose(f);
static int read_data(void) {
r = read_data_locale();
q = read_data_vconsole();
p = read_data_x11();
static int write_data_locale(void) {
char **l = NULL;
if (r < 0 && r != -ENOENT)
for (p = 0; p < _PROP_MAX; p++) {
strv_free(l);
return -ENOMEM;
u = strv_env_set(l, t);
free(t);
strv_free(l);
return -ENOMEM;
if (strv_isempty(l)) {
strv_free(l);
strv_free(l);
goto finish;
for (p = 0; p < _PROP_MAX; p++) {
goto finish;
m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment");
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
if (!reply) {
goto finish;
if (reply)
static int write_data_vconsole(void) {
char **l = NULL;
if (r < 0 && r != -ENOENT)
strv_free(l);
return -ENOMEM;
u = strv_env_set(l, s);
free(s);
strv_free(l);
return -ENOMEM;
strv_free(l);
return -ENOMEM;
u = strv_env_set(l, s);
free(s);
strv_free(l);
return -ENOMEM;
if (strv_isempty(l)) {
strv_free(l);
strv_free(l);
static int write_data_x11(void) {
FILE *f;
char *temp_path;
#ifdef TARGET_FEDORA
fflush(f);
r = -errno;
#ifdef TARGET_FEDORA
fclose(f);
if (!error) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
r = -ENOMEM;
goto finish;
if (!dbus_message_append_args(m,
r = -ENOMEM;
goto finish;
if (!reply) {
r = -EIO;
goto finish;
if (reply)
static char *strnulldash(const char *s) {
assert(f);
assert(n);
assert(a);
errno = 0;
if (ferror(f))
b = strv_split_quoted(l);
return -ENOMEM;
strv_free(b);
bool modified = false;
modified =
FILE *f;
return -errno;
r = read_next_mapping(f, &n, &a);
fclose(f);
strv_free(a);
strv_free(a);
fclose(f);
return -ENOMEM;
modified = true;
strv_free(a);
fclose(f);
if (modified) {
dbus_bool_t b;
r = write_data_x11();
"/org/freedesktop/locale1",
if (!changed)
return -ENOMEM;
return -ENOMEM;
bool modified = false;
modified =
FILE *f;
unsigned best_matching = 0;
return -errno;
unsigned matching = 0;
r = read_next_mapping(f, &n, &a);
fclose(f);
size_t x;
size_t w;
if (matching > 0 &&
matching++;
matching++;
matching++;
if (!new_keymap) {
strv_free(a);
fclose(f);
return -ENOMEM;
strv_free(a);
fclose(f);
modified = true;
if (modified) {
dbus_bool_t b;
r = write_data_vconsole();
"/org/freedesktop/locale1",
if (!changed)
return -ENOMEM;
return -ENOMEM;
return -ENOMEM;
for (p = 0; p < _PROP_MAX; p++) {
strv_free(l);
return -ENOMEM;
strv_free(l);
{ "VConsoleKeymapToggle", bus_property_append_string, "s", offsetof(State, vc_keymap_toggle), true },
{ NULL, }
{ NULL, }
void *userdata) {
char **l = NULL, **i;
bool modified = false;
if (r == -ENOMEM)
goto oom;
strv_free(l);
STRV_FOREACH(i, l) {
bool valid = false;
for (p = 0; p < _PROP_MAX; p++) {
size_t k;
valid = true;
passed[p] = true;
modified = true;
if (!valid) {
strv_free(l);
if (!modified) {
for (p = 0; p < _PROP_MAX; p++)
modified = true;
if (modified) {
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, NULL, &error);
strv_free(l);
STRV_FOREACH(i, l) {
for (p = 0; p < _PROP_MAX; p++) {
size_t k;
strv_free(l);
goto oom;
data[p] = t;
strv_free(l);
for (p = 0; p < _PROP_MAX; p++) {
if (passed[p])
simplify();
r = write_data_locale();
"/org/freedesktop/locale1",
if (!changed)
goto oom;
} else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetVConsoleKeyboard")) {
if (!dbus_message_get_args(
&error,
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error);
goto oom;
r = write_data_vconsole();
"/org/freedesktop/locale1",
if (!changed)
goto oom;
if (convert) {
if (!dbus_message_get_args(
&error,
r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error);
goto oom;
r = write_data_x11();
"/org/freedesktop/locale1",
if (!changed)
goto oom;
if (convert) {
goto oom;
goto oom;
if (changed) {
goto oom;
return DBUS_HANDLER_RESULT_HANDLED;
oom:
if (reply)
if (changed)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if (!bus) {
r = -ECONNREFUSED;
goto fail;
r = -ENOMEM;
goto fail;
r = -EEXIST;
goto fail;
if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
r = -EEXIST;
goto fail;
if (_bus)
fail:
bool exiting = false;
log_open();
r = -EINVAL;
goto finish;
r = read_data();
goto finish;
goto finish;
if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
exiting = true;
free_data();
if (bus) {