1
0
forked from pool/gdm
Files
gdm/gdm-sysconfig-settings.patch
Dominique Leuenberger 7cb19a7690 - Update to version 49.0.1:
+ Follow-up for permissions issue fix, making the fix work in
    more environments

- Update to version 49.0:
  + Fix build failures when built without plymouth support
  + Fix permissions issue on the GDM work dir (/var/lib/gdm) that
    broke settings persistence
  + Updated translations

- Update to version 49.rc:
  + Fixed a bug in PAM config files, introduced by transition to
    dynamic users
  + Added logic to retry preferred display server (usually Wayland)
    before falling back (usually to X11)
  + Fixed a bug where Plymouth keeps running if no display is
    plugged into the system. This would prevent bootup from
    completing and would prevent the user from logging in on a
    serial console
  + Fixed GDM's session file loading logic to search directories in
    correct precedence order
  + Fix simpledrm device detection to match the kernel's new device
    naming scheme
  + Re-enabled X11 support by default. We found it difficult to
    cleanly separate GDM's ability to launch modern X11 sessions
    (which we intended to keep enabled in GNOME 49) from the rest
    of GDM's X11 integration (which we intended to disable but
    leave intact for GNOME 49). We still plan to remove GDM's full
    X11 integration in a future version, and leave only the ability
    to launch modern X11 sessions.

OBS-URL: https://build.opensuse.org/package/show/GNOME:Factory/gdm?expand=0&rev=600
2025-09-17 15:55:07 +00:00

1052 lines
36 KiB
Diff

Index: gdm-49.rc/common/gdm-settings-system-backend.c
===================================================================
--- /dev/null
+++ gdm-49.rc/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);
+}
Index: gdm-49.rc/common/gdm-settings-system-backend.h
===================================================================
--- /dev/null
+++ gdm-49.rc/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-49.rc/common/gdm-settings.c
===================================================================
--- gdm-49.rc.orig/common/gdm-settings.c
+++ gdm-49.rc/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);
Index: gdm-49.rc/common/gdm-sysconfig.c
===================================================================
--- /dev/null
+++ gdm-49.rc/common/gdm-sysconfig.c
@@ -0,0 +1,509 @@
+/* -*- 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 <gio/gio.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;
+ g_autofree gchar *temp_file_name = NULL;
+ gint i;
+ gchar *path = NULL;
+ g_autofree char *template = NULL;
+
+ template = g_strdup_printf ("/run/sysconfig.XXXXXX");
+ path = g_mkdtemp (template);
+ if (path == NULL)
+ goto out;
+
+ temp_file_name = g_strdup_printf ("%s/%s.new",path, g_path_get_basename(file_name));
+
+ 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);
+ }
+
+ gboolean result = FALSE;
+ if (last_status == G_IO_STATUS_NORMAL && temp_file_name) {
+ g_autoptr (GFile) old_file = g_file_new_for_path(temp_file_name);
+ g_autoptr (GFile) new_file = g_file_new_for_path(file_name);
+ g_remove(file_name);
+ result = g_file_move (old_file,
+ new_file,
+ G_FILE_COPY_OVERWRITE,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ if (last_status == G_IO_STATUS_NORMAL && !result)
+ last_status = G_IO_STATUS_ERROR;
+
+ if (path) {
+ g_rmdir(path);
+ }
+
+ 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 (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, &quotes);
+ 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, 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 ((gchar **)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 ((gchar **)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;
+}
Index: gdm-49.rc/common/gdm-sysconfig.h
===================================================================
--- /dev/null
+++ gdm-49.rc/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, 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 */
Index: gdm-49.rc/data/gdm.conf-custom.in
===================================================================
--- gdm-49.rc.orig/data/gdm.conf-custom.in
+++ gdm-49.rc/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
Index: gdm-49.rc/common/meson.build
===================================================================
--- gdm-49.rc.orig/common/meson.build
+++ gdm-49.rc/common/meson.build
@@ -6,9 +6,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 = [