File gdm-sysconfig-settings.patch of Package gdm
--- /dev/null
+++ b/common/gdm-settings-system-backend.c
@@ -0,0 +1,372 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Hans Petter Jansson <hpj@copyleft.no>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "gdm-sysconfig.h"
+#include "gdm-settings-keys.h"
+#include "gdm-settings-system-backend.h"
+
+#include "gdm-log.h"
+
+#define SYSCONFIG_AUTOLOGIN_KEY "DISPLAYMANAGER_AUTOLOGIN"
+#define SYSCONFIG_TCP_OPEN_KEY "DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN"
+#define SYSCONFIG_XDMCP_KEY "DISPLAYMANAGER_REMOTE_ACCESS"
+#define SYSCONFIG_STARTS_XSERVER_KEY "DISPLAYMANAGER_STARTS_XSERVER"
+/* Keys from sysconfig that have no equivalent in GDM:
+ * - DISPLAYMANAGER_ROOT_LOGIN_REMOTE
+ * - DISPLAYMANAGER_PASSWORD_LESS_LOGIN
+ * - DISPLAYMANAGER_AD_INTEGRATION
+ * - DISPLAYMANAGER_SHUTDOWN (handled by ConsoleKit)
+ */
+
+#define GDM_SETTINGS_SYSTEM_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SETTINGS_SYSTEM_BACKEND, GdmSettingsSystemBackendPrivate))
+
+struct GdmSettingsSystemBackendPrivate
+{
+ char *filename;
+ gchar **lines;
+ guint save_id;
+
+ gboolean dirty;
+ gboolean dirty_autologin;
+ gboolean dirty_autologin_user;
+ gboolean dirty_tcp_open;
+ gboolean dirty_xdmcp;
+ gboolean dirty_show_local_greeter;
+
+ gchar *set_autologin_user;
+ gboolean set_autologin_enabled;
+
+ gboolean set_tcp_open;
+ gboolean set_xdmcp;
+ gboolean set_show_local_greeter;
+};
+
+static void gdm_settings_system_backend_class_init (GdmSettingsSystemBackendClass *klass);
+static void gdm_settings_system_backend_init (GdmSettingsSystemBackend *settings_system_backend);
+static void gdm_settings_system_backend_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmSettingsSystemBackend, gdm_settings_system_backend, GDM_TYPE_SETTINGS_BACKEND)
+
+static gboolean
+gdm_settings_system_backend_get_value (GdmSettingsBackend *backend,
+ const char *key,
+ char **value,
+ GError **error)
+{
+ GdmSettingsSystemBackend *system_backend = (GdmSettingsSystemBackend *) backend;
+ GdmSettingsSystemBackendPrivate *priv;
+ gchar *val;
+ gboolean ret;
+
+ g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ priv = system_backend->priv;
+ val = NULL;
+ ret = FALSE;
+
+ if (value != NULL) {
+ *value = NULL;
+ }
+
+ if (!strcasecmp (key, GDM_KEY_AUTO_LOGIN_ENABLE)) {
+ if (priv->dirty_autologin) {
+ val = g_strdup (priv->set_autologin_enabled ? "true" : "false");
+ } else {
+ const gchar *new_val;
+
+ val = gdm_sysconfig_get_value ((const gchar **) priv->lines, SYSCONFIG_AUTOLOGIN_KEY);
+
+ new_val = (val && *val) ? "true" : "false";
+ g_free (val);
+ val = g_strdup (new_val);
+ }
+ } else if (!strcasecmp (key, GDM_KEY_AUTO_LOGIN_USER)) {
+ if (priv->dirty_autologin_user) {
+ val = g_strdup (priv->set_autologin_user);
+ } else {
+ val = gdm_sysconfig_get_value ((const gchar **) priv->lines, SYSCONFIG_AUTOLOGIN_KEY);
+ }
+ } else if (!strcasecmp (key, GDM_KEY_DISALLOW_TCP)) {
+ /* beware: that's the opposite of the sysconfig key */
+ if (priv->dirty_tcp_open) {
+ val = g_strdup (priv->set_tcp_open ? "false" : "true");
+ } else {
+ gboolean tcp_open;
+
+ if (gdm_sysconfig_get_value_boolean ((const gchar **) priv->lines, SYSCONFIG_TCP_OPEN_KEY, &tcp_open)) {
+ val = g_strdup (tcp_open ? "false" : "true");
+ }
+ }
+ } else if (!strcasecmp (key, GDM_KEY_XDMCP_ENABLE)) {
+ if (priv->dirty_xdmcp) {
+ val = g_strdup (priv->set_xdmcp ? "true" : "false");
+ } else {
+ gboolean xdmcp;
+
+ if (gdm_sysconfig_get_value_boolean ((const gchar **) priv->lines, SYSCONFIG_XDMCP_KEY, &xdmcp)) {
+ val = g_strdup (xdmcp ? "true" : "false");
+ }
+ }
+ } else if (!strcasecmp (key, GDM_KEY_SHOW_LOCAL_GREETER)) {
+ if (priv->dirty_show_local_greeter) {
+ val = g_strdup (priv->set_xdmcp ? "true" : "false");
+ } else {
+ gboolean local_greeter;
+
+ if (gdm_sysconfig_get_value_boolean ((const gchar **) priv->lines, SYSCONFIG_STARTS_XSERVER_KEY, &local_greeter)) {
+ val = g_strdup (local_greeter ? "true" : "false");
+ }
+ }
+ } else {
+ g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
+ goto out;
+ }
+
+ ret = (val != NULL);
+
+ if (value != NULL && val != NULL && *val != '\0') {
+ *value = val;
+ } else {
+ g_free (val);
+ }
+
+ out:
+ return ret;
+}
+
+static void
+save_settings (GdmSettingsSystemBackend *backend)
+{
+ if (! backend->priv->dirty) {
+ return;
+ }
+
+ g_debug ("Saving settings to %s", backend->priv->filename);
+
+ if (backend->priv->dirty_autologin || backend->priv->dirty_autologin_user) {
+ if (!backend->priv->dirty_autologin) {
+ gchar *val;
+
+ val = gdm_sysconfig_get_value ((const gchar **) backend->priv->lines, SYSCONFIG_AUTOLOGIN_KEY);
+ backend->priv->set_autologin_enabled = (val && *val);
+ g_free (val);
+ }
+
+ if (!backend->priv->set_autologin_enabled) {
+ g_free (backend->priv->set_autologin_user);
+ backend->priv->set_autologin_user = g_strdup ("");
+ } else if (!backend->priv->dirty_autologin_user) {
+ g_free (backend->priv->set_autologin_user);
+ backend->priv->set_autologin_user = gdm_sysconfig_get_value ((const gchar **) backend->priv->lines, SYSCONFIG_AUTOLOGIN_KEY);
+ }
+
+ if (!gdm_sysconfig_set_value (backend->priv->lines, SYSCONFIG_AUTOLOGIN_KEY, backend->priv->set_autologin_user))
+ g_warning ("Unable to set key %s to '%s'.", SYSCONFIG_AUTOLOGIN_KEY,
+ backend->priv->set_autologin_user);
+ }
+
+ if (backend->priv->dirty_tcp_open) {
+ if (!gdm_sysconfig_set_value_boolean (backend->priv->lines, SYSCONFIG_TCP_OPEN_KEY, backend->priv->set_tcp_open))
+ g_warning ("Unable to set key %s to '%s'.", SYSCONFIG_TCP_OPEN_KEY,
+ backend->priv->set_tcp_open ? "yes" : "no");
+ }
+
+ if (backend->priv->dirty_xdmcp) {
+ if (!gdm_sysconfig_set_value_boolean (backend->priv->lines, SYSCONFIG_XDMCP_KEY, backend->priv->set_xdmcp))
+ g_warning ("Unable to set key %s to '%s'.", SYSCONFIG_XDMCP_KEY,
+ backend->priv->set_xdmcp ? "yes" : "no");
+ }
+
+ if (backend->priv->dirty_show_local_greeter) {
+ if (!gdm_sysconfig_set_value_boolean (backend->priv->lines, SYSCONFIG_STARTS_XSERVER_KEY, backend->priv->set_show_local_greeter))
+ g_warning ("Unable to set key %s to '%s'.", SYSCONFIG_STARTS_XSERVER_KEY,
+ backend->priv->set_show_local_greeter? "yes" : "no");
+ }
+
+ if (!gdm_sysconfig_save_file (backend->priv->filename, backend->priv->lines))
+ g_warning ("Unable to save settings to %s.", backend->priv->filename);
+
+ backend->priv->dirty = FALSE;
+ backend->priv->dirty_autologin = FALSE;
+ backend->priv->dirty_autologin_user = FALSE;
+ backend->priv->dirty_tcp_open = FALSE;
+ backend->priv->dirty_xdmcp = FALSE;
+ backend->priv->dirty_show_local_greeter = FALSE;
+}
+
+static gboolean
+save_settings_timer (GdmSettingsSystemBackend *backend)
+{
+ save_settings (backend);
+ backend->priv->save_id = 0;
+ return FALSE;
+}
+
+static void
+queue_save (GdmSettingsSystemBackend *backend)
+{
+ if (! backend->priv->dirty) {
+ return;
+ }
+
+ if (backend->priv->save_id != 0) {
+ /* already pending */
+ return;
+ }
+
+ backend->priv->save_id = g_timeout_add_seconds (5, (GSourceFunc)save_settings_timer, backend);
+}
+
+static gboolean
+value_to_boolean (const char *value)
+{
+ gchar t = 0;
+
+ if (value)
+ t = g_ascii_tolower (*value);
+
+ return (t == 'y' || t == 't');
+}
+
+static gboolean
+gdm_settings_system_backend_set_value (GdmSettingsBackend *backend,
+ const char *key,
+ const char *value,
+ GError **error)
+{
+ GdmSettingsSystemBackend *system_backend = (GdmSettingsSystemBackend *) backend;
+ GdmSettingsSystemBackendPrivate *priv;
+ gchar *old_val = NULL;
+
+ g_return_val_if_fail (GDM_IS_SETTINGS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ priv = system_backend->priv;
+
+ gdm_settings_system_backend_get_value (backend, key, &old_val, NULL);
+
+ if (!strcasecmp (key, GDM_KEY_AUTO_LOGIN_ENABLE)) {
+ priv->set_autologin_enabled = value_to_boolean (value);
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty_autologin = TRUE;
+ } else if (!strcasecmp (key, GDM_KEY_AUTO_LOGIN_USER)) {
+ g_free (priv->set_autologin_user);
+ priv->set_autologin_user = g_strdup (value);
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty_autologin_user = TRUE;
+ } else if (!strcasecmp (key, GDM_KEY_DISALLOW_TCP)) {
+ /* beware: that's the opposite of the sysconfig key */
+ priv->set_tcp_open = !value_to_boolean (value);
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty_tcp_open = TRUE;
+ } else if (!strcasecmp (key, GDM_KEY_XDMCP_ENABLE)) {
+ priv->set_xdmcp = value_to_boolean (value);
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty_xdmcp = TRUE;
+ } else if (!strcasecmp (key, GDM_KEY_SHOW_LOCAL_GREETER)) {
+ priv->set_show_local_greeter = value_to_boolean (value);
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty_show_local_greeter = TRUE;
+ } else {
+ g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
+ return FALSE;
+ }
+
+ GDM_SETTINGS_SYSTEM_BACKEND (backend)->priv->dirty = TRUE;
+ queue_save (GDM_SETTINGS_SYSTEM_BACKEND (backend));
+
+ gdm_settings_backend_value_changed (backend, key, old_val, value);
+
+ g_free (old_val);
+
+ return TRUE;
+}
+
+static void
+gdm_settings_system_backend_class_init (GdmSettingsSystemBackendClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdmSettingsBackendClass *backend_class = GDM_SETTINGS_BACKEND_CLASS (klass);
+
+ object_class->finalize = gdm_settings_system_backend_finalize;
+
+ backend_class->get_value = gdm_settings_system_backend_get_value;
+ backend_class->set_value = gdm_settings_system_backend_set_value;
+
+ g_type_class_add_private (klass, sizeof (GdmSettingsSystemBackendPrivate));
+}
+
+static void
+gdm_settings_system_backend_init (GdmSettingsSystemBackend *backend)
+{
+ backend->priv = GDM_SETTINGS_SYSTEM_BACKEND_GET_PRIVATE (backend);
+
+ backend->priv->filename = g_strdup ("/etc/sysconfig/displaymanager");
+ backend->priv->lines = gdm_sysconfig_load_file (backend->priv->filename);
+
+ if (!backend->priv->lines) {
+ g_warning ("Unable to load file '%s'", backend->priv->filename);
+ }
+}
+
+static void
+gdm_settings_system_backend_finalize (GObject *object)
+{
+ GdmSettingsSystemBackend *backend;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_SETTINGS_SYSTEM_BACKEND (object));
+
+ backend = GDM_SETTINGS_SYSTEM_BACKEND (object);
+
+ g_return_if_fail (backend->priv != NULL);
+
+ save_settings (backend);
+ g_strfreev (backend->priv->lines);
+ g_free (backend->priv->filename);
+ g_free (backend->priv->set_autologin_user);
+
+ G_OBJECT_CLASS (gdm_settings_system_backend_parent_class)->finalize (object);
+}
+
+GdmSettingsBackend *
+gdm_settings_system_backend_new (void)
+{
+ GObject *object;
+
+ if (!g_file_test ("/etc/sysconfig/displaymanager", G_FILE_TEST_IS_REGULAR))
+ return NULL;
+
+ object = g_object_new (GDM_TYPE_SETTINGS_SYSTEM_BACKEND, NULL);
+
+ return GDM_SETTINGS_BACKEND (object);
+}
--- /dev/null
+++ b/common/gdm-settings-system-backend.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Hans Petter Jansson <hpj@copyleft.no>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_SETTINGS_SYSTEM_BACKEND_H
+#define __GDM_SETTINGS_SYSTEM_BACKEND_H
+
+#include <glib-object.h>
+#include "gdm-settings-backend.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SETTINGS_SYSTEM_BACKEND (gdm_settings_system_backend_get_type ())
+#define GDM_SETTINGS_SYSTEM_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SETTINGS_SYSTEM_BACKEND, GdmSettingsSystemBackend))
+#define GDM_SETTINGS_SYSTEM_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SETTINGS_SYSTEM_BACKEND, GdmSettingsSystemBackendClass))
+#define GDM_IS_SETTINGS_SYSTEM_BACKEND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SETTINGS_SYSTEM_BACKEND))
+#define GDM_IS_SETTINGS_SYSTEM_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SETTINGS_SYSTEM_BACKEND))
+#define GDM_SETTINGS_SYSTEM_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SETTINGS_SYSTEM_BACKEND, GdmSettingsSystemBackendClass))
+
+typedef struct GdmSettingsSystemBackendPrivate GdmSettingsSystemBackendPrivate;
+
+typedef struct
+{
+ GdmSettingsBackend parent;
+ GdmSettingsSystemBackendPrivate *priv;
+} GdmSettingsSystemBackend;
+
+typedef struct
+{
+ GdmSettingsBackendClass parent_class;
+} GdmSettingsSystemBackendClass;
+
+GType gdm_settings_system_backend_get_type (void);
+
+GdmSettingsBackend *gdm_settings_system_backend_new (void);
+
+G_END_DECLS
+
+#endif /* __GDM_SETTINGS_SYSTEM_BACKEND_H */
--- a/common/gdm-settings.c
+++ b/common/gdm-settings.c
@@ -38,6 +38,7 @@
#include "gdm-settings.h"
#include "gdm-settings-desktop-backend.h"
+#include "gdm-settings-system-backend.h"
struct _GdmSettings
{
@@ -203,6 +204,10 @@ gdm_settings_reload (GdmSettings *settin
if (backend)
settings->backends = g_list_prepend (NULL, backend);
+ backend = gdm_settings_system_backend_new ();
+ if (backend)
+ settings->backends = g_list_prepend (settings->backends, backend);
+
backend = gdm_settings_desktop_backend_new (GDM_RUNTIME_CONF);
if (backend)
settings->backends = g_list_prepend (settings->backends, backend);
--- /dev/null
+++ b/common/gdm-sysconfig.c
@@ -0,0 +1,484 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Hans Petter Jansson <hpj@novell.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* Parser for shell-script-like key-value files. Far from complete, but
+ * deals with a couple of common shell oddities. For instance, the following
+ * are parsed correctly:
+ *
+ * KEY=value\0
+ * KEY = value#comment\0
+ * KEY = " value with spaces" \0
+ * KEY = ' it\'s a value with "embedded" quotes'\0
+ * KEY = "if quotes aren't closed, we assume the string ends at EOL\0
+ *
+ * It should be good enough for the config files in /etc/sysconfig/.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include "gdm-sysconfig.h"
+
+#define SPACE_CHARS " \t"
+#define KEY_ALLOW_CHARS "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+static gchar **
+load_settings_file (const gchar *file_name)
+{
+ GIOChannel *channel;
+ GPtrArray *lines;
+ gchar *str;
+
+ g_debug ("Loading settings from %s", file_name);
+
+ channel = g_io_channel_new_file (file_name, "r", NULL);
+ if (!channel) {
+ g_debug ("Failed to open %s", file_name);
+ return NULL;
+ }
+
+ lines = g_ptr_array_new ();
+
+ while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
+ if (str) {
+ gchar *p0;
+
+ /* Remove line separators */
+
+ for (p0 = str + strlen (str) - 1; p0 >= str && strchr ("\r\n", *p0); p0--)
+ *p0 = '\0';
+
+ g_ptr_array_add (lines, str);
+ g_debug ("%s", str);
+ } else {
+ g_ptr_array_add (lines, g_strdup (""));
+ g_debug ("%s", "");
+ }
+ }
+
+ g_io_channel_shutdown (channel, FALSE, NULL);
+ g_io_channel_unref (channel);
+
+ g_ptr_array_add (lines, NULL);
+
+ return (gchar **) g_ptr_array_free (lines, FALSE);
+}
+
+static gboolean
+save_settings_file (const gchar *file_name, gchar **lines)
+{
+ GIOStatus last_status = G_IO_STATUS_ERROR;
+ GIOChannel *channel = NULL;
+ gchar *temp_file_name;
+ gint i;
+
+ temp_file_name = g_strdup_printf ("%s.new.%u", file_name, g_random_int ());
+
+ channel = g_io_channel_new_file (temp_file_name, "w", NULL);
+ if (!channel)
+ goto out;
+
+ if (!lines)
+ goto out;
+
+ for (i = 0; lines [i]; i++) {
+ gsize bytes_written;
+
+ if (lines [i] [0] != '\0')
+ last_status = g_io_channel_write_chars (channel,
+ lines [i], strlen (lines [i]),
+ &bytes_written,
+ NULL);
+
+ if (last_status != G_IO_STATUS_NORMAL)
+ break;
+
+ last_status = g_io_channel_write_unichar (channel, '\n', NULL);
+
+ if (last_status != G_IO_STATUS_NORMAL)
+ break;
+ }
+
+out:
+ if (channel) {
+ g_io_channel_shutdown (channel, FALSE, NULL);
+ g_io_channel_unref (channel);
+ }
+
+ if (last_status == G_IO_STATUS_NORMAL && g_rename (temp_file_name, file_name) != 0)
+ last_status = G_IO_STATUS_ERROR;
+
+ g_free (temp_file_name);
+ return last_status == G_IO_STATUS_NORMAL ? TRUE : FALSE;
+}
+
+static const gchar *
+skip_from_start_to_key (const gchar *line)
+{
+ const gchar *p0;
+
+ /* Skip initial space */
+
+ p0 = line + strspn (line, SPACE_CHARS);
+
+ /* Ignore comments and other junk */
+
+ if (*p0 && strchr (KEY_ALLOW_CHARS, *p0))
+ return p0;
+
+ return NULL;
+}
+
+static const gchar *
+skip_from_start_to_value_of_key (const gchar *line, const gchar *key_normal, gint key_len)
+{
+ const gchar *p0, *p1;
+ gchar *potential_key_normal;
+ gboolean result;
+
+ p0 = skip_from_start_to_key (line);
+ if (!p0)
+ return NULL;
+
+ /* There's at least one key-like character, figure out how many */
+
+ p1 = p0 + strspn (p0, KEY_ALLOW_CHARS);
+
+ /* Is this the key we're looking for? */
+
+ if (p1 - p0 != key_len)
+ return NULL;
+
+ potential_key_normal = g_ascii_strdown (p0, p1 - p0);
+ result = strcmp (key_normal, potential_key_normal) == 0 ? TRUE : FALSE;
+ g_free (potential_key_normal);
+
+ if (!result)
+ return NULL;
+
+ /* It's the right key; skip over key-value separator */
+
+ p0 = p1 + strspn (p1, SPACE_CHARS);
+ if (*p0 != '=')
+ return NULL;
+
+ p0++;
+ p0 += strspn (p0, SPACE_CHARS);
+
+ return p0;
+}
+
+static const gchar *
+skip_over_value (const gchar *value_start, gchar *quotes_out)
+{
+ const gchar *p0 = value_start;
+ const gchar *p1;
+ gchar quotes;
+
+ /* Is the value quoted? */
+
+ quotes = *p0;
+ if (quotes == '\'' || quotes == '"') {
+ /* Quoted sequence opened; find closing quote, but skip over escaped ones. If
+ * there's no closing quote on this line, assume the EOL closes it. */
+
+ *quotes_out = quotes;
+
+ p1 = p0;
+ do {
+ p1++;
+ p1 = strchr (p1, quotes);
+ if (!p1) {
+ /* Hit EOL */
+
+ p1 = p0 + strlen (p0) - 1;
+ break;
+ }
+ } while (*(p1 - 1) == '\\');
+ } else {
+ /* No quotes; look for comment or EOL */
+
+ *quotes_out = 0;
+
+ p1 = strchr (p0, '#');
+ if (!p1)
+ p1 = p0 + strlen (p0);
+
+ for (p1--; p1 >= p0; p1--)
+ if (!strchr (SPACE_CHARS, *p1))
+ break;
+ }
+
+ return p1 + 1;
+}
+
+static gchar *
+get_value_of_key (const gchar *line, const gchar *key_normal, gint key_len)
+{
+ const gchar *p0, *p1;
+ gchar quotes;
+ gchar *value;
+ gchar *temp;
+
+ p0 = skip_from_start_to_value_of_key (line, key_normal, key_len);
+ if (!p0)
+ return NULL;
+
+ p1 = skip_over_value (p0, "es);
+
+ if (quotes != 0) {
+ if (p1 - p0 > 2) {
+ temp = g_strndup (p0 + 1, p1 - p0 - 2);
+ value = g_strcompress (temp);
+ g_free (temp);
+ } else {
+ value = g_strdup ("");
+ }
+ } else {
+ temp = g_strndup (p0, p1 - p0);
+ value = g_strcompress (temp);
+ g_free (temp);
+ g_strchomp (value);
+ }
+
+ return value;
+}
+
+static gchar *
+get_value (const gchar **lines, const gchar *key)
+{
+ gchar *value = NULL;
+ gchar *key_normal;
+ gint key_len;
+ gint i;
+
+ g_debug ("Getting value of %s", key);
+
+ if (!lines) {
+ g_debug ("Missing configuration data");
+ return NULL;
+ }
+
+ key_normal = g_ascii_strdown (key, -1);
+ key_len = strlen (key_normal);
+
+ for (i = 0; lines [i]; i++) {
+ value = get_value_of_key (lines [i], key_normal, key_len);
+ if (value)
+ break;
+ }
+
+ g_free (key_normal);
+
+ g_debug ("Got value of %s: %s", key, value);
+
+ return value;
+}
+
+static gchar *
+set_value_of_key (const gchar *line, const gchar *key_normal, gint key_len, const gchar *key, const gchar *value)
+{
+ const gchar *p0, *p1, *p2;
+ gchar quotes;
+ gchar *escaped_value;
+ gchar *quoted_escaped_value;
+ gint quoted_escaped_value_len;
+ gchar *new_line;
+ gint len;
+
+ p0 = skip_from_start_to_value_of_key (line, key_normal, key_len);
+ if (!p0)
+ return NULL;
+
+ escaped_value = g_strescape (value, "");
+ quoted_escaped_value = g_strdup_printf ("\"%s\"", escaped_value);
+ g_free (escaped_value);
+ quoted_escaped_value_len = strlen (quoted_escaped_value);
+
+ p1 = skip_over_value (p0, "es);
+ p2 = p1 + strlen (p1);
+ len = (p0 - line) + quoted_escaped_value_len + (p2 - p1);
+
+ new_line = g_malloc (len + 1);
+ memcpy (new_line, line, p0 - line);
+ memcpy (new_line + (p0 - line), quoted_escaped_value, quoted_escaped_value_len);
+ memcpy (new_line + (p0 - line) + quoted_escaped_value_len, p1, p2 - p1);
+
+ *(new_line + len) = '\0';
+
+ g_free (quoted_escaped_value);
+
+ return new_line;
+}
+
+static gboolean
+set_value (gchar **lines, const gchar *key, const gchar *value)
+{
+ gboolean result = FALSE;
+ gchar *key_normal;
+ gint key_len;
+ gint i;
+
+ if (!lines)
+ return FALSE;
+
+ key_normal = g_ascii_strdown (key, -1);
+ key_len = strlen (key_normal);
+
+ for (i = 0; lines [i]; i++) {
+ gchar *new_line;
+
+ new_line = set_value_of_key (lines [i], key_normal, key_len, key, value);
+ if (new_line) {
+ g_free (lines [i]);
+ lines [i] = new_line;
+ result = TRUE;
+ break;
+ }
+ }
+
+ g_free (key_normal);
+
+ return result;
+}
+
+gchar **
+gdm_sysconfig_load_file (const gchar *file_name)
+{
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ return load_settings_file (file_name);
+}
+
+gboolean
+gdm_sysconfig_save_file (const gchar *file_name, const gchar **sysconfig)
+{
+ g_return_val_if_fail (file_name != NULL, FALSE);
+ g_return_val_if_fail (sysconfig != NULL, FALSE);
+
+ return save_settings_file (file_name, sysconfig);
+}
+
+gchar *
+gdm_sysconfig_get_value (const gchar **sysconfig, const gchar *key)
+{
+ g_return_val_if_fail (sysconfig != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ return get_value (sysconfig, key);
+}
+
+gboolean
+gdm_sysconfig_set_value (gchar **sysconfig, const gchar *key, const gchar *value)
+{
+ g_return_val_if_fail (sysconfig != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ return set_value (sysconfig, key, value);
+}
+
+gboolean
+gdm_sysconfig_get_value_boolean (const gchar **sysconfig, const gchar *key, gboolean *value)
+{
+ char *val;
+ gboolean val_bool;
+
+ g_return_val_if_fail (sysconfig != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ val = get_value (sysconfig, key);
+ if (val == NULL) {
+ return FALSE;
+ }
+
+ if (!strcasecmp (val, "yes")) {
+ val_bool = TRUE;
+ } else if (!strcasecmp (val, "no")) {
+ val_bool = FALSE;
+ } else {
+ g_free (val);
+ return FALSE;
+ }
+
+ g_free (val);
+
+ if (value != NULL) {
+ *value = val_bool;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gdm_sysconfig_set_value_boolean (gchar **sysconfig, const gchar *key, gboolean value)
+{
+ g_return_val_if_fail (sysconfig != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ return set_value (sysconfig, key, value ? "yes" : "no");
+}
+
+gchar *
+gdm_sysconfig_load_value (const gchar *file_name, const gchar *key)
+{
+ gchar **lines;
+ gchar *value;
+
+ g_return_val_if_fail (file_name != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ lines = load_settings_file (file_name);
+ if (!lines)
+ return NULL;
+
+ value = get_value (lines, key);
+
+ g_strfreev (lines);
+ return value;
+}
+
+gboolean
+gdm_sysconfig_save_value (const gchar *file_name, const gchar *key, const gchar *value)
+{
+ gchar **lines;
+ gboolean result;
+
+ g_return_val_if_fail (file_name != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ lines = load_settings_file (file_name);
+ if (!lines)
+ return FALSE;
+
+ result = set_value (lines, key, value);
+ if (result)
+ result = save_settings_file (file_name, lines);
+
+ g_strfreev (lines);
+ return result;
+}
--- /dev/null
+++ b/common/gdm-sysconfig.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Hans Petter Jansson <hpj@novell.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_SYSCONFIG_H
+#define __GDM_SYSCONFIG_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+gchar **gdm_sysconfig_load_file (const gchar *file_name);
+gboolean gdm_sysconfig_save_file (const gchar *file_name, const gchar **sysconfig);
+
+gchar *gdm_sysconfig_get_value (const gchar **sysconfig, const gchar *key);
+gboolean gdm_sysconfig_set_value (gchar **sysconfig, const gchar *key, const gchar *value);
+
+gboolean gdm_sysconfig_get_value_boolean (const gchar **sysconfig, const gchar *key, gboolean *value);
+gboolean gdm_sysconfig_set_value_boolean (gchar **sysconfig, const gchar *key, gboolean value);
+
+gchar *gdm_sysconfig_load_value (const gchar *file_name, const gchar *key);
+gboolean gdm_sysconfig_save_value (const gchar *file_name, const gchar *key, const gchar *value);
+
+G_END_DECLS
+
+#endif /* __GDM_SYSCONFIG_H */
--- a/data/gdm.conf-custom.in
+++ b/data/gdm.conf-custom.in
@@ -1,4 +1,7 @@
# GDM configuration storage
+#
+# Note: settings from /etc/sysconfig/displaymanager have a higher priority
+#
[daemon]
# Uncomment the line below to force the login screen to use Xorg
--- a/common/meson.build
+++ b/common/meson.build
@@ -5,9 +5,11 @@ libgdmcommon_src = files(
'gdm-profile.c',
'gdm-settings-backend.c',
'gdm-settings-desktop-backend.c',
+ 'gdm-settings-system-backend.c',
'gdm-settings-direct.c',
'gdm-settings-utils.c',
'gdm-settings.c',
+ 'gdm-sysconfig.c',
)
libgdmcommon_deps = [