--- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 + * + * 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 +#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 + * + * 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 +#include + +#include +#include +#include + +#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 + * + * 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 + +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 = [