aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am21
-rw-r--r--README22
-rw-r--r--TODO2
-rw-r--r--data/locale1.xml30
-rw-r--r--src/localed.c227
-rw-r--r--src/localed.h31
-rw-r--r--src/main.c3
-rw-r--r--src/shell-utils.c83
-rw-r--r--src/shell-utils.h5
10 files changed, 406 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore
index b0d689f..8fae933 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@
/openrc-settingsd
/stamp-h1
/src/hostname1-generated.[ch]
+/src/locale1-generated.[ch]
# Relative rules
*.o
diff --git a/Makefile.am b/Makefile.am
index f2a770a..7ae61ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
EXTRA_DIST = \
data/hostname1.xml \
+ data/locale1.xml \
$(NULL)
AM_CPPFLAGS = \
@@ -22,10 +23,18 @@ hostnamed_built_sources = \
src/hostname1-generated.h \
$(NULL)
+localed_built_sources = \
+ src/locale1-generated.c \
+ src/locale1-generated.h \
+ $(NULL)
+
openrc_settingsd_SOURCES = \
$(hostnamed_built_sources) \
+ $(localed_built_sources) \
src/hostnamed.c \
src/hostnamed.h \
+ src/localed.c \
+ src/localed.h \
src/bus-utils.c \
src/bus-utils.h \
src/shell-utils.c \
@@ -41,5 +50,13 @@ $(hostnamed_built_sources) : data/hostname1.xml
$(srcdir)/data/hostname1.xml; \
mv hostname1-generated.{c,h} $(top_srcdir)/src/ )
-BUILT_SOURCES = $(hostnamed_built_sources)
-CLEANFILES = $(hostnamed_built_sources)
+$(localed_built_sources) : data/locale1.xml
+ ( $(GDBUS_CODEGEN) \
+ --interface-prefix org.freedesktop. \
+ --c-namespace OpenrcSettingsdLocaled \
+ --generate-c-code locale1-generated \
+ $(srcdir)/data/locale1.xml; \
+ mv locale1-generated.{c,h} $(top_srcdir)/src/ )
+
+BUILT_SOURCES = $(hostnamed_built_sources) $(localed_built_sources)
+CLEANFILES = $(hostnamed_built_sources) $(localed_built_sources)
diff --git a/README b/README
index 62bd904..bd6adac 100644
--- a/README
+++ b/README
@@ -16,6 +16,28 @@ Hostnamed:
PRETTY_HOSTNAME="Foo !"
ICON_NAME="computer-desktop"
+Localed:
+
+ See http://www.freedesktop.org/wiki/Software/systemd/localed for the DBus
+ protocol description.
+
+ The system locale variables are set in /etc/env.d/02locale.
+
+ Virtual console keymap is set in /etc/conf.d/keymaps as
+ keymap="foo"
+ The virtual console keymap toggle is not supported.
+
+/*
+ Not implemented yet.
+
+ X11 keyboard options are set in /etc/X11/xorg.conf.d/30-keyboard.conf
+ (falling back to 00-keyboard.conf if it exists and 30-keyboard.conf does
+ not) in an InputClass section.
+ Localed will attempt to detect if multiple InputClass sections with
+ keyboard options exist in /etc/X11/xorg.conf and /etc/X11/xorg.conf.d/,
+ and if that is the case, will refuse to modify X11 keyboard settings.
+*/
+
Note that openrc-settingsd expects any shell-syntax settings files that it
modifies to be in UTF-8 encoding, and to consist only of comments and simple
scalar assignments, i.e. something like
diff --git a/TODO b/TODO
index e8694da..a7feb33 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,4 @@
-Add nss-myhostname detection (and add nss-myhostnane to portage)
+Add nss-myhostname detection
Source /etc/rc.conf after /etc/conf.d/$service; do something intelligent
if the relevant variable is set in /etc/rc.conf (go to read-only mode?)
diff --git a/data/locale1.xml b/data/locale1.xml
new file mode 100644
index 0000000..dfd98d3
--- /dev/null
+++ b/data/locale1.xml
@@ -0,0 +1,30 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/freedesktop/locale1">
+ <interface name="org.freedesktop.locale1">
+ <method name="SetLocale">
+ <arg direction="in" type="as" name="locale"/>
+ <arg direction="in" type="b" name="user_interaction"/>
+ </method>
+ <method name="SetVConsoleKeyboard">
+ <arg direction="in" type="s" name="keymap"/>
+ <arg direction="in" type="s" name="keymap_toggle"/>
+ <arg direction="in" type="b" name="convert"/>
+ <arg direction="in" type="b" name="user_interaction"/>
+ </method>
+ <method name="SetX11Keyboard">
+ <arg direction="in" type="s" name="layout"/>
+ <arg direction="in" type="s" name="model"/>
+ <arg direction="in" type="s" name="variant"/>
+ <arg direction="in" type="s" name="options"/>
+ <arg direction="in" type="b" name="convert"/>
+ <arg direction="in" type="b" name="user_interaction"/>
+ </method>
+ <property name="Locale" type="as" access="read"/>
+ <property name="VConsoleKeymap" type="s" access="read"/>
+ <property name="VConsoleKeymapToggle" type="s" access="read"/>
+ <property name="X11Layout" type="s" access="read"/>
+ <property name="X11Model" type="s" access="read"/>
+ <property name="X11Variant" type="s" access="read"/>
+ <property name="X11Options" type="s" access="read"/>
+ </interface>
+</node>
diff --git a/src/localed.c b/src/localed.c
new file mode 100644
index 0000000..12d9ad7
--- /dev/null
+++ b/src/localed.c
@@ -0,0 +1,227 @@
+/*
+ Copyright 2012 Alexandre Rostovtsev
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <stdlib.h>
+
+#include <dbus/dbus-protocol.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "localed.h"
+#include "locale1-generated.h"
+#include "bus-utils.h"
+#include "shell-utils.h"
+
+#include "config.h"
+
+#define SERVICE_NAME "openrc-settingsd localed"
+
+static guint bus_id = 0;
+static gboolean read_only = FALSE;
+
+static OpenrcSettingsdLocaledLocale1 *locale1 = NULL;
+
+static gchar *locale_variables[] = {
+ "LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", "LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS", "LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", NULL
+};
+
+static gchar **locale = NULL; /* Expected format is { "LANG=foo", "LC_TIME=bar", NULL } */
+static GFile *locale_file = NULL;
+G_LOCK_DEFINE_STATIC (locale);
+
+static gchar *vconsole_keymap = NULL;
+static gchar *vconsole_keymap_toggle = NULL;
+static GFile *keymaps_file = NULL;
+G_LOCK_DEFINE_STATIC (keymaps);
+
+static gchar *x11_layout = NULL;
+static gchar *x11_model = NULL;
+static gchar *x11_variant = NULL;
+static gchar *x11_options = NULL;
+G_LOCK_DEFINE_STATIC (xorg_conf);
+
+static gboolean
+on_handle_set_locale (OpenrcSettingsdLocaledLocale1 *locale1,
+ GDBusMethodInvocation *invocation,
+ const gchar * const *_locale,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ DBUS_ERROR_NOT_SUPPORTED,
+ SERVICE_NAME " is in read-only mode");
+
+ return TRUE;
+}
+
+static gboolean
+on_handle_set_vconsole_keyboard (OpenrcSettingsdLocaledLocale1 *locale1,
+ GDBusMethodInvocation *invocation,
+ const gchar *keymap,
+ const gchar *keymap_toggle,
+ const gboolean convert,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ DBUS_ERROR_NOT_SUPPORTED,
+ SERVICE_NAME " is in read-only mode");
+
+ return TRUE;
+}
+
+static gboolean
+on_handle_set_x11_keyboard (OpenrcSettingsdLocaledLocale1 *locale1,
+ GDBusMethodInvocation *invocation,
+ const gchar *layout,
+ const gchar *model,
+ const gchar *variant,
+ const gchar *options,
+ const gboolean convert,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ DBUS_ERROR_NOT_SUPPORTED,
+ SERVICE_NAME " is in read-only mode");
+
+ return TRUE;
+}
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *bus_name,
+ gpointer user_data)
+{
+ gchar *name;
+ GError *err = NULL;
+
+ g_debug ("Acquired a message bus connection");
+
+ locale1 = openrc_settingsd_localed_locale1_skeleton_new ();
+
+ openrc_settingsd_localed_locale1_set_locale (locale1, (const gchar * const *) locale);
+ openrc_settingsd_localed_locale1_set_vconsole_keymap (locale1, vconsole_keymap);
+ openrc_settingsd_localed_locale1_set_vconsole_keymap_toggle (locale1, vconsole_keymap_toggle);
+ openrc_settingsd_localed_locale1_set_x11_layout (locale1, x11_layout);
+ openrc_settingsd_localed_locale1_set_x11_model (locale1, x11_model);
+ openrc_settingsd_localed_locale1_set_x11_variant (locale1, x11_variant);
+ openrc_settingsd_localed_locale1_set_x11_options (locale1, x11_options);
+
+ g_signal_connect (locale1, "handle-set-locale", G_CALLBACK (on_handle_set_locale), NULL);
+ g_signal_connect (locale1, "handle-set-vconsole-keyboard", G_CALLBACK (on_handle_set_vconsole_keyboard), NULL);
+ g_signal_connect (locale1, "handle-set-x11-keyboard", G_CALLBACK (on_handle_set_x11_keyboard), NULL);
+
+ if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (locale1),
+ connection,
+ "/org/freedesktop/locale1",
+ &err)) {
+ if (err != NULL) {
+ g_printerr ("Failed to export interface on /org/freedesktop/locale1: %s\n", err->message);
+ g_error_free (err);
+ }
+ }
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *bus_name,
+ gpointer user_data)
+{
+ g_debug ("Acquired the name %s", bus_name);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *bus_name,
+ gpointer user_data)
+{
+ if (connection == NULL)
+ g_printerr ("Failed to acquire a dbus connection\n");
+ else
+ g_printerr ("Failed to acquire dbus name %s\n", bus_name);
+ exit(-1);
+}
+
+void
+localed_init (gboolean _read_only)
+{
+ GError *err = NULL;
+ gchar **locale_values = NULL;
+
+ read_only = _read_only;
+ locale_file = g_file_new_for_path (SYSCONFDIR "/env.d/02locale");
+ keymaps_file = g_file_new_for_path (SYSCONFDIR "/conf.d/keymaps");
+
+ locale = g_new0 (gchar *, g_strv_length (locale_variables) + 1);
+ locale_values = shell_utils_trivial_source_var_list (locale_file, (const gchar * const *)locale_variables, &err);
+ if (locale_values != NULL) {
+ gchar **variable, **value, **loc;
+ loc = locale;
+ for (variable = locale_variables, value = locale_values; *variable != NULL; variable++, value++) {
+ if (*value != NULL) {
+ *loc = g_strdup_printf ("%s=%s", *variable, *value);
+ loc++;
+ }
+ }
+
+ g_strfreev (locale_values);
+ }
+ if (err != NULL) {
+ g_debug ("%s", err->message);
+ g_clear_error (&err);
+ }
+
+ vconsole_keymap = shell_utils_source_var (keymaps_file, "${keymap}", &err);
+ if (vconsole_keymap == NULL)
+ vconsole_keymap = g_strdup ("");
+ if (err != NULL) {
+ g_debug ("%s", err->message);
+ g_clear_error (&err);
+ }
+
+ /* We don't have a good equivalent for this in openrc at the moment */
+ vconsole_keymap_toggle = g_strdup ("");
+
+ bus_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
+ "org.freedesktop.locale1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL,
+ NULL);
+}
+
+void
+localed_destroy (void)
+{
+ g_bus_unown_name (bus_id);
+ bus_id = 0;
+ read_only = FALSE;
+ g_strfreev (locale);
+ g_free (vconsole_keymap);
+ g_free (vconsole_keymap_toggle);
+ g_free (x11_layout);
+ g_free (x11_model);
+ g_free (x11_variant);
+ g_free (x11_options);
+
+ g_object_unref (locale_file);
+ g_object_unref (keymaps_file);
+}
diff --git a/src/localed.h b/src/localed.h
new file mode 100644
index 0000000..dff55c6
--- /dev/null
+++ b/src/localed.h
@@ -0,0 +1,31 @@
+/*
+ Copyright 2012 Alexandre Rostovtsev
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef OPENRC_LOCALED_H
+#define OPENRC_LOCALED_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+void
+localed_init (gboolean read_only);
+
+void
+localed_destroy (void);
+
+#endif
diff --git a/src/main.c b/src/main.c
index c7165f0..fabb96c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,6 +23,7 @@
#include <gio/gio.h>
#include "hostnamed.h"
+#include "localed.h"
#include "shell-utils.h"
#include "config.h"
@@ -68,10 +69,12 @@ main (gint argc, gchar *argv[])
shell_utils_init ();
hostnamed_init (read_only);
+ localed_init (read_only);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_main_loop_unref (loop);
+ localed_destroy ();
hostnamed_destroy ();
shell_utils_destroy ();
return 0;
diff --git a/src/shell-utils.c b/src/shell-utils.c
index 30026a9..db67303 100644
--- a/src/shell-utils.c
+++ b/src/shell-utils.c
@@ -45,6 +45,7 @@ struct ShellEntry {
enum ShellEntryType type;
gchar *string;
gchar *variable; /* only relevant for assignments */
+ gchar *unquoted_value; /* only relevant for assignments */
};
gchar *
@@ -104,10 +105,9 @@ shell_entry_free (struct ShellEntry *entry)
if (entry == NULL)
return;
- if (entry->string != NULL)
- g_free (entry->string);
- if (entry->variable != NULL)
- g_free (entry->variable);
+ g_free (entry->string);
+ g_free (entry->variable);
+ g_free (entry->unquoted_value);
g_free (entry);
}
@@ -132,7 +132,7 @@ shell_utils_trivial_new (GFile *file,
{
gchar *filebuf = NULL;
ShellUtilsTrivial *ret = NULL;
- GError *local_err;
+ GError *local_err = NULL;
gchar *s;
if (file == NULL)
@@ -214,6 +214,7 @@ shell_utils_trivial_new (GFile *file,
matched = g_regex_match (var_equals_regex, s, 0, &match_info);
if (matched) {
+ gchar *raw_value = NULL, *temp1 = NULL, *temp2 = NULL;
/* If we expect a separator and get an assignment instead, fail */
if (want_separator)
goto no_match;
@@ -231,7 +232,6 @@ shell_utils_trivial_new (GFile *file,
while (*s != 0) {
g_debug ("Scanning string for values: ``%s''", s);
gboolean matched2 = FALSE;
- gchar *temp1 = NULL, *temp2 = NULL;
matched2 = g_regex_match (single_quoted_regex, s, 0, &match_info);
if (matched2)
@@ -256,18 +256,36 @@ shell_utils_trivial_new (GFile *file,
break;
append_value:
+
+ if (raw_value == NULL) {
+ raw_value = g_match_info_fetch (match_info, 0);
+ s += strlen (raw_value);
+ g_debug ("Scanned value: ``%s''", raw_value);
+ } else {
+ temp1 = raw_value;
+ temp2 = g_match_info_fetch (match_info, 0);
+ raw_value = g_strconcat (temp1, temp2, NULL);
+ s += strlen (temp2);
+ g_debug ("Scanned value: ``%s''", temp2);
+ g_free (temp1);
+ g_free (temp2);
+ }
+ g_match_info_free (match_info);
+ match_info = NULL;
+ }
+
+ if (raw_value != NULL) {
+ entry->unquoted_value = g_shell_unquote (raw_value, &local_err);
+ g_debug ("Unquoted value: ``%s''", entry->unquoted_value);
temp1 = entry->string;
- temp2 = g_match_info_fetch (match_info, 0);
+ temp2 = raw_value;
entry->string = g_strconcat (temp1, temp2, NULL);
- s += strlen (temp2);
- g_debug ("Scanned value: ``%s''", temp2);
g_free (temp1);
g_free (temp2);
- g_match_info_free (match_info);
- match_info = NULL;
+ ret->entry_list = g_list_prepend (ret->entry_list, entry);
+ if (local_err != NULL)
+ goto no_match;
}
-
- ret->entry_list = g_list_prepend (ret->entry_list, entry);
continue;
}
@@ -275,9 +293,12 @@ no_match:
/* Nothing matches, parsing has failed! */
g_match_info_free (match_info);
match_info = NULL;
- g_propagate_error (error,
- g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED,
- "Unable to parse '%s'", ret->filename));
+ if (local_err != NULL)
+ g_propagate_prefixed_error (error, local_err, "Unable to parse '%s':", ret->filename);
+ else
+ g_propagate_error (error,
+ g_error_new (G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "Unable to parse '%s'", ret->filename));
shell_utils_trivial_free (ret);
return NULL;
}
@@ -420,6 +441,36 @@ shell_utils_trivial_set_and_save (GFile *file,
return ret;
}
+gchar **
+shell_utils_trivial_source_var_list (GFile *file,
+ const gchar * const *var_names,
+ GError **error)
+{
+ ShellUtilsTrivial *trivial;
+ gchar **ret = NULL, **value;
+ const gchar* const* var_name;
+
+ if (var_names == NULL)
+ return NULL;
+
+ if ((trivial = shell_utils_trivial_new (file, error)) == NULL)
+ return NULL;
+
+ ret = g_new0 (gchar *, g_strv_length ((gchar **)var_names) + 1);
+ for (var_name = var_names, value = ret; *var_name != NULL; var_name++, value++) {
+ GList *curr;
+ for (curr = trivial->entry_list; curr != NULL; curr = curr->next) {
+ struct ShellEntry *entry;
+
+ entry = (struct ShellEntry *)(curr->data);
+ if (entry->type == SHELL_ENTRY_TYPE_ASSIGNMENT && g_strcmp0 (*var_name, entry->variable) == 0)
+ *value = g_strdup (entry->unquoted_value);
+ }
+ }
+ shell_utils_trivial_free (trivial);
+ return ret;
+}
+
void
shell_utils_destroy (void)
{
diff --git a/src/shell-utils.h b/src/shell-utils.h
index 5e1863d..9ca40e9 100644
--- a/src/shell-utils.h
+++ b/src/shell-utils.h
@@ -66,4 +66,9 @@ shell_utils_trivial_set_and_save (GFile *file,
const gchar *first_alt_var_name,
const gchar *first_value,
...);
+
+gchar **
+shell_utils_trivial_source_var_list (GFile *file,
+ const gchar * const *var_names,
+ GError **error);
#endif