Index: gdm-2.24.0/common/Makefile.am
===================================================================
--- gdm-2.24.0.orig/common/Makefile.am
+++ gdm-2.24.0/common/Makefile.am
@@ -83,6 +83,8 @@ libgdmcommon_la_SOURCES =	\
 	gdm-settings-backend.h	\
 	gdm-settings-desktop-backend.c 	\
 	gdm-settings-desktop-backend.h	\
+	gdm-settings-system-backend.c 	\
+	gdm-settings-system-backend.h	\
 	gdm-settings-keys.h	\
 	gdm-settings-utils.h	\
 	gdm-settings-utils.c	\
@@ -90,6 +92,8 @@ libgdmcommon_la_SOURCES =	\
 	gdm-settings-direct.h	\
 	gdm-settings-client.h	\
 	gdm-settings-client.c	\
+	gdm-sysconfig.c		\
+	gdm-sysconfig.h		\
 	gdm-log.h		\
 	gdm-log.c		\
 	gdm-md5.h		\
Index: gdm-2.24.0/common/gdm-settings-system-backend.c
===================================================================
--- /dev/null
+++ gdm-2.24.0/common/gdm-settings-system-backend.c
@@ -0,0 +1,281 @@
+/* -*- 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-marshal.h"
+#include "gdm-log.h"
+
+#define SYSCONFIG_AUTOLOGIN_KEY "DISPLAYMANAGER_AUTOLOGIN"
+
+#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;
+        gboolean    dirty;
+        guint       save_id;
+
+        gchar      *set_autologin_user;
+        gboolean    set_autologin_enabled;
+};
+
+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;
+        ret = FALSE;
+
+        if (value != NULL) {
+                *value = NULL;
+        }
+
+        if (strcasecmp (key, GDM_KEY_AUTO_LOGIN_ENABLE) &&
+            strcasecmp (key, GDM_KEY_AUTO_LOGIN_USER)) {
+                g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
+                goto out;
+        }
+
+        if (!strcasecmp (key, GDM_KEY_AUTO_LOGIN_ENABLE)) {
+                if (priv->dirty) {
+                        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 (priv->dirty && priv->set_autologin_user) {
+                        val = g_strdup (priv->set_autologin_user);
+                } else {
+                        val = gdm_sysconfig_get_value ((const gchar **) priv->lines, SYSCONFIG_AUTOLOGIN_KEY);
+                }
+        }
+
+        if (value != NULL && val != NULL && *val != '\0') {
+                *value = val;
+        } else {
+                g_free (val);
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+static void
+save_settings (GdmSettingsSystemBackend *backend)
+{
+        GError   *local_error;
+        char     *contents;
+        gsize     length;
+
+        if (! backend->priv->dirty) {
+                return;
+        }
+
+        g_debug ("Saving settings to %s", backend->priv->filename);
+
+        if (!backend->priv->set_autologin_enabled) {
+                g_free (backend->priv->set_autologin_user);
+                backend->priv->set_autologin_user = g_strdup ("");
+        }
+
+        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 (!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;
+}
+
+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
+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;
+
+        if (strcasecmp ("key", GDM_KEY_AUTO_LOGIN_ENABLE) &&
+            strcasecmp ("key", GDM_KEY_AUTO_LOGIN_USER)) {
+                g_set_error (error, GDM_SETTINGS_BACKEND_ERROR, GDM_SETTINGS_BACKEND_ERROR_KEY_NOT_FOUND, "Key not found");
+                return FALSE;
+        }
+
+        gdm_settings_system_backend_get_value (backend, key, &old_val, NULL);
+
+        if (!strcasecmp ("key", GDM_KEY_AUTO_LOGIN_ENABLE)) {
+                gchar t = 0;
+
+                if (value)
+                        t = g_ascii_tolower (*value);
+
+                if (t == 'y' || t == 't')
+                        priv->set_autologin_enabled = TRUE;
+                else
+                        priv->set_autologin_enabled = FALSE;
+        } else {
+                g_free (priv->set_autologin_user);
+                priv->set_autologin_user = g_strdup (value);
+        }
+
+        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)
+{
+        gboolean res;
+        GError  *error;
+
+        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;
+
+        object = g_object_new (GDM_TYPE_SETTINGS_SYSTEM_BACKEND, NULL);
+
+        return GDM_SETTINGS_BACKEND (object);
+}
Index: gdm-2.24.0/common/gdm-settings-system-backend.h
===================================================================
--- /dev/null
+++ gdm-2.24.0/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 */
Index: gdm-2.24.0/common/gdm-settings.c
===================================================================
--- gdm-2.24.0.orig/common/gdm-settings.c
+++ gdm-2.24.0/common/gdm-settings.c
@@ -41,6 +41,7 @@
 #include "gdm-settings-glue.h"
 
 #include "gdm-settings-desktop-backend.h"
+#include "gdm-settings-system-backend.h"
 
 #include "gdm-marshal.h"
 
@@ -53,7 +54,7 @@
 struct GdmSettingsPrivate
 {
         DBusGConnection    *connection;
-        GdmSettingsBackend *backend;
+        GList              *backends;
 };
 
 enum {
@@ -94,15 +95,29 @@ gdm_settings_get_value (GdmSettings *set
 {
         GError  *local_error;
         gboolean res;
+        GList   *l;
 
         g_return_val_if_fail (GDM_IS_SETTINGS (settings), FALSE);
         g_return_val_if_fail (key != NULL, FALSE);
 
         local_error = NULL;
-        res = gdm_settings_backend_get_value (settings->priv->backend,
-                                              key,
-                                              value,
-                                              &local_error);
+
+        for (l = settings->priv->backends; l; l = g_list_next (l)) {
+                GdmSettingsBackend *backend = l->data;
+
+                if (local_error) {
+                        g_error_free (local_error);
+                        local_error = NULL;
+                }
+
+                res = gdm_settings_backend_get_value (backend,
+                                                      key,
+                                                      value,
+                                                      &local_error);
+                if (res)
+                        break;
+        }
+
         if (! res) {
                 g_propagate_error (error, local_error);
         }
@@ -122,6 +137,7 @@ gdm_settings_set_value (GdmSettings *set
 {
         GError  *local_error;
         gboolean res;
+        GList   *l;
 
         g_return_val_if_fail (GDM_IS_SETTINGS (settings), FALSE);
         g_return_val_if_fail (key != NULL, FALSE);
@@ -129,10 +145,23 @@ gdm_settings_set_value (GdmSettings *set
         g_debug ("Setting value %s", key);
 
         local_error = NULL;
-        res = gdm_settings_backend_set_value (settings->priv->backend,
-                                              key,
-                                              value,
-                                              &local_error);
+
+        for (l = settings->priv->backends; l; l = g_list_next (l)) {
+                GdmSettingsBackend *backend = l->data;
+
+                if (local_error) {
+                        g_error_free (local_error);
+                        local_error = NULL;
+                }
+
+                res = gdm_settings_backend_set_value (backend,
+                                                      key,
+                                                      value,
+                                                      &local_error);
+                if (res)
+                        break;
+        }
+
         if (! res) {
                 g_propagate_error (error, local_error);
         }
@@ -210,13 +239,21 @@ backend_value_changed (GdmSettingsBacken
 static void
 gdm_settings_init (GdmSettings *settings)
 {
+        GList *l;
+
         settings->priv = GDM_SETTINGS_GET_PRIVATE (settings);
 
-        settings->priv->backend = gdm_settings_desktop_backend_new ();
-        g_signal_connect (settings->priv->backend,
-                          "value-changed",
-                          G_CALLBACK (backend_value_changed),
-                          settings);
+        settings->priv->backends = g_list_prepend (NULL, gdm_settings_desktop_backend_new ());
+        settings->priv->backends = g_list_prepend (settings->priv->backends, gdm_settings_system_backend_new ());
+
+        for (l = settings->priv->backends; l; l = g_list_next (l)) {
+                GdmSettingsBackend *backend = l->data;
+
+                g_signal_connect (backend,
+                                  "value-changed",
+                                  G_CALLBACK (backend_value_changed),
+                                  settings);
+        }
 }
 
 static void
@@ -231,9 +268,9 @@ gdm_settings_finalize (GObject *object)
 
         g_return_if_fail (settings->priv != NULL);
 
-        if (settings->priv->backend != NULL) {
-                g_object_unref (settings->priv->backend);
-        }
+        g_list_foreach (settings->priv->backends, (GFunc) g_object_unref, NULL);
+        g_list_free (settings->priv->backends);
+        settings->priv->backends = NULL;
 
         G_OBJECT_CLASS (gdm_settings_parent_class)->finalize (object);
 }
Index: gdm-2.24.0/common/gdm-sysconfig.c
===================================================================
--- /dev/null
+++ gdm-2.24.0/common/gdm-sysconfig.c
@@ -0,0 +1,439 @@
+/* -*- 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 "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 ("", str);
+                }
+        }
+
+        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, &quotes);
+
+        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;
+        gint         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, "");
+        escaped_value_len = strlen (escaped_value);
+
+        p1 = skip_over_value (p0, &quotes);
+        p2 = p1 + strlen (p1);
+        len = (p0 - line) + escaped_value_len + (p2 - p1);
+
+        new_line = g_malloc (len + 1);
+        memcpy (new_line,                                   line,          p0 - line);
+        memcpy (new_line + (p0 - line),                     escaped_value, escaped_value_len);
+        memcpy (new_line + (p0 - line) + escaped_value_len, p1,            p2 - p1);
+
+        *(new_line + len - 1) = '\0';
+
+        g_free (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);
+}
+
+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;
+}
Index: gdm-2.24.0/common/gdm-sysconfig.h
===================================================================
--- /dev/null
+++ gdm-2.24.0/common/gdm-sysconfig.h
@@ -0,0 +1,40 @@
+/* -*- 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);
+
+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 */
Index: gdm-2.24.0/daemon/gdm-session-direct.c
===================================================================
--- gdm-2.24.0.orig/daemon/gdm-session-direct.c
+++ gdm-2.24.0/daemon/gdm-session-direct.c
@@ -45,6 +45,8 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "gdm-sysconfig.h"
+
 #include "gdm-session-direct.h"
 #include "gdm-session.h"
 #include "gdm-session-private.h"
@@ -600,8 +602,16 @@ get_default_language_name (GdmSessionDir
 static const char *
 get_default_layout_name (GdmSessionDirect *session)
 {
-    if (session->priv->saved_layout != NULL) {
-                return session->priv->saved_layout;
+    if (!session->priv->saved_layout)
+            session->priv->saved_layout = gdm_sysconfig_load_value ("/etc/sysconfig/keyboard", "KEYTABLE");
+
+    if (session->priv->saved_layout) {
+            if (g_str_has_suffix (session->priv->saved_layout, ".gz"))
+                    *(session->priv->saved_layout + strlen (session->priv->saved_layout) - strlen (".gz")) = '\0';
+            if (g_str_has_suffix (session->priv->saved_layout, ".map"))
+                    *(session->priv->saved_layout + strlen (session->priv->saved_layout) - strlen (".map")) = '\0';
+
+            return session->priv->saved_layout;
     }
 
     return "us";
Index: gdm-2.24.0/gui/simple-greeter/gdm-layouts.c
===================================================================
--- gdm-2.24.0.orig/gui/simple-greeter/gdm-layouts.c
+++ gdm-2.24.0/gui/simple-greeter/gdm-layouts.c
@@ -70,14 +70,35 @@ xci_desc_to_utf8 (XklConfigItem * ci)
                 g_locale_to_utf8 (sd, -1, NULL, NULL, NULL);
 }
 
+static gchar *
+canonicalize_layout_name (const gchar *name)
+{
+        gchar *canon_name;
+
+        if (!name)
+                return NULL;
+
+        canon_name = g_strdup (name);
+
+        if (g_str_has_suffix (canon_name, ".gz"))
+                *(canon_name + strlen (canon_name) - strlen (".gz")) = '\0';
+        if (g_str_has_suffix (canon_name, ".map"))
+                *(canon_name + strlen (canon_name) - strlen (".map")) = '\0';
+
+        return canon_name;
+}
+
 static void
 add_variant (XklConfigRegistry   *config,
              const XklConfigItem *item,
              gpointer             data)
 {
         LayoutData *ldata = data;
+        gchar      *name;
 
-        ldata->list = g_slist_prepend (ldata->list, g_strdup_printf  ("%s\t%s", ldata->layout, item->name));
+        name = canonicalize_layout_name (item->name);
+        ldata->list = g_slist_prepend (ldata->list, g_strdup_printf  ("%s\t%s", ldata->layout, name));
+        g_free (name);
 }
 
 static void
@@ -86,11 +107,16 @@ add_layout (XklConfigRegistry   *config,
             gpointer             data)
 {
         LayoutData *ldata = data;
+        gchar *name;
 
-        ldata->layout = item->name;
-        ldata->list = g_slist_prepend (ldata->list, g_strdup (item->name));
-        xkl_config_registry_foreach_layout_variant (config, item->name, add_variant, data);
+        name = canonicalize_layout_name (item->name);
+
+        ldata->layout = name;
+        ldata->list = g_slist_prepend (ldata->list, g_strdup (name));
+        xkl_config_registry_foreach_layout_variant (config, name, add_variant, data);
         ldata->layout = NULL;
+
+        g_free (name);
 }
 #endif
 
@@ -108,7 +134,7 @@ gdm_get_layout_from_name (const char *na
 
         init_xkl ();
 
-        id1 = g_strdup (name);
+        id1 = canonicalize_layout_name (name);
         p = strchr (id1, '\t');
 
         if (p != NULL) {
@@ -207,7 +233,7 @@ gdm_layout_activate (const char *layout)
                 config->options = g_strdupv (initial_config->options);
         } else {
                 config->layouts = g_new0 (char *, 2);
-                config->layouts[0] = g_strdup (layout);
+                config->layouts[0] = canonicalize_layout_name (layout);
 
                 p = strchr (config->layouts[0], '\t');
                 if (p != NULL) {
