Merge lp:~ubuntu-branches/ubuntu/precise/gconf/precise-201203060106 into lp:ubuntu/precise/gconf

Proposed by Ubuntu Package Importer
Status: Rejected
Rejected by: James Westby
Proposed branch: lp:~ubuntu-branches/ubuntu/precise/gconf/precise-201203060106
Merge into: lp:ubuntu/precise/gconf
Diff against target: 37212 lines (+19994/-8531) (has conflicts)
18 files modified
.pc/01_defaults_path.patch/defaults/gconf-defaults.c (+0/-1199)
.pc/01_defaults_path.patch/gconf/gconfd.c (+0/-2847)
.pc/02_fix_wrong_return_value.patch/gconf/gconf-client.c (+0/-2938)
.pc/02_xml-gettext-domain.patch/backends/markup-tree.c (+4673/-0)
.pc/02_xml-gettext-domain.patch/doc/gconf-1.0.dtd (+45/-0)
.pc/02_xml-gettext-domain.patch/gconf/GConfX.idl (+269/-0)
.pc/02_xml-gettext-domain.patch/gconf/gconf-internals.c (+2953/-0)
.pc/02_xml-gettext-domain.patch/gconf/gconf-schema.c (+344/-0)
.pc/02_xml-gettext-domain.patch/gconf/gconf-schema.h (+85/-0)
.pc/02_xml-gettext-domain.patch/gconf/gconftool.c (+4359/-0)
.pc/04_manpage.patch/doc/gconftool-2.1 (+0/-148)
.pc/05_nodisplay_autostart.patch/gsettings/gsettings-data-convert.desktop.in (+9/-0)
.pc/05_readd_gconf_engine_key_is_writable.patch/gconf/gconf-dbus.c (+2524/-0)
.pc/06_onlyshowin_unity.patch/gsettings/gsettings-data-convert.desktop.in (+10/-0)
.pc/25_gconf-path-max-hurd.patch/backends/markup-tree.c (+4709/-0)
.pc/25_gconf-path-max-hurd.patch/backends/xml-dir.c (+0/-1399)
.pc/applied-patches (+8/-0)
debian/control (+6/-0)
Conflict adding file .pc/02_xml-gettext-domain.patch.  Moved existing file to .pc/02_xml-gettext-domain.patch.moved.
Conflict adding file .pc/05_nodisplay_autostart.patch.  Moved existing file to .pc/05_nodisplay_autostart.patch.moved.
Conflict adding file .pc/05_readd_gconf_engine_key_is_writable.patch.  Moved existing file to .pc/05_readd_gconf_engine_key_is_writable.patch.moved.
Conflict adding file .pc/06_onlyshowin_unity.patch.  Moved existing file to .pc/06_onlyshowin_unity.patch.moved.
Conflict: can't delete .pc/25_gconf-path-max-hurd.patch.moved because it is not empty.  Not deleting.
Conflict adding file .pc/25_gconf-path-max-hurd.patch.  Moved existing file to .pc/25_gconf-path-max-hurd.patch.moved.
Conflict because .pc/25_gconf-path-max-hurd.patch.moved is not versioned, but has versioned children.  Versioned directory.
Conflict: can't delete .pc/25_gconf-path-max-hurd.patch.moved/backends because it is not empty.  Not deleting.
Conflict because .pc/25_gconf-path-max-hurd.patch.moved/backends is not versioned, but has versioned children.  Versioned directory.
Contents conflict in .pc/25_gconf-path-max-hurd.patch.moved/backends/markup-tree.c
Contents conflict in .pc/applied-patches
Text conflict in debian/control
To merge this branch: bzr merge lp:~ubuntu-branches/ubuntu/precise/gconf/precise-201203060106
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+96032@code.launchpad.net

Description of the change

The package importer has detected a possible inconsistency between the package history in the archive and the history in bzr. As the archive is authoritative the importer has made lp:ubuntu/precise/gconf reflect what is in the archive and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/precise/gconf/precise-201203060106. This merge proposal was created so that an Ubuntu developer can review the situations and perform a merge/upload if necessary. There are three typical cases where this can happen.
  1. Where someone pushes a change to bzr and someone else uploads the package without that change. This is the reason that this check is done by the importer. If this appears to be the case then a merge/upload should be done if the changes that were in bzr are still desirable.
  2. The importer incorrectly detected the above situation when someone made a change in bzr and then uploaded it.
  3. The importer incorrectly detected the above situation when someone just uploaded a package and didn't touch bzr.

If this case doesn't appear to be the first situation then set the status of the merge proposal to "Rejected" and help avoid the problem in future by filing a bug at https://bugs.launchpad.net/udd linking to this merge proposal.

(this is an automatically generated message)

To post a comment you must log in.

Unmerged revisions

84. By Steve Langasek

releasing version 3.2.3-3ubuntu1

83. By Steve Langasek

Merge version 3.2.3-3 from Debian testing

82. By Steve Langasek

Merging shared upstream rev into target branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/01_defaults_path.patch'
2=== removed directory '.pc/01_defaults_path.patch'
3=== added directory '.pc/01_defaults_path.patch/defaults'
4=== removed directory '.pc/01_defaults_path.patch/defaults'
5=== added file '.pc/01_defaults_path.patch/defaults/gconf-defaults.c'
6--- .pc/01_defaults_path.patch/defaults/gconf-defaults.c 1970-01-01 00:00:00 +0000
7+++ .pc/01_defaults_path.patch/defaults/gconf-defaults.c 2012-03-06 01:10:25 +0000
8@@ -0,0 +1,1199 @@
9+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10+ *
11+ * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com>
12+ *
13+ * This program is free software; you can redistribute it and/or modify
14+ * it under the terms of the GNU General Public License as published by
15+ * the Free Software Foundation; either version 2 of the License, or
16+ * (at your option) any later version.
17+ *
18+ * This program is distributed in the hope that it will be useful,
19+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+ * GNU General Public License for more details.
22+ *
23+ * You should have received a copy of the GNU General Public License
24+ * along with this program; if not, write to the Free Software
25+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26+ *
27+ */
28+
29+#include <config.h>
30+
31+#include <stdlib.h>
32+#include <stdio.h>
33+#include <fcntl.h>
34+#include <unistd.h>
35+#include <string.h>
36+#include <sys/wait.h>
37+#include <errno.h>
38+#include <sys/time.h>
39+#include <sys/types.h>
40+#include <pwd.h>
41+
42+#include <glib.h>
43+#include <glib-object.h>
44+
45+#include <dbus/dbus-glib.h>
46+#include <dbus/dbus-glib-lowlevel.h>
47+
48+#include <polkit/polkit.h>
49+
50+#define GCONF_ENABLE_INTERNALS
51+#include <gconf/gconf-client.h>
52+#include <gconf/gconf-engine.h>
53+
54+#include "gconf-defaults.h"
55+#include "gconf-defaults-glue.h"
56+
57+static gboolean
58+do_exit (gpointer user_data)
59+{
60+ g_debug ("Exiting due to inactivity");
61+ exit (1);
62+ return FALSE;
63+}
64+
65+static guint timer_id = 0;
66+gboolean disable_killtimer = FALSE;
67+
68+static void
69+stop_killtimer (void)
70+{
71+ if (disable_killtimer)
72+ return;
73+
74+ if (timer_id > 0) {
75+ g_source_remove (timer_id);
76+ timer_id = 0;
77+ }
78+}
79+
80+static void
81+start_killtimer (void)
82+{
83+ if (disable_killtimer)
84+ return;
85+
86+ if (timer_id == 0) {
87+ g_debug ("Setting killtimer to 30 seconds...");
88+ timer_id = g_timeout_add_seconds (30, do_exit, NULL);
89+ }
90+}
91+
92+static gint operations = 0;
93+
94+static void
95+start_operation (void)
96+{
97+ if (operations == 0)
98+ stop_killtimer ();
99+ operations++;
100+}
101+
102+static void
103+stop_operation (void)
104+{
105+ if (operations == 1)
106+ start_killtimer ();
107+ operations --;
108+}
109+
110+struct GConfDefaultsPrivate
111+{
112+ DBusGConnection *system_bus_connection;
113+ DBusGProxy *system_bus_proxy;
114+ PolkitAuthority *auth;
115+};
116+
117+static void gconf_defaults_finalize (GObject *object);
118+
119+G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
120+
121+#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
122+
123+GQuark
124+gconf_defaults_error_quark (void)
125+{
126+ static GQuark ret = 0;
127+
128+ if (ret == 0) {
129+ ret = g_quark_from_static_string ("gconf_defaults_error");
130+ }
131+
132+ return ret;
133+}
134+
135+
136+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
137+
138+GType
139+gconf_defaults_error_get_type (void)
140+{
141+ static GType etype = 0;
142+
143+ if (etype == 0)
144+ {
145+ static const GEnumValue values[] =
146+ {
147+ ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
148+ ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
149+ { 0, 0, 0 }
150+ };
151+
152+ g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
153+
154+ etype = g_enum_register_static ("GConfDefaultsError", values);
155+ }
156+
157+ return etype;
158+}
159+
160+
161+static GObject *
162+gconf_defaults_constructor (GType type,
163+ guint n_construct_properties,
164+ GObjectConstructParam *construct_properties)
165+{
166+ GConfDefaults *mechanism;
167+ GConfDefaultsClass *klass;
168+
169+ klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
170+
171+ mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
172+ type,
173+ n_construct_properties,
174+ construct_properties));
175+
176+ return G_OBJECT (mechanism);
177+}
178+
179+enum {
180+ SYSTEM_SET,
181+ LAST_SIGNAL
182+};
183+
184+static guint signals[LAST_SIGNAL] = { 0 };
185+
186+static void
187+gconf_defaults_class_init (GConfDefaultsClass *klass)
188+{
189+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
190+
191+ object_class->constructor = gconf_defaults_constructor;
192+ object_class->finalize = gconf_defaults_finalize;
193+
194+ signals[SYSTEM_SET] = g_signal_new ("system-set",
195+ G_OBJECT_CLASS_TYPE (object_class),
196+ G_SIGNAL_RUN_FIRST,
197+ G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
198+ NULL, NULL,
199+ g_cclosure_marshal_VOID__BOXED,
200+ G_TYPE_NONE, 1, G_TYPE_STRV);
201+
202+ g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
203+
204+ dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
205+
206+ dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
207+
208+}
209+
210+static void
211+gconf_defaults_init (GConfDefaults *mechanism)
212+{
213+ mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
214+}
215+
216+static void
217+gconf_defaults_finalize (GObject *object)
218+{
219+ GConfDefaults *mechanism;
220+
221+ g_return_if_fail (object != NULL);
222+ g_return_if_fail (GCONF_IS_DEFAULTS (object));
223+
224+ mechanism = GCONF_DEFAULTS (object);
225+
226+ g_return_if_fail (mechanism->priv != NULL);
227+
228+ g_object_unref (mechanism->priv->auth);
229+ g_object_unref (mechanism->priv->system_bus_proxy);
230+
231+ G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
232+}
233+
234+static gboolean
235+register_mechanism (GConfDefaults *mechanism)
236+{
237+ GError *error = NULL;
238+
239+ mechanism->priv->auth = polkit_authority_get ();
240+
241+ error = NULL;
242+ mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
243+ if (mechanism->priv->system_bus_connection == NULL) {
244+ if (error != NULL) {
245+ g_critical ("error getting system bus: %s", error->message);
246+ g_error_free (error);
247+ }
248+ goto error;
249+ }
250+
251+ dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
252+ G_OBJECT (mechanism));
253+
254+ mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
255+ DBUS_SERVICE_DBUS,
256+ DBUS_PATH_DBUS,
257+ DBUS_INTERFACE_DBUS);
258+
259+ start_killtimer ();
260+
261+ return TRUE;
262+
263+error:
264+ return FALSE;
265+}
266+
267+
268+GConfDefaults *
269+gconf_defaults_new (void)
270+{
271+ GObject *object;
272+ gboolean res;
273+
274+ object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
275+
276+ res = register_mechanism (GCONF_DEFAULTS (object));
277+ if (! res) {
278+ g_object_unref (object);
279+ return NULL;
280+ }
281+
282+ return GCONF_DEFAULTS (object);
283+}
284+
285+static const char *
286+polkit_action_for_gconf_path (GConfDefaults *mechanism,
287+ GList *action_descriptions,
288+ const char *annotation_key,
289+ const char *path)
290+{
291+ char *prefix, *p;
292+ const char *action;
293+ GList *l;
294+ PolkitActionDescription *action_description;
295+ const gchar *annotation;
296+
297+ g_debug ("finding action for path '%s'", path);
298+ prefix = g_strdup (path);
299+ while (1) {
300+ for (l = action_descriptions; l; l = l->next) {
301+ action_description = l->data;
302+
303+ annotation = polkit_action_description_get_annotation (action_description, annotation_key);
304+ if (g_strcmp0 (prefix, annotation) == 0) {
305+ action = polkit_action_description_get_action_id (action_description);
306+ g_debug ("action for prefix '%s': '%s'\n", prefix, action);
307+ goto found;
308+ }
309+ }
310+
311+ p = strrchr (prefix, '/');
312+
313+ if (p == NULL || p == prefix) {
314+ action = NULL;
315+ break;
316+ }
317+
318+ *p = 0;
319+ }
320+
321+ found:
322+ g_free (prefix);
323+
324+ return action;
325+}
326+
327+static void
328+throw_error (DBusGMethodInvocation *context,
329+ gint error_code,
330+ const gchar *format,
331+ ...)
332+{
333+ GError *error;
334+ va_list args;
335+ gchar *message;
336+
337+ va_start (args, format);
338+ message = g_strdup_vprintf (format, args);
339+ va_end (args);
340+
341+ error = g_error_new (GCONF_DEFAULTS_ERROR,
342+ error_code,
343+ "%s", message);
344+ dbus_g_method_return_error (context, error);
345+ g_error_free (error);
346+ g_free (message);
347+}
348+
349+typedef void (*AuthObtainedCallback) (GConfDefaults *mechanism,
350+ DBusGMethodInvocation *context,
351+ gpointer user_data);
352+
353+typedef struct
354+{
355+ GConfDefaults *mechanism;
356+ DBusGMethodInvocation *context;
357+ gchar **actions;
358+ gint id;
359+ gint flags;
360+ AuthObtainedCallback auth_obtained_callback;
361+ GAsyncReadyCallback check_auth_callback;
362+ gpointer user_data;
363+ GDestroyNotify destroy;
364+ PolkitSubject *subject;
365+ gboolean challenge;
366+} CheckAuthData;
367+
368+static void
369+check_auth_data_free (CheckAuthData *data)
370+{
371+ g_object_unref (data->mechanism);
372+ g_strfreev (data->actions);
373+ if (data->destroy)
374+ data->destroy (data->user_data);
375+ g_object_unref (data->subject);
376+ g_free (data);
377+}
378+
379+static void check_next_action (CheckAuthData *data);
380+
381+static void
382+check_authorization_callback (PolkitAuthority *authority,
383+ GAsyncResult *res,
384+ gpointer user_data)
385+{
386+ CheckAuthData *data = user_data;
387+ PolkitAuthorizationResult *result;
388+ GError *error;
389+ gboolean is_authorized;
390+
391+ is_authorized = FALSE;
392+
393+ error = NULL;
394+ result = polkit_authority_check_authorization_finish (authority,
395+ res,
396+ &error);
397+ if (error != NULL) {
398+ g_debug ("error checking action '%s'\n", error->message);
399+ throw_error (data->context,
400+ GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
401+ "Not Authorized: %s", error->message);
402+ g_error_free (error);
403+ }
404+ else {
405+ if (polkit_authorization_result_get_is_authorized (result)) {
406+ g_debug ("result for '%s': authorized\n",
407+ data->actions[data->id]);
408+ is_authorized = TRUE;
409+ }
410+ else if (polkit_authorization_result_get_is_challenge (result)) {
411+ g_debug ("result for '%s': challenge\n",
412+ data->actions[data->id]);
413+ throw_error (data->context,
414+ GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
415+ "Authorization is required");
416+ }
417+ else {
418+ g_debug ("result for '%s': not authorized\n",
419+ data->actions[data->id]);
420+ throw_error (data->context,
421+ GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
422+ "Not Authorized");
423+ }
424+ }
425+
426+ if (is_authorized) {
427+ data->id++;
428+ if (data->actions[data->id] == NULL)
429+ data->auth_obtained_callback (data->mechanism,
430+ data->context,
431+ data->user_data);
432+ else {
433+ check_next_action (data);
434+ return; /* continue operation */
435+ }
436+ }
437+
438+ check_auth_data_free (data);
439+ g_object_unref (result);
440+ stop_operation ();
441+}
442+
443+static void
444+check_next_action (CheckAuthData *data)
445+{
446+ g_debug ("checking action '%s'\n", data->actions[data->id]);
447+ polkit_authority_check_authorization (data->mechanism->priv->auth,
448+ data->subject,
449+ data->actions[data->id],
450+ NULL,
451+ data->flags,
452+ NULL,
453+ data->check_auth_callback,
454+ data);
455+}
456+
457+static void
458+check_polkit_for_actions (GConfDefaults *mechanism,
459+ DBusGMethodInvocation *context,
460+ gchar **actions,
461+ AuthObtainedCallback auth_obtained_callback,
462+ gpointer user_data,
463+ GDestroyNotify destroy)
464+{
465+ CheckAuthData *data;
466+
467+ data = g_new0 (CheckAuthData, 1);
468+ data->mechanism = g_object_ref (mechanism);
469+ data->context = context;
470+ data->actions = actions;
471+ data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
472+ data->id = 0;
473+ data->auth_obtained_callback = auth_obtained_callback;
474+ data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback;
475+ data->user_data = user_data;
476+ data->destroy = destroy;
477+ data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
478+ data->challenge = FALSE;
479+
480+ check_next_action (data);
481+}
482+
483+static char *
484+gconf_address_for_caller (GConfDefaults *mechanism,
485+ DBusGMethodInvocation *context,
486+ GError **gerror)
487+{
488+ char *sender;
489+ DBusConnection *conn;
490+ uid_t uid;
491+ struct passwd *pwd;
492+ char *result;
493+ DBusError error;
494+
495+ conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
496+ sender = dbus_g_method_get_sender (context);
497+
498+ dbus_error_init (&error);
499+ uid = dbus_bus_get_unix_user (conn, sender, &error);
500+ g_free (sender);
501+ if (uid == (unsigned)-1) {
502+ dbus_set_g_error (gerror, &error);
503+ dbus_error_free (&error);
504+ return NULL;
505+ }
506+
507+ pwd = getpwuid (uid);
508+ if (pwd == NULL) {
509+ g_set_error (gerror,
510+ 0, 0,
511+ "Failed to get passwd information for uid %d", uid);
512+ return NULL;
513+ }
514+
515+ result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
516+ return result;
517+}
518+
519+static gboolean
520+path_is_excluded (const char *path,
521+ const char **excludes)
522+{
523+ int i;
524+
525+ for (i = 0; excludes && excludes[i]; i++) {
526+ if (g_str_has_prefix (path, excludes[i]))
527+ return TRUE;
528+ }
529+
530+ return FALSE;
531+}
532+
533+static void
534+copy_tree (GConfClient *src,
535+ const char *path,
536+ GConfChangeSet *changes,
537+ const char **excludes)
538+{
539+ GSList *list, *l;
540+ GConfEntry *entry;
541+
542+ if (path_is_excluded (path, excludes))
543+ return;
544+
545+ list = gconf_client_all_entries (src, path, NULL);
546+ for (l = list; l; l = l->next) {
547+ entry = l->data;
548+ if (!path_is_excluded (entry->key, excludes))
549+ gconf_change_set_set (changes, entry->key, entry->value);
550+ }
551+ g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
552+ g_slist_free (list);
553+
554+ list = gconf_client_all_dirs (src, path, NULL);
555+ for (l = list; l; l = l->next)
556+ copy_tree (src, (const char *)l->data, changes, excludes);
557+ g_slist_foreach (list, (GFunc)g_free, NULL);
558+ g_slist_free (list);
559+}
560+
561+static void
562+copy_entry (GConfClient *src,
563+ const char *path,
564+ GConfChangeSet *changes,
565+ const char **excludes)
566+{
567+ GConfValue *value;
568+
569+ if (path_is_excluded (path, excludes))
570+ return;
571+
572+ value = gconf_client_get (src, path, NULL);
573+ if (value) {
574+ gconf_change_set_set (changes, path, value);
575+ gconf_value_free (value);
576+ }
577+}
578+
579+typedef void (*ChangeSetCallback) (GConfDefaults *mechanism,
580+ GConfChangeSet *changes,
581+ gpointer data);
582+
583+typedef struct
584+{
585+ GConfDefaults *mechanism;
586+ DBusGMethodInvocation *context;
587+ const char *dest_address;
588+ char **actions;
589+ char **includes;
590+ char **excludes;
591+ GConfValue *value;
592+ ChangeSetCallback changeset_callback;
593+ gpointer user_data;
594+ GDestroyNotify destroy;
595+} CopyData;
596+
597+static void
598+copy_data_free (gpointer user_data)
599+{
600+ CopyData *data = user_data;
601+
602+ g_object_unref (data->mechanism);
603+ g_strfreev (data->includes);
604+ g_strfreev (data->excludes);
605+ g_strfreev (data->actions);
606+ if (data->value)
607+ gconf_value_free (data->value);
608+ if (data->destroy)
609+ data->destroy (data->user_data);
610+ g_free (data);
611+}
612+
613+static void
614+do_copy_authorized (GConfDefaults *mechanism,
615+ DBusGMethodInvocation *context,
616+ gpointer user_data)
617+{
618+ CopyData *data = user_data;
619+ GConfClient *source = NULL;
620+ GConfClient *dest = NULL;
621+ GConfChangeSet *changes = NULL;
622+ GConfEngine *engine;
623+ char *address = NULL;
624+ gint i;
625+ GError *error;
626+
627+ error = NULL;
628+ engine = gconf_engine_get_local (data->dest_address, &error);
629+ if (error)
630+ goto cleanup;
631+
632+ dest = gconf_client_get_for_engine (engine);
633+ gconf_engine_unref (engine);
634+
635+ /* find the address to from the caller id */
636+ address = gconf_address_for_caller (data->mechanism, data->context, &error);
637+ if (error)
638+ goto cleanup;
639+
640+ engine = gconf_engine_get_local (address, &error);
641+ if (error)
642+ goto cleanup;
643+
644+ source = gconf_client_get_for_engine (engine);
645+ gconf_engine_unref (engine);
646+
647+ changes = gconf_change_set_new ();
648+
649+ if (data->value) {
650+ g_assert (data->includes[1] == NULL);
651+ g_assert (data->excludes == NULL);
652+
653+ gconf_change_set_set (changes, data->includes[0], data->value);
654+ }
655+ else {
656+ /* recursively copy each include, leaving out the excludes */
657+ for (i = 0; data->includes[i]; i++) {
658+ if (gconf_client_dir_exists (source, data->includes[i], NULL))
659+ copy_tree (source, data->includes[i], changes, (const char **)data->excludes);
660+ else
661+ copy_entry (source, data->includes[i], changes, (const char **)data->excludes);
662+ }
663+ }
664+
665+ gconf_client_commit_change_set (dest, changes, FALSE, &error);
666+ gconf_client_suggest_sync (dest, NULL);
667+
668+ if (data->changeset_callback) {
669+ data->changeset_callback (data->mechanism, changes, data->user_data);
670+ }
671+
672+cleanup:
673+ g_free (address);
674+ if (changes)
675+ gconf_change_set_unref (changes);
676+ if (dest)
677+ g_object_unref (dest);
678+ if (source)
679+ g_object_unref (source);
680+
681+ if (error) {
682+ throw_error (data->context,
683+ GCONF_DEFAULTS_ERROR_GENERAL,
684+ "%s", error->message);
685+ g_error_free (error);
686+ }
687+ else
688+ dbus_g_method_return (data->context);
689+}
690+
691+typedef void (*ActionsReadyCallback) (GConfDefaults *mechanism,
692+ DBusGMethodInvocation *context,
693+ gchar **actions,
694+ AuthObtainedCallback auth_obtained_callback,
695+ gpointer data,
696+ GDestroyNotify destroy);
697+
698+typedef struct
699+{
700+ GConfDefaults *mechanism;
701+ DBusGMethodInvocation *context;
702+ char **includes;
703+ const char *default_action;
704+ const char *annotation_key;
705+ ActionsReadyCallback actions_ready_callback;
706+ AuthObtainedCallback auth_obtained_callback;
707+ gpointer data;
708+ GDestroyNotify destroy;
709+} ActionData;
710+
711+static void
712+action_data_free (ActionData *data)
713+{
714+ g_object_unref (data->mechanism);
715+ g_strfreev (data->includes);
716+ if (data->destroy)
717+ data->destroy (data->data);
718+ g_free (data);
719+}
720+
721+static void
722+actions_ready_cb (GObject *source,
723+ GAsyncResult *res,
724+ gpointer user_data)
725+{
726+ ActionData *data = user_data;
727+ GList *action_descriptions;
728+ GError *error = NULL;
729+ int i;
730+ GHashTable *obtained;
731+ GHashTableIter iter;
732+ const gchar *action;
733+ gchar **actions;
734+ gpointer key, value;
735+
736+ action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error);
737+
738+ if (error) {
739+ throw_error (data->context,
740+ GCONF_DEFAULTS_ERROR_GENERAL,
741+ "Failed to get action descriptions: %s", error->message);
742+ g_error_free (error);
743+ action_data_free (data);
744+ stop_operation ();
745+ return;
746+ }
747+
748+ obtained = g_hash_table_new (g_str_hash, g_str_equal);
749+
750+ for (i = 0; data->includes[i]; i++) {
751+ action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]);
752+ if (action == NULL) {
753+ g_debug ("using default action '%s' for path '%s'",
754+ data->default_action, data->includes[i]);
755+ action = data->default_action;
756+ }
757+
758+ g_hash_table_insert (obtained, (gpointer)action, (gpointer)action);
759+ }
760+ actions = g_new0 (char *, g_hash_table_size (obtained) + 1);
761+ g_hash_table_iter_init (&iter, obtained);
762+ i = 0;
763+ while (g_hash_table_iter_next (&iter, &key, &value)) {
764+ actions[i] = g_strdup ((char *)key);
765+ i++;
766+ }
767+ g_hash_table_destroy (obtained);
768+ g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL);
769+ g_list_free (action_descriptions);
770+
771+ data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy);
772+
773+ data->destroy = NULL;
774+ action_data_free (data);
775+}
776+
777+static void
778+do_copy (GConfDefaults *mechanism,
779+ gboolean mandatory,
780+ const gchar **includes,
781+ const gchar **excludes,
782+ GConfValue *value,
783+ DBusGMethodInvocation *context,
784+ ChangeSetCallback changeset_callback,
785+ gpointer user_data,
786+ GDestroyNotify destroy)
787+{
788+ CopyData *cdata;
789+ ActionData *adata;
790+
791+ start_operation ();
792+
793+ cdata = g_new0 (CopyData, 1);
794+ cdata->mechanism = g_object_ref (mechanism);
795+ cdata->context = context;
796+ cdata->includes = g_strdupv ((gchar **)includes);
797+ cdata->excludes = g_strdupv ((gchar **)excludes);
798+ cdata->value = value;
799+ cdata->actions = NULL;
800+ cdata->changeset_callback = changeset_callback;
801+ cdata->user_data = user_data;
802+ cdata->destroy = destroy;
803+
804+ adata = g_new0 (ActionData, 1);
805+ adata->mechanism = g_object_ref (mechanism);
806+ adata->context = context;
807+ adata->includes = g_strdupv ((gchar **)includes);
808+ adata->actions_ready_callback = check_polkit_for_actions;
809+ adata->auth_obtained_callback = do_copy_authorized;
810+ adata->data = cdata;
811+ adata->destroy = copy_data_free;
812+
813+ /* check privileges for each include */
814+ if (mandatory) {
815+ adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
816+ adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
817+ cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory";
818+ }
819+ else {
820+ adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
821+ adata->default_action = "org.gnome.gconf.defaults.set-system";
822+ cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system";
823+ }
824+
825+ polkit_authority_enumerate_actions (mechanism->priv->auth,
826+ NULL,
827+ actions_ready_cb,
828+ adata);
829+}
830+
831+static void
832+append_key (GConfChangeSet *cs,
833+ const gchar *key,
834+ GConfValue *value,
835+ gpointer user_data)
836+{
837+ GPtrArray *keys = (GPtrArray *) user_data;
838+
839+ g_ptr_array_add (keys, (gpointer) key);
840+}
841+
842+static void
843+set_system_changes (GConfDefaults *mechanism,
844+ GConfChangeSet *changes,
845+ gpointer data)
846+{
847+ GPtrArray *keys;
848+
849+ keys = g_ptr_array_new ();
850+ gconf_change_set_foreach (changes, append_key, keys);
851+ g_ptr_array_add (keys, NULL);
852+
853+ g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
854+
855+ g_ptr_array_free (keys, TRUE);
856+}
857+
858+void
859+gconf_defaults_set_system (GConfDefaults *mechanism,
860+ const char **includes,
861+ const char **excludes,
862+ DBusGMethodInvocation *context)
863+{
864+ do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL);
865+}
866+
867+void
868+gconf_defaults_set_mandatory (GConfDefaults *mechanism,
869+ const char **includes,
870+ const char **excludes,
871+ DBusGMethodInvocation *context)
872+{
873+ do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL);
874+}
875+
876+static void
877+unset_tree (GConfClient *dest,
878+ const char *path,
879+ GConfChangeSet *changes,
880+ const char **excludes)
881+{
882+ GSList *list, *l;
883+ GConfEntry *entry;
884+
885+ if (path_is_excluded (path, excludes))
886+ return;
887+
888+ list = gconf_client_all_entries (dest, path, NULL);
889+ for (l = list; l; l = l->next) {
890+ entry = l->data;
891+ if (!path_is_excluded (entry->key, excludes))
892+ gconf_change_set_unset (changes, entry->key);
893+ }
894+ g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
895+ g_slist_free (list);
896+
897+ list = gconf_client_all_dirs (dest, path, NULL);
898+ for (l = list; l; l = l->next)
899+ unset_tree (dest, (const char *)l->data, changes, excludes);
900+ g_slist_foreach (list, (GFunc)g_free, NULL);
901+ g_slist_free (list);
902+}
903+
904+static void
905+unset_entry (GConfClient *dest,
906+ const char *path,
907+ GConfChangeSet *changes,
908+ const char **excludes)
909+{
910+ if (path_is_excluded (path, excludes))
911+ return;
912+
913+ gconf_change_set_unset (changes, path);
914+}
915+
916+static void
917+unset_in_db (GConfDefaults *mechanism,
918+ const gchar *address,
919+ const gchar **includes,
920+ const gchar **excludes,
921+ GError **error)
922+{
923+ GConfEngine *engine;
924+ GConfClient *dest = NULL;
925+ GConfChangeSet *changes = NULL;
926+ int i;
927+
928+ engine = gconf_engine_get_local (address, error);
929+ if (*error)
930+ goto out;
931+
932+ dest = gconf_client_get_for_engine (engine);
933+ gconf_engine_unref (engine);
934+
935+ changes = gconf_change_set_new ();
936+
937+ /* recursively copy each include, leaving out the excludes */
938+ for (i = 0; includes[i]; i++) {
939+ if (gconf_client_dir_exists (dest, includes[i], NULL))
940+ unset_tree (dest, includes[i], changes, excludes);
941+ else
942+ unset_entry (dest, includes[i], changes, excludes);
943+ }
944+
945+ gconf_client_commit_change_set (dest, changes, TRUE, error);
946+ gconf_client_suggest_sync (dest, NULL);
947+
948+out:
949+ if (dest)
950+ g_object_unref (dest);
951+ if (changes)
952+ gconf_change_set_unref (changes);
953+}
954+
955+typedef struct
956+{
957+ GConfDefaults *mechanism;
958+ DBusGMethodInvocation *context;
959+ char **includes;
960+ char **excludes;
961+} UnsetData;
962+
963+static void
964+unset_data_free (gpointer user_data)
965+{
966+ UnsetData *data = user_data;
967+
968+ g_object_unref (data->mechanism);
969+ g_strfreev (data->includes);
970+ g_strfreev (data->excludes);
971+ g_free (data);
972+}
973+
974+static void
975+do_unset_authorized (GConfDefaults *mechanism,
976+ DBusGMethodInvocation *context,
977+ gpointer user_data)
978+{
979+ UnsetData *data = user_data;
980+ GError *error;
981+
982+ error = NULL;
983+ unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory",
984+ (const gchar **)data->includes,
985+ (const gchar **)data->excludes, &error);
986+
987+ if (error) {
988+ throw_error (data->context,
989+ GCONF_DEFAULTS_ERROR,
990+ GCONF_DEFAULTS_ERROR_GENERAL,
991+ "%s", error->message);
992+ g_error_free (error);
993+ }
994+ else
995+ dbus_g_method_return (data->context);
996+}
997+
998+void
999+gconf_defaults_unset_mandatory (GConfDefaults *mechanism,
1000+ const char **includes,
1001+ const char **excludes,
1002+ DBusGMethodInvocation *context)
1003+{
1004+ UnsetData *udata;
1005+ ActionData *adata;
1006+
1007+ start_operation ();
1008+
1009+ udata = g_new0 (UnsetData, 1);
1010+ udata->mechanism = g_object_ref (mechanism);
1011+ udata->context = context;
1012+ udata->includes = g_strdupv ((gchar **)includes);
1013+ udata->excludes = g_strdupv ((gchar **)excludes);
1014+
1015+ adata = g_new0 (ActionData, 1);
1016+ adata->mechanism = g_object_ref (mechanism);
1017+ adata->context = context;
1018+ adata->includes = g_strdupv ((gchar **)includes);
1019+ adata->auth_obtained_callback = do_unset_authorized;
1020+ adata->data = udata;
1021+ adata->destroy = unset_data_free;
1022+
1023+ adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1024+ adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1025+
1026+ polkit_authority_enumerate_actions (mechanism->priv->auth,
1027+ NULL,
1028+ actions_ready_cb,
1029+ adata);
1030+}
1031+
1032+static void
1033+check_authorization_only_callback (PolkitAuthority *authority,
1034+ GAsyncResult *res,
1035+ gpointer user_data)
1036+{
1037+ CheckAuthData *data = user_data;
1038+ PolkitAuthorizationResult *result;
1039+ GError *error;
1040+ gboolean is_authorized;
1041+
1042+ is_authorized = FALSE;
1043+
1044+ error = NULL;
1045+ result = polkit_authority_check_authorization_finish (authority,
1046+ res,
1047+ &error);
1048+ if (error != NULL) {
1049+ g_debug ("error checking action '%s'\n", error->message);
1050+ throw_error (data->context,
1051+ GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1052+ "Not Authorized: %s", error->message);
1053+ g_error_free (error);
1054+ goto out;
1055+ }
1056+ else {
1057+ if (polkit_authorization_result_get_is_authorized (result)) {
1058+ g_debug ("result for '%s': authorized\n",
1059+ data->actions[data->id]);
1060+ is_authorized = TRUE;
1061+ }
1062+ else if (polkit_authorization_result_get_is_challenge (result)) {
1063+ g_debug ("result for '%s': challenge\n",
1064+ data->actions[data->id]);
1065+ is_authorized = TRUE;
1066+ data->challenge = TRUE;
1067+ }
1068+ else {
1069+ g_debug ("result for '%s': not authorized\n",
1070+ data->actions[data->id]);
1071+ is_authorized = FALSE;
1072+ }
1073+ }
1074+
1075+ if (is_authorized) {
1076+ data->id++;
1077+ if (data->actions[data->id] == NULL) {
1078+ gint result;
1079+
1080+ result = data->challenge ? 1 : 2;
1081+ g_debug ("return %d\n", result);
1082+ dbus_g_method_return (data->context, result);
1083+ }
1084+ else {
1085+ check_next_action (data);
1086+ return; /* continue operation */
1087+ }
1088+ }
1089+ else {
1090+ g_debug ("return 0\n");
1091+ dbus_g_method_return (data->context, 0);
1092+ }
1093+
1094+out:
1095+ check_auth_data_free (data);
1096+ g_object_unref (result);
1097+ stop_operation ();
1098+}
1099+
1100+static void
1101+check_permissions_only (GConfDefaults *mechanism,
1102+ DBusGMethodInvocation *context,
1103+ gchar **actions,
1104+ AuthObtainedCallback auth_obtained_callback,
1105+ gpointer user_data,
1106+ GDestroyNotify destroy)
1107+{
1108+ CheckAuthData *data;
1109+
1110+ data = g_new0 (CheckAuthData, 1);
1111+ data->mechanism = g_object_ref (mechanism);
1112+ data->context = context;
1113+ data->actions = actions;
1114+ data->flags = 0;
1115+ data->id = 0;
1116+ data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback;
1117+ data->auth_obtained_callback = NULL;
1118+ data->user_data = NULL;
1119+ data->destroy = NULL;
1120+ data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
1121+ data->challenge = FALSE;
1122+
1123+ check_next_action (data);
1124+}
1125+
1126+static void
1127+do_check (GConfDefaults *mechanism,
1128+ gboolean mandatory,
1129+ const gchar **includes,
1130+ DBusGMethodInvocation *context)
1131+{
1132+ ActionData *adata;
1133+
1134+ start_operation ();
1135+
1136+ adata = g_new0 (ActionData, 1);
1137+ adata->mechanism = g_object_ref (mechanism);
1138+ adata->context = context;
1139+ adata->includes = g_strdupv ((gchar **)includes);
1140+ adata->actions_ready_callback = check_permissions_only;
1141+ adata->auth_obtained_callback = NULL;
1142+ adata->data = NULL;
1143+ adata->destroy = NULL;
1144+
1145+ if (mandatory) {
1146+ adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1147+ adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1148+ }
1149+ else {
1150+ adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
1151+ adata->default_action = "org.gnome.gconf.defaults.set-system";
1152+ }
1153+
1154+ polkit_authority_enumerate_actions (mechanism->priv->auth,
1155+ NULL,
1156+ actions_ready_cb,
1157+ adata);
1158+}
1159+
1160+void
1161+gconf_defaults_can_set_system (GConfDefaults *mechanism,
1162+ const char **includes,
1163+ DBusGMethodInvocation *context)
1164+{
1165+ do_check (mechanism, FALSE, includes, context);
1166+}
1167+
1168+void
1169+gconf_defaults_can_set_mandatory (GConfDefaults *mechanism,
1170+ const char **includes,
1171+ DBusGMethodInvocation *context)
1172+{
1173+ do_check (mechanism, TRUE, includes, context);
1174+}
1175+
1176+void
1177+gconf_defaults_set_system_value (GConfDefaults *mechanism,
1178+ const char *path,
1179+ const char *value,
1180+ DBusGMethodInvocation *context)
1181+{
1182+ GConfValue *gvalue;
1183+ const char *includes[] = { NULL, NULL };
1184+
1185+ gvalue = gconf_value_decode (value);
1186+ if (gvalue) {
1187+ includes[0] = path;
1188+ do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL);
1189+ }
1190+}
1191+
1192+void
1193+gconf_defaults_set_mandatory_value (GConfDefaults *mechanism,
1194+ const char *path,
1195+ const char *value,
1196+ DBusGMethodInvocation *context)
1197+{
1198+ GConfValue *gvalue;
1199+ const char *includes[] = { NULL, NULL };
1200+
1201+ gvalue = gconf_value_decode (value);
1202+ if (gvalue) {
1203+ includes[0] = path;
1204+ do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL);
1205+ }
1206+}
1207+
1208
1209=== removed file '.pc/01_defaults_path.patch/defaults/gconf-defaults.c'
1210--- .pc/01_defaults_path.patch/defaults/gconf-defaults.c 2010-12-06 00:53:14 +0000
1211+++ .pc/01_defaults_path.patch/defaults/gconf-defaults.c 1970-01-01 00:00:00 +0000
1212@@ -1,1199 +0,0 @@
1213-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1214- *
1215- * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com>
1216- *
1217- * This program is free software; you can redistribute it and/or modify
1218- * it under the terms of the GNU General Public License as published by
1219- * the Free Software Foundation; either version 2 of the License, or
1220- * (at your option) any later version.
1221- *
1222- * This program is distributed in the hope that it will be useful,
1223- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1224- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1225- * GNU General Public License for more details.
1226- *
1227- * You should have received a copy of the GNU General Public License
1228- * along with this program; if not, write to the Free Software
1229- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1230- *
1231- */
1232-
1233-#include <config.h>
1234-
1235-#include <stdlib.h>
1236-#include <stdio.h>
1237-#include <fcntl.h>
1238-#include <unistd.h>
1239-#include <string.h>
1240-#include <sys/wait.h>
1241-#include <errno.h>
1242-#include <sys/time.h>
1243-#include <sys/types.h>
1244-#include <pwd.h>
1245-
1246-#include <glib.h>
1247-#include <glib-object.h>
1248-
1249-#include <dbus/dbus-glib.h>
1250-#include <dbus/dbus-glib-lowlevel.h>
1251-
1252-#include <polkit/polkit.h>
1253-
1254-#define GCONF_ENABLE_INTERNALS
1255-#include <gconf/gconf-client.h>
1256-#include <gconf/gconf-engine.h>
1257-
1258-#include "gconf-defaults.h"
1259-#include "gconf-defaults-glue.h"
1260-
1261-static gboolean
1262-do_exit (gpointer user_data)
1263-{
1264- g_debug ("Exiting due to inactivity");
1265- exit (1);
1266- return FALSE;
1267-}
1268-
1269-static guint timer_id = 0;
1270-gboolean disable_killtimer = FALSE;
1271-
1272-static void
1273-stop_killtimer (void)
1274-{
1275- if (disable_killtimer)
1276- return;
1277-
1278- if (timer_id > 0) {
1279- g_source_remove (timer_id);
1280- timer_id = 0;
1281- }
1282-}
1283-
1284-static void
1285-start_killtimer (void)
1286-{
1287- if (disable_killtimer)
1288- return;
1289-
1290- if (timer_id == 0) {
1291- g_debug ("Setting killtimer to 30 seconds...");
1292- timer_id = g_timeout_add_seconds (30, do_exit, NULL);
1293- }
1294-}
1295-
1296-static gint operations = 0;
1297-
1298-static void
1299-start_operation (void)
1300-{
1301- if (operations == 0)
1302- stop_killtimer ();
1303- operations++;
1304-}
1305-
1306-static void
1307-stop_operation (void)
1308-{
1309- if (operations == 1)
1310- start_killtimer ();
1311- operations --;
1312-}
1313-
1314-struct GConfDefaultsPrivate
1315-{
1316- DBusGConnection *system_bus_connection;
1317- DBusGProxy *system_bus_proxy;
1318- PolkitAuthority *auth;
1319-};
1320-
1321-static void gconf_defaults_finalize (GObject *object);
1322-
1323-G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
1324-
1325-#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
1326-
1327-GQuark
1328-gconf_defaults_error_quark (void)
1329-{
1330- static GQuark ret = 0;
1331-
1332- if (ret == 0) {
1333- ret = g_quark_from_static_string ("gconf_defaults_error");
1334- }
1335-
1336- return ret;
1337-}
1338-
1339-
1340-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
1341-
1342-GType
1343-gconf_defaults_error_get_type (void)
1344-{
1345- static GType etype = 0;
1346-
1347- if (etype == 0)
1348- {
1349- static const GEnumValue values[] =
1350- {
1351- ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
1352- ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
1353- { 0, 0, 0 }
1354- };
1355-
1356- g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
1357-
1358- etype = g_enum_register_static ("GConfDefaultsError", values);
1359- }
1360-
1361- return etype;
1362-}
1363-
1364-
1365-static GObject *
1366-gconf_defaults_constructor (GType type,
1367- guint n_construct_properties,
1368- GObjectConstructParam *construct_properties)
1369-{
1370- GConfDefaults *mechanism;
1371- GConfDefaultsClass *klass;
1372-
1373- klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
1374-
1375- mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
1376- type,
1377- n_construct_properties,
1378- construct_properties));
1379-
1380- return G_OBJECT (mechanism);
1381-}
1382-
1383-enum {
1384- SYSTEM_SET,
1385- LAST_SIGNAL
1386-};
1387-
1388-static guint signals[LAST_SIGNAL] = { 0 };
1389-
1390-static void
1391-gconf_defaults_class_init (GConfDefaultsClass *klass)
1392-{
1393- GObjectClass *object_class = G_OBJECT_CLASS (klass);
1394-
1395- object_class->constructor = gconf_defaults_constructor;
1396- object_class->finalize = gconf_defaults_finalize;
1397-
1398- signals[SYSTEM_SET] = g_signal_new ("system-set",
1399- G_OBJECT_CLASS_TYPE (object_class),
1400- G_SIGNAL_RUN_FIRST,
1401- G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
1402- NULL, NULL,
1403- g_cclosure_marshal_VOID__BOXED,
1404- G_TYPE_NONE, 1, G_TYPE_STRV);
1405-
1406- g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
1407-
1408- dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
1409-
1410- dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
1411-
1412-}
1413-
1414-static void
1415-gconf_defaults_init (GConfDefaults *mechanism)
1416-{
1417- mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
1418-}
1419-
1420-static void
1421-gconf_defaults_finalize (GObject *object)
1422-{
1423- GConfDefaults *mechanism;
1424-
1425- g_return_if_fail (object != NULL);
1426- g_return_if_fail (GCONF_IS_DEFAULTS (object));
1427-
1428- mechanism = GCONF_DEFAULTS (object);
1429-
1430- g_return_if_fail (mechanism->priv != NULL);
1431-
1432- g_object_unref (mechanism->priv->auth);
1433- g_object_unref (mechanism->priv->system_bus_proxy);
1434-
1435- G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
1436-}
1437-
1438-static gboolean
1439-register_mechanism (GConfDefaults *mechanism)
1440-{
1441- GError *error = NULL;
1442-
1443- mechanism->priv->auth = polkit_authority_get ();
1444-
1445- error = NULL;
1446- mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
1447- if (mechanism->priv->system_bus_connection == NULL) {
1448- if (error != NULL) {
1449- g_critical ("error getting system bus: %s", error->message);
1450- g_error_free (error);
1451- }
1452- goto error;
1453- }
1454-
1455- dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
1456- G_OBJECT (mechanism));
1457-
1458- mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
1459- DBUS_SERVICE_DBUS,
1460- DBUS_PATH_DBUS,
1461- DBUS_INTERFACE_DBUS);
1462-
1463- start_killtimer ();
1464-
1465- return TRUE;
1466-
1467-error:
1468- return FALSE;
1469-}
1470-
1471-
1472-GConfDefaults *
1473-gconf_defaults_new (void)
1474-{
1475- GObject *object;
1476- gboolean res;
1477-
1478- object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
1479-
1480- res = register_mechanism (GCONF_DEFAULTS (object));
1481- if (! res) {
1482- g_object_unref (object);
1483- return NULL;
1484- }
1485-
1486- return GCONF_DEFAULTS (object);
1487-}
1488-
1489-static const char *
1490-polkit_action_for_gconf_path (GConfDefaults *mechanism,
1491- GList *action_descriptions,
1492- const char *annotation_key,
1493- const char *path)
1494-{
1495- char *prefix, *p;
1496- const char *action;
1497- GList *l;
1498- PolkitActionDescription *action_description;
1499- const gchar *annotation;
1500-
1501- g_debug ("finding action for path '%s'", path);
1502- prefix = g_strdup (path);
1503- while (1) {
1504- for (l = action_descriptions; l; l = l->next) {
1505- action_description = l->data;
1506-
1507- annotation = polkit_action_description_get_annotation (action_description, annotation_key);
1508- if (g_strcmp0 (prefix, annotation) == 0) {
1509- action = polkit_action_description_get_action_id (action_description);
1510- g_debug ("action for prefix '%s': '%s'\n", prefix, action);
1511- goto found;
1512- }
1513- }
1514-
1515- p = strrchr (prefix, '/');
1516-
1517- if (p == NULL || p == prefix) {
1518- action = NULL;
1519- break;
1520- }
1521-
1522- *p = 0;
1523- }
1524-
1525- found:
1526- g_free (prefix);
1527-
1528- return action;
1529-}
1530-
1531-static void
1532-throw_error (DBusGMethodInvocation *context,
1533- gint error_code,
1534- const gchar *format,
1535- ...)
1536-{
1537- GError *error;
1538- va_list args;
1539- gchar *message;
1540-
1541- va_start (args, format);
1542- message = g_strdup_vprintf (format, args);
1543- va_end (args);
1544-
1545- error = g_error_new (GCONF_DEFAULTS_ERROR,
1546- error_code,
1547- "%s", message);
1548- dbus_g_method_return_error (context, error);
1549- g_error_free (error);
1550- g_free (message);
1551-}
1552-
1553-typedef void (*AuthObtainedCallback) (GConfDefaults *mechanism,
1554- DBusGMethodInvocation *context,
1555- gpointer user_data);
1556-
1557-typedef struct
1558-{
1559- GConfDefaults *mechanism;
1560- DBusGMethodInvocation *context;
1561- gchar **actions;
1562- gint id;
1563- gint flags;
1564- AuthObtainedCallback auth_obtained_callback;
1565- GAsyncReadyCallback check_auth_callback;
1566- gpointer user_data;
1567- GDestroyNotify destroy;
1568- PolkitSubject *subject;
1569- gboolean challenge;
1570-} CheckAuthData;
1571-
1572-static void
1573-check_auth_data_free (CheckAuthData *data)
1574-{
1575- g_object_unref (data->mechanism);
1576- g_strfreev (data->actions);
1577- if (data->destroy)
1578- data->destroy (data->user_data);
1579- g_object_unref (data->subject);
1580- g_free (data);
1581-}
1582-
1583-static void check_next_action (CheckAuthData *data);
1584-
1585-static void
1586-check_authorization_callback (PolkitAuthority *authority,
1587- GAsyncResult *res,
1588- gpointer user_data)
1589-{
1590- CheckAuthData *data = user_data;
1591- PolkitAuthorizationResult *result;
1592- GError *error;
1593- gboolean is_authorized;
1594-
1595- is_authorized = FALSE;
1596-
1597- error = NULL;
1598- result = polkit_authority_check_authorization_finish (authority,
1599- res,
1600- &error);
1601- if (error != NULL) {
1602- g_debug ("error checking action '%s'\n", error->message);
1603- throw_error (data->context,
1604- GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1605- "Not Authorized: %s", error->message);
1606- g_error_free (error);
1607- }
1608- else {
1609- if (polkit_authorization_result_get_is_authorized (result)) {
1610- g_debug ("result for '%s': authorized\n",
1611- data->actions[data->id]);
1612- is_authorized = TRUE;
1613- }
1614- else if (polkit_authorization_result_get_is_challenge (result)) {
1615- g_debug ("result for '%s': challenge\n",
1616- data->actions[data->id]);
1617- throw_error (data->context,
1618- GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1619- "Authorization is required");
1620- }
1621- else {
1622- g_debug ("result for '%s': not authorized\n",
1623- data->actions[data->id]);
1624- throw_error (data->context,
1625- GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1626- "Not Authorized");
1627- }
1628- }
1629-
1630- if (is_authorized) {
1631- data->id++;
1632- if (data->actions[data->id] == NULL)
1633- data->auth_obtained_callback (data->mechanism,
1634- data->context,
1635- data->user_data);
1636- else {
1637- check_next_action (data);
1638- return; /* continue operation */
1639- }
1640- }
1641-
1642- check_auth_data_free (data);
1643- g_object_unref (result);
1644- stop_operation ();
1645-}
1646-
1647-static void
1648-check_next_action (CheckAuthData *data)
1649-{
1650- g_debug ("checking action '%s'\n", data->actions[data->id]);
1651- polkit_authority_check_authorization (data->mechanism->priv->auth,
1652- data->subject,
1653- data->actions[data->id],
1654- NULL,
1655- data->flags,
1656- NULL,
1657- data->check_auth_callback,
1658- data);
1659-}
1660-
1661-static void
1662-check_polkit_for_actions (GConfDefaults *mechanism,
1663- DBusGMethodInvocation *context,
1664- gchar **actions,
1665- AuthObtainedCallback auth_obtained_callback,
1666- gpointer user_data,
1667- GDestroyNotify destroy)
1668-{
1669- CheckAuthData *data;
1670-
1671- data = g_new0 (CheckAuthData, 1);
1672- data->mechanism = g_object_ref (mechanism);
1673- data->context = context;
1674- data->actions = actions;
1675- data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
1676- data->id = 0;
1677- data->auth_obtained_callback = auth_obtained_callback;
1678- data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback;
1679- data->user_data = user_data;
1680- data->destroy = destroy;
1681- data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
1682- data->challenge = FALSE;
1683-
1684- check_next_action (data);
1685-}
1686-
1687-static char *
1688-gconf_address_for_caller (GConfDefaults *mechanism,
1689- DBusGMethodInvocation *context,
1690- GError **gerror)
1691-{
1692- char *sender;
1693- DBusConnection *conn;
1694- uid_t uid;
1695- struct passwd *pwd;
1696- char *result;
1697- DBusError error;
1698-
1699- conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
1700- sender = dbus_g_method_get_sender (context);
1701-
1702- dbus_error_init (&error);
1703- uid = dbus_bus_get_unix_user (conn, sender, &error);
1704- g_free (sender);
1705- if (uid == (unsigned)-1) {
1706- dbus_set_g_error (gerror, &error);
1707- dbus_error_free (&error);
1708- return NULL;
1709- }
1710-
1711- pwd = getpwuid (uid);
1712- if (pwd == NULL) {
1713- g_set_error (gerror,
1714- 0, 0,
1715- "Failed to get passwd information for uid %d", uid);
1716- return NULL;
1717- }
1718-
1719- result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
1720- return result;
1721-}
1722-
1723-static gboolean
1724-path_is_excluded (const char *path,
1725- const char **excludes)
1726-{
1727- int i;
1728-
1729- for (i = 0; excludes && excludes[i]; i++) {
1730- if (g_str_has_prefix (path, excludes[i]))
1731- return TRUE;
1732- }
1733-
1734- return FALSE;
1735-}
1736-
1737-static void
1738-copy_tree (GConfClient *src,
1739- const char *path,
1740- GConfChangeSet *changes,
1741- const char **excludes)
1742-{
1743- GSList *list, *l;
1744- GConfEntry *entry;
1745-
1746- if (path_is_excluded (path, excludes))
1747- return;
1748-
1749- list = gconf_client_all_entries (src, path, NULL);
1750- for (l = list; l; l = l->next) {
1751- entry = l->data;
1752- if (!path_is_excluded (entry->key, excludes))
1753- gconf_change_set_set (changes, entry->key, entry->value);
1754- }
1755- g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
1756- g_slist_free (list);
1757-
1758- list = gconf_client_all_dirs (src, path, NULL);
1759- for (l = list; l; l = l->next)
1760- copy_tree (src, (const char *)l->data, changes, excludes);
1761- g_slist_foreach (list, (GFunc)g_free, NULL);
1762- g_slist_free (list);
1763-}
1764-
1765-static void
1766-copy_entry (GConfClient *src,
1767- const char *path,
1768- GConfChangeSet *changes,
1769- const char **excludes)
1770-{
1771- GConfValue *value;
1772-
1773- if (path_is_excluded (path, excludes))
1774- return;
1775-
1776- value = gconf_client_get (src, path, NULL);
1777- if (value) {
1778- gconf_change_set_set (changes, path, value);
1779- gconf_value_free (value);
1780- }
1781-}
1782-
1783-typedef void (*ChangeSetCallback) (GConfDefaults *mechanism,
1784- GConfChangeSet *changes,
1785- gpointer data);
1786-
1787-typedef struct
1788-{
1789- GConfDefaults *mechanism;
1790- DBusGMethodInvocation *context;
1791- const char *dest_address;
1792- char **actions;
1793- char **includes;
1794- char **excludes;
1795- GConfValue *value;
1796- ChangeSetCallback changeset_callback;
1797- gpointer user_data;
1798- GDestroyNotify destroy;
1799-} CopyData;
1800-
1801-static void
1802-copy_data_free (gpointer user_data)
1803-{
1804- CopyData *data = user_data;
1805-
1806- g_object_unref (data->mechanism);
1807- g_strfreev (data->includes);
1808- g_strfreev (data->excludes);
1809- g_strfreev (data->actions);
1810- if (data->value)
1811- gconf_value_free (data->value);
1812- if (data->destroy)
1813- data->destroy (data->user_data);
1814- g_free (data);
1815-}
1816-
1817-static void
1818-do_copy_authorized (GConfDefaults *mechanism,
1819- DBusGMethodInvocation *context,
1820- gpointer user_data)
1821-{
1822- CopyData *data = user_data;
1823- GConfClient *source = NULL;
1824- GConfClient *dest = NULL;
1825- GConfChangeSet *changes = NULL;
1826- GConfEngine *engine;
1827- char *address = NULL;
1828- gint i;
1829- GError *error;
1830-
1831- error = NULL;
1832- engine = gconf_engine_get_local (data->dest_address, &error);
1833- if (error)
1834- goto cleanup;
1835-
1836- dest = gconf_client_get_for_engine (engine);
1837- gconf_engine_unref (engine);
1838-
1839- /* find the address to from the caller id */
1840- address = gconf_address_for_caller (data->mechanism, data->context, &error);
1841- if (error)
1842- goto cleanup;
1843-
1844- engine = gconf_engine_get_local (address, &error);
1845- if (error)
1846- goto cleanup;
1847-
1848- source = gconf_client_get_for_engine (engine);
1849- gconf_engine_unref (engine);
1850-
1851- changes = gconf_change_set_new ();
1852-
1853- if (data->value) {
1854- g_assert (data->includes[1] == NULL);
1855- g_assert (data->excludes == NULL);
1856-
1857- gconf_change_set_set (changes, data->includes[0], data->value);
1858- }
1859- else {
1860- /* recursively copy each include, leaving out the excludes */
1861- for (i = 0; data->includes[i]; i++) {
1862- if (gconf_client_dir_exists (source, data->includes[i], NULL))
1863- copy_tree (source, data->includes[i], changes, (const char **)data->excludes);
1864- else
1865- copy_entry (source, data->includes[i], changes, (const char **)data->excludes);
1866- }
1867- }
1868-
1869- gconf_client_commit_change_set (dest, changes, FALSE, &error);
1870- gconf_client_suggest_sync (dest, NULL);
1871-
1872- if (data->changeset_callback) {
1873- data->changeset_callback (data->mechanism, changes, data->user_data);
1874- }
1875-
1876-cleanup:
1877- g_free (address);
1878- if (changes)
1879- gconf_change_set_unref (changes);
1880- if (dest)
1881- g_object_unref (dest);
1882- if (source)
1883- g_object_unref (source);
1884-
1885- if (error) {
1886- throw_error (data->context,
1887- GCONF_DEFAULTS_ERROR_GENERAL,
1888- "%s", error->message);
1889- g_error_free (error);
1890- }
1891- else
1892- dbus_g_method_return (data->context);
1893-}
1894-
1895-typedef void (*ActionsReadyCallback) (GConfDefaults *mechanism,
1896- DBusGMethodInvocation *context,
1897- gchar **actions,
1898- AuthObtainedCallback auth_obtained_callback,
1899- gpointer data,
1900- GDestroyNotify destroy);
1901-
1902-typedef struct
1903-{
1904- GConfDefaults *mechanism;
1905- DBusGMethodInvocation *context;
1906- char **includes;
1907- const char *default_action;
1908- const char *annotation_key;
1909- ActionsReadyCallback actions_ready_callback;
1910- AuthObtainedCallback auth_obtained_callback;
1911- gpointer data;
1912- GDestroyNotify destroy;
1913-} ActionData;
1914-
1915-static void
1916-action_data_free (ActionData *data)
1917-{
1918- g_object_unref (data->mechanism);
1919- g_strfreev (data->includes);
1920- if (data->destroy)
1921- data->destroy (data->data);
1922- g_free (data);
1923-}
1924-
1925-static void
1926-actions_ready_cb (GObject *source,
1927- GAsyncResult *res,
1928- gpointer user_data)
1929-{
1930- ActionData *data = user_data;
1931- GList *action_descriptions;
1932- GError *error = NULL;
1933- int i;
1934- GHashTable *obtained;
1935- GHashTableIter iter;
1936- const gchar *action;
1937- gchar **actions;
1938- gpointer key, value;
1939-
1940- action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error);
1941-
1942- if (error) {
1943- throw_error (data->context,
1944- GCONF_DEFAULTS_ERROR_GENERAL,
1945- "Failed to get action descriptions: %s", error->message);
1946- g_error_free (error);
1947- action_data_free (data);
1948- stop_operation ();
1949- return;
1950- }
1951-
1952- obtained = g_hash_table_new (g_str_hash, g_str_equal);
1953-
1954- for (i = 0; data->includes[i]; i++) {
1955- action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]);
1956- if (action == NULL) {
1957- g_debug ("using default action '%s' for path '%s'",
1958- data->default_action, data->includes[i]);
1959- action = data->default_action;
1960- }
1961-
1962- g_hash_table_insert (obtained, (gpointer)action, (gpointer)action);
1963- }
1964- actions = g_new0 (char *, g_hash_table_size (obtained) + 1);
1965- g_hash_table_iter_init (&iter, obtained);
1966- i = 0;
1967- while (g_hash_table_iter_next (&iter, &key, &value)) {
1968- actions[i] = g_strdup ((char *)key);
1969- i++;
1970- }
1971- g_hash_table_destroy (obtained);
1972- g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL);
1973- g_list_free (action_descriptions);
1974-
1975- data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy);
1976-
1977- data->destroy = NULL;
1978- action_data_free (data);
1979-}
1980-
1981-static void
1982-do_copy (GConfDefaults *mechanism,
1983- gboolean mandatory,
1984- const gchar **includes,
1985- const gchar **excludes,
1986- GConfValue *value,
1987- DBusGMethodInvocation *context,
1988- ChangeSetCallback changeset_callback,
1989- gpointer user_data,
1990- GDestroyNotify destroy)
1991-{
1992- CopyData *cdata;
1993- ActionData *adata;
1994-
1995- start_operation ();
1996-
1997- cdata = g_new0 (CopyData, 1);
1998- cdata->mechanism = g_object_ref (mechanism);
1999- cdata->context = context;
2000- cdata->includes = g_strdupv ((gchar **)includes);
2001- cdata->excludes = g_strdupv ((gchar **)excludes);
2002- cdata->value = value;
2003- cdata->actions = NULL;
2004- cdata->changeset_callback = changeset_callback;
2005- cdata->user_data = user_data;
2006- cdata->destroy = destroy;
2007-
2008- adata = g_new0 (ActionData, 1);
2009- adata->mechanism = g_object_ref (mechanism);
2010- adata->context = context;
2011- adata->includes = g_strdupv ((gchar **)includes);
2012- adata->actions_ready_callback = check_polkit_for_actions;
2013- adata->auth_obtained_callback = do_copy_authorized;
2014- adata->data = cdata;
2015- adata->destroy = copy_data_free;
2016-
2017- /* check privileges for each include */
2018- if (mandatory) {
2019- adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
2020- adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
2021- cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory";
2022- }
2023- else {
2024- adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
2025- adata->default_action = "org.gnome.gconf.defaults.set-system";
2026- cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system";
2027- }
2028-
2029- polkit_authority_enumerate_actions (mechanism->priv->auth,
2030- NULL,
2031- actions_ready_cb,
2032- adata);
2033-}
2034-
2035-static void
2036-append_key (GConfChangeSet *cs,
2037- const gchar *key,
2038- GConfValue *value,
2039- gpointer user_data)
2040-{
2041- GPtrArray *keys = (GPtrArray *) user_data;
2042-
2043- g_ptr_array_add (keys, (gpointer) key);
2044-}
2045-
2046-static void
2047-set_system_changes (GConfDefaults *mechanism,
2048- GConfChangeSet *changes,
2049- gpointer data)
2050-{
2051- GPtrArray *keys;
2052-
2053- keys = g_ptr_array_new ();
2054- gconf_change_set_foreach (changes, append_key, keys);
2055- g_ptr_array_add (keys, NULL);
2056-
2057- g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
2058-
2059- g_ptr_array_free (keys, TRUE);
2060-}
2061-
2062-void
2063-gconf_defaults_set_system (GConfDefaults *mechanism,
2064- const char **includes,
2065- const char **excludes,
2066- DBusGMethodInvocation *context)
2067-{
2068- do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL);
2069-}
2070-
2071-void
2072-gconf_defaults_set_mandatory (GConfDefaults *mechanism,
2073- const char **includes,
2074- const char **excludes,
2075- DBusGMethodInvocation *context)
2076-{
2077- do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL);
2078-}
2079-
2080-static void
2081-unset_tree (GConfClient *dest,
2082- const char *path,
2083- GConfChangeSet *changes,
2084- const char **excludes)
2085-{
2086- GSList *list, *l;
2087- GConfEntry *entry;
2088-
2089- if (path_is_excluded (path, excludes))
2090- return;
2091-
2092- list = gconf_client_all_entries (dest, path, NULL);
2093- for (l = list; l; l = l->next) {
2094- entry = l->data;
2095- if (!path_is_excluded (entry->key, excludes))
2096- gconf_change_set_unset (changes, entry->key);
2097- }
2098- g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
2099- g_slist_free (list);
2100-
2101- list = gconf_client_all_dirs (dest, path, NULL);
2102- for (l = list; l; l = l->next)
2103- unset_tree (dest, (const char *)l->data, changes, excludes);
2104- g_slist_foreach (list, (GFunc)g_free, NULL);
2105- g_slist_free (list);
2106-}
2107-
2108-static void
2109-unset_entry (GConfClient *dest,
2110- const char *path,
2111- GConfChangeSet *changes,
2112- const char **excludes)
2113-{
2114- if (path_is_excluded (path, excludes))
2115- return;
2116-
2117- gconf_change_set_unset (changes, path);
2118-}
2119-
2120-static void
2121-unset_in_db (GConfDefaults *mechanism,
2122- const gchar *address,
2123- const gchar **includes,
2124- const gchar **excludes,
2125- GError **error)
2126-{
2127- GConfEngine *engine;
2128- GConfClient *dest = NULL;
2129- GConfChangeSet *changes = NULL;
2130- int i;
2131-
2132- engine = gconf_engine_get_local (address, error);
2133- if (*error)
2134- goto out;
2135-
2136- dest = gconf_client_get_for_engine (engine);
2137- gconf_engine_unref (engine);
2138-
2139- changes = gconf_change_set_new ();
2140-
2141- /* recursively copy each include, leaving out the excludes */
2142- for (i = 0; includes[i]; i++) {
2143- if (gconf_client_dir_exists (dest, includes[i], NULL))
2144- unset_tree (dest, includes[i], changes, excludes);
2145- else
2146- unset_entry (dest, includes[i], changes, excludes);
2147- }
2148-
2149- gconf_client_commit_change_set (dest, changes, TRUE, error);
2150- gconf_client_suggest_sync (dest, NULL);
2151-
2152-out:
2153- if (dest)
2154- g_object_unref (dest);
2155- if (changes)
2156- gconf_change_set_unref (changes);
2157-}
2158-
2159-typedef struct
2160-{
2161- GConfDefaults *mechanism;
2162- DBusGMethodInvocation *context;
2163- char **includes;
2164- char **excludes;
2165-} UnsetData;
2166-
2167-static void
2168-unset_data_free (gpointer user_data)
2169-{
2170- UnsetData *data = user_data;
2171-
2172- g_object_unref (data->mechanism);
2173- g_strfreev (data->includes);
2174- g_strfreev (data->excludes);
2175- g_free (data);
2176-}
2177-
2178-static void
2179-do_unset_authorized (GConfDefaults *mechanism,
2180- DBusGMethodInvocation *context,
2181- gpointer user_data)
2182-{
2183- UnsetData *data = user_data;
2184- GError *error;
2185-
2186- error = NULL;
2187- unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory",
2188- (const gchar **)data->includes,
2189- (const gchar **)data->excludes, &error);
2190-
2191- if (error) {
2192- throw_error (data->context,
2193- GCONF_DEFAULTS_ERROR,
2194- GCONF_DEFAULTS_ERROR_GENERAL,
2195- "%s", error->message);
2196- g_error_free (error);
2197- }
2198- else
2199- dbus_g_method_return (data->context);
2200-}
2201-
2202-void
2203-gconf_defaults_unset_mandatory (GConfDefaults *mechanism,
2204- const char **includes,
2205- const char **excludes,
2206- DBusGMethodInvocation *context)
2207-{
2208- UnsetData *udata;
2209- ActionData *adata;
2210-
2211- start_operation ();
2212-
2213- udata = g_new0 (UnsetData, 1);
2214- udata->mechanism = g_object_ref (mechanism);
2215- udata->context = context;
2216- udata->includes = g_strdupv ((gchar **)includes);
2217- udata->excludes = g_strdupv ((gchar **)excludes);
2218-
2219- adata = g_new0 (ActionData, 1);
2220- adata->mechanism = g_object_ref (mechanism);
2221- adata->context = context;
2222- adata->includes = g_strdupv ((gchar **)includes);
2223- adata->auth_obtained_callback = do_unset_authorized;
2224- adata->data = udata;
2225- adata->destroy = unset_data_free;
2226-
2227- adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
2228- adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
2229-
2230- polkit_authority_enumerate_actions (mechanism->priv->auth,
2231- NULL,
2232- actions_ready_cb,
2233- adata);
2234-}
2235-
2236-static void
2237-check_authorization_only_callback (PolkitAuthority *authority,
2238- GAsyncResult *res,
2239- gpointer user_data)
2240-{
2241- CheckAuthData *data = user_data;
2242- PolkitAuthorizationResult *result;
2243- GError *error;
2244- gboolean is_authorized;
2245-
2246- is_authorized = FALSE;
2247-
2248- error = NULL;
2249- result = polkit_authority_check_authorization_finish (authority,
2250- res,
2251- &error);
2252- if (error != NULL) {
2253- g_debug ("error checking action '%s'\n", error->message);
2254- throw_error (data->context,
2255- GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
2256- "Not Authorized: %s", error->message);
2257- g_error_free (error);
2258- goto out;
2259- }
2260- else {
2261- if (polkit_authorization_result_get_is_authorized (result)) {
2262- g_debug ("result for '%s': authorized\n",
2263- data->actions[data->id]);
2264- is_authorized = TRUE;
2265- }
2266- else if (polkit_authorization_result_get_is_challenge (result)) {
2267- g_debug ("result for '%s': challenge\n",
2268- data->actions[data->id]);
2269- is_authorized = TRUE;
2270- data->challenge = TRUE;
2271- }
2272- else {
2273- g_debug ("result for '%s': not authorized\n",
2274- data->actions[data->id]);
2275- is_authorized = FALSE;
2276- }
2277- }
2278-
2279- if (is_authorized) {
2280- data->id++;
2281- if (data->actions[data->id] == NULL) {
2282- gint result;
2283-
2284- result = data->challenge ? 1 : 2;
2285- g_debug ("return %d\n", result);
2286- dbus_g_method_return (data->context, result);
2287- }
2288- else {
2289- check_next_action (data);
2290- return; /* continue operation */
2291- }
2292- }
2293- else {
2294- g_debug ("return 0\n");
2295- dbus_g_method_return (data->context, 0);
2296- }
2297-
2298-out:
2299- check_auth_data_free (data);
2300- g_object_unref (result);
2301- stop_operation ();
2302-}
2303-
2304-static void
2305-check_permissions_only (GConfDefaults *mechanism,
2306- DBusGMethodInvocation *context,
2307- gchar **actions,
2308- AuthObtainedCallback auth_obtained_callback,
2309- gpointer user_data,
2310- GDestroyNotify destroy)
2311-{
2312- CheckAuthData *data;
2313-
2314- data = g_new0 (CheckAuthData, 1);
2315- data->mechanism = g_object_ref (mechanism);
2316- data->context = context;
2317- data->actions = actions;
2318- data->flags = 0;
2319- data->id = 0;
2320- data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback;
2321- data->auth_obtained_callback = NULL;
2322- data->user_data = NULL;
2323- data->destroy = NULL;
2324- data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
2325- data->challenge = FALSE;
2326-
2327- check_next_action (data);
2328-}
2329-
2330-static void
2331-do_check (GConfDefaults *mechanism,
2332- gboolean mandatory,
2333- const gchar **includes,
2334- DBusGMethodInvocation *context)
2335-{
2336- ActionData *adata;
2337-
2338- start_operation ();
2339-
2340- adata = g_new0 (ActionData, 1);
2341- adata->mechanism = g_object_ref (mechanism);
2342- adata->context = context;
2343- adata->includes = g_strdupv ((gchar **)includes);
2344- adata->actions_ready_callback = check_permissions_only;
2345- adata->auth_obtained_callback = NULL;
2346- adata->data = NULL;
2347- adata->destroy = NULL;
2348-
2349- if (mandatory) {
2350- adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
2351- adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
2352- }
2353- else {
2354- adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
2355- adata->default_action = "org.gnome.gconf.defaults.set-system";
2356- }
2357-
2358- polkit_authority_enumerate_actions (mechanism->priv->auth,
2359- NULL,
2360- actions_ready_cb,
2361- adata);
2362-}
2363-
2364-void
2365-gconf_defaults_can_set_system (GConfDefaults *mechanism,
2366- const char **includes,
2367- DBusGMethodInvocation *context)
2368-{
2369- do_check (mechanism, FALSE, includes, context);
2370-}
2371-
2372-void
2373-gconf_defaults_can_set_mandatory (GConfDefaults *mechanism,
2374- const char **includes,
2375- DBusGMethodInvocation *context)
2376-{
2377- do_check (mechanism, TRUE, includes, context);
2378-}
2379-
2380-void
2381-gconf_defaults_set_system_value (GConfDefaults *mechanism,
2382- const char *path,
2383- const char *value,
2384- DBusGMethodInvocation *context)
2385-{
2386- GConfValue *gvalue;
2387- const char *includes[] = { NULL, NULL };
2388-
2389- gvalue = gconf_value_decode (value);
2390- if (gvalue) {
2391- includes[0] = path;
2392- do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL);
2393- }
2394-}
2395-
2396-void
2397-gconf_defaults_set_mandatory_value (GConfDefaults *mechanism,
2398- const char *path,
2399- const char *value,
2400- DBusGMethodInvocation *context)
2401-{
2402- GConfValue *gvalue;
2403- const char *includes[] = { NULL, NULL };
2404-
2405- gvalue = gconf_value_decode (value);
2406- if (gvalue) {
2407- includes[0] = path;
2408- do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL);
2409- }
2410-}
2411-
2412
2413=== added directory '.pc/01_defaults_path.patch/gconf'
2414=== removed directory '.pc/01_defaults_path.patch/gconf'
2415=== added file '.pc/01_defaults_path.patch/gconf/gconfd.c'
2416--- .pc/01_defaults_path.patch/gconf/gconfd.c 1970-01-01 00:00:00 +0000
2417+++ .pc/01_defaults_path.patch/gconf/gconfd.c 2012-03-06 01:10:25 +0000
2418@@ -0,0 +1,2847 @@
2419+/* GConf
2420+ * Copyright (C) 1999, 2000 Red Hat Inc.
2421+ * Developed by Havoc Pennington, some code in here borrowed from
2422+ * gnome-name-server and libgnorba (Elliot Lee)
2423+ *
2424+ * This library is free software; you can redistribute it and/or
2425+ * modify it under the terms of the GNU Library General Public
2426+ * License as published by the Free Software Foundation; either
2427+ * version 2 of the License, or (at your option) any later version.
2428+ *
2429+ * This library is distributed in the hope that it will be useful,
2430+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2431+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2432+ * Library General Public License for more details.
2433+ *
2434+ * You should have received a copy of the GNU Library General Public
2435+ * License along with this library; if not, write to the
2436+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2437+ * Boston, MA 02110-1301, USA.
2438+ */
2439+
2440+
2441+/*
2442+ * This is the per-user configuration daemon.
2443+ * (has debug crap in it now)
2444+ */
2445+
2446+#include <config.h>
2447+
2448+#include "gconf-internals.h"
2449+#include "gconf-sources.h"
2450+#include "gconf-listeners.h"
2451+#include "gconf-locale.h"
2452+#include "gconf-schema.h"
2453+#include "gconf.h"
2454+#include "gconfd.h"
2455+#include "gconf-database.h"
2456+
2457+#ifdef HAVE_DBUS
2458+#include "gconf-database-dbus.h"
2459+#include "gconfd-dbus.h"
2460+#endif
2461+
2462+#ifdef HAVE_CORBA
2463+#include <orbit/orbit.h>
2464+
2465+#include "GConfX.h"
2466+#endif
2467+
2468+#include <sys/types.h>
2469+#include <stdio.h>
2470+#include <stdlib.h>
2471+#include <string.h>
2472+#include <signal.h>
2473+#include <unistd.h>
2474+#include <sys/stat.h>
2475+#include <fcntl.h>
2476+#include <errno.h>
2477+#include <ctype.h>
2478+#include <time.h>
2479+#ifdef HAVE_SYS_WAIT_H
2480+#include <sys/wait.h>
2481+#endif
2482+#include <locale.h>
2483+
2484+#include <dbus/dbus-glib-lowlevel.h>
2485+
2486+#ifdef G_OS_WIN32
2487+#include <io.h>
2488+#include <conio.h>
2489+#define _WIN32_WINNT 0x0500
2490+#include <windows.h>
2491+
2492+static int
2493+fsync (int fd)
2494+{
2495+ HANDLE h = (HANDLE) _get_osfhandle (fd);
2496+ DWORD err;
2497+
2498+ if (h == INVALID_HANDLE_VALUE)
2499+ {
2500+ errno = EBADF;
2501+ return -1;
2502+ }
2503+
2504+ if (!FlushFileBuffers (h))
2505+ {
2506+ err = GetLastError ();
2507+ switch (err)
2508+ {
2509+ case ERROR_INVALID_HANDLE:
2510+ errno = EINVAL;
2511+ break;
2512+
2513+ default:
2514+ errno = EIO;
2515+ }
2516+ return -1;
2517+ }
2518+
2519+ return 0;
2520+}
2521+#endif
2522+
2523+/* This makes hash table safer when debugging */
2524+#ifndef GCONF_ENABLE_DEBUG
2525+#define safe_g_hash_table_insert g_hash_table_insert
2526+#else
2527+static void
2528+safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
2529+{
2530+ gpointer oldkey = NULL, oldval = NULL;
2531+
2532+ if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
2533+ {
2534+ gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
2535+ (gchar*) key);
2536+ return;
2537+ }
2538+ else
2539+ {
2540+ g_hash_table_insert(ht, key, value);
2541+ }
2542+}
2543+#endif
2544+
2545+/*
2546+ * Declarations
2547+ */
2548+
2549+static void gconf_main (void);
2550+static gboolean gconf_main_is_running (void);
2551+
2552+#ifdef HAVE_CORBA
2553+static void logfile_save (void);
2554+static void logfile_read (void);
2555+static void log_client_add (const ConfigListener client);
2556+static void log_client_remove (const ConfigListener client);
2557+
2558+static void add_client (const ConfigListener client);
2559+static void remove_client (const ConfigListener client);
2560+static GSList *list_clients (void);
2561+static void log_clients_to_string (GString *str);
2562+static void drop_old_clients (void);
2563+static guint client_count (void);
2564+#endif
2565+
2566+static void enter_shutdown (void);
2567+
2568+static void init_databases (void);
2569+static void shutdown_databases (void);
2570+#ifdef HAVE_DBUS
2571+static void reload_databases (void);
2572+#endif
2573+static void set_default_database (GConfDatabase* db);
2574+static void register_database (GConfDatabase* db);
2575+static void unregister_database (GConfDatabase* db);
2576+static GConfDatabase* lookup_database (GSList *addresses);
2577+static void drop_old_databases (void);
2578+static gboolean no_databases_in_use (void);
2579+
2580+/*
2581+ * Flag indicating that we are shutting down, so return errors
2582+ * on any attempted operation. We do this instead of unregistering with
2583+ * OAF or deactivating the server object, because we want to avoid
2584+ * another gconfd starting up before we finish shutting down.
2585+ */
2586+
2587+static gboolean in_shutdown = FALSE;
2588+
2589+/*
2590+ * Flag indicating we received a SIGHUP and we should reaload
2591+ * all sources during the next periodic_cleanup()
2592+ */
2593+static gboolean need_db_reload = FALSE;
2594+
2595+#ifdef HAVE_CORBA
2596+/*
2597+ * CORBA goo
2598+ */
2599+
2600+static ConfigServer2 server = CORBA_OBJECT_NIL;
2601+static PortableServer_POA the_poa;
2602+static GConfLock *daemon_lock = NULL;
2603+
2604+static ConfigDatabase
2605+gconfd_get_default_database(PortableServer_Servant servant,
2606+ CORBA_Environment* ev);
2607+
2608+static ConfigDatabase
2609+gconfd_get_database(PortableServer_Servant servant,
2610+ const CORBA_char* address,
2611+ CORBA_Environment* ev);
2612+
2613+static ConfigDatabase
2614+gconfd_get_database_for_addresses (PortableServer_Servant servant,
2615+ const ConfigServer2_AddressList *addresses,
2616+ CORBA_Environment *ev);
2617+
2618+static void
2619+gconfd_add_client (PortableServer_Servant servant,
2620+ const ConfigListener client,
2621+ CORBA_Environment *ev);
2622+
2623+static void
2624+gconfd_remove_client (PortableServer_Servant servant,
2625+ const ConfigListener client,
2626+ CORBA_Environment *ev);
2627+
2628+static CORBA_long
2629+gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev);
2630+
2631+static void
2632+gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev);
2633+
2634+static PortableServer_ServantBase__epv base_epv = {
2635+ NULL,
2636+ NULL,
2637+ NULL
2638+};
2639+
2640+static POA_ConfigServer__epv server_epv = {
2641+ NULL,
2642+ gconfd_get_default_database,
2643+ gconfd_get_database,
2644+ gconfd_add_client,
2645+ gconfd_remove_client,
2646+ gconfd_ping,
2647+ gconfd_shutdown
2648+};
2649+
2650+static POA_ConfigServer2__epv server2_epv = {
2651+ NULL,
2652+ gconfd_get_database_for_addresses
2653+};
2654+
2655+static POA_ConfigServer2__vepv poa_server_vepv = { &base_epv, &server_epv, &server2_epv };
2656+static POA_ConfigServer2 poa_server_servant = { NULL, &poa_server_vepv };
2657+
2658+static ConfigDatabase
2659+gconfd_get_default_database(PortableServer_Servant servant,
2660+ CORBA_Environment* ev)
2661+{
2662+ GConfDatabase *db;
2663+
2664+ if (gconfd_check_in_shutdown (ev))
2665+ return CORBA_OBJECT_NIL;
2666+
2667+ db = lookup_database (NULL);
2668+
2669+ if (db)
2670+ return CORBA_Object_duplicate (db->objref, ev);
2671+ else
2672+ return CORBA_OBJECT_NIL;
2673+}
2674+
2675+static ConfigDatabase
2676+gconfd_get_database(PortableServer_Servant servant,
2677+ const CORBA_char* address,
2678+ CORBA_Environment* ev)
2679+{
2680+ GConfDatabase *db;
2681+ GSList *addresses;
2682+ GError* error = NULL;
2683+
2684+ if (gconfd_check_in_shutdown (ev))
2685+ return CORBA_OBJECT_NIL;
2686+
2687+ addresses = g_slist_append (NULL, (char *) address);
2688+ db = gconfd_obtain_database (addresses, &error);
2689+ g_slist_free (addresses);
2690+
2691+ if (db != NULL)
2692+ return CORBA_Object_duplicate (db->objref, ev);
2693+
2694+ gconf_set_exception (&error, ev);
2695+
2696+ return CORBA_OBJECT_NIL;
2697+}
2698+
2699+static ConfigDatabase
2700+gconfd_get_database_for_addresses (PortableServer_Servant servant,
2701+ const ConfigServer2_AddressList *seq,
2702+ CORBA_Environment *ev)
2703+{
2704+ GConfDatabase *db;
2705+ GSList *addresses = NULL;
2706+ GError *error = NULL;
2707+ int i;
2708+
2709+ if (gconfd_check_in_shutdown (ev))
2710+ return CORBA_OBJECT_NIL;
2711+
2712+ i = 0;
2713+ while (i < seq->_length)
2714+ addresses = g_slist_append (addresses, seq->_buffer [i++]);
2715+
2716+ db = gconfd_obtain_database (addresses, &error);
2717+
2718+ g_slist_free (addresses);
2719+
2720+ if (db != NULL)
2721+ return CORBA_Object_duplicate (db->objref, ev);
2722+
2723+ gconf_set_exception (&error, ev);
2724+
2725+ return CORBA_OBJECT_NIL;
2726+}
2727+
2728+static void
2729+gconfd_add_client (PortableServer_Servant servant,
2730+ const ConfigListener client,
2731+ CORBA_Environment *ev)
2732+{
2733+ if (gconfd_check_in_shutdown (ev))
2734+ return;
2735+
2736+ add_client (client);
2737+}
2738+
2739+static void
2740+gconfd_remove_client (PortableServer_Servant servant,
2741+ const ConfigListener client,
2742+ CORBA_Environment *ev)
2743+{
2744+ if (gconfd_check_in_shutdown (ev))
2745+ return;
2746+
2747+ remove_client (client);
2748+}
2749+
2750+static CORBA_long
2751+gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev)
2752+{
2753+ if (gconfd_check_in_shutdown (ev))
2754+ return 0;
2755+
2756+ return getpid();
2757+}
2758+
2759+static void
2760+gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev)
2761+{
2762+ if (gconfd_check_in_shutdown (ev))
2763+ return;
2764+
2765+ gconf_log(GCL_DEBUG, _("Shutdown request received"));
2766+
2767+ gconfd_main_quit();
2768+}
2769+#endif /* HAVE_CORBA */
2770+
2771+/*
2772+ * Main code
2773+ */
2774+
2775+/* This needs to be called before we register with OAF
2776+ */
2777+static GConfSources *
2778+gconf_server_get_default_sources(void)
2779+{
2780+ GSList* addresses;
2781+ GList* tmp;
2782+ gboolean have_writable = FALSE;
2783+ gchar* conffile;
2784+ GConfSources* sources = NULL;
2785+ GError* error = NULL;
2786+
2787+ conffile = g_strconcat(GCONF_CONFDIR, "/path", NULL);
2788+
2789+ addresses = gconf_load_source_path(conffile, NULL);
2790+
2791+ g_free(conffile);
2792+
2793+#ifdef GCONF_ENABLE_DEBUG
2794+ /* -- Debug only */
2795+
2796+ if (addresses == NULL)
2797+ {
2798+ gconf_log(GCL_DEBUG, _("gconfd compiled with debugging; trying to load gconf.path from the source directory"));
2799+ conffile = g_strconcat(GCONF_SRCDIR, "/gconf/gconf.path", NULL);
2800+ addresses = gconf_load_source_path(conffile, NULL);
2801+ g_free(conffile);
2802+ }
2803+
2804+ /* -- End of Debug Only */
2805+#endif
2806+
2807+ if (addresses == NULL)
2808+ {
2809+#ifndef G_OS_WIN32
2810+ const char *home = g_get_home_dir ();
2811+#else
2812+ const char *home = _gconf_win32_get_home_dir ();
2813+#endif
2814+
2815+ /* Try using the default address xml:readwrite:$(HOME)/.gconf */
2816+ addresses = g_slist_append(addresses, g_strconcat("xml:readwrite:", home, "/.gconf", NULL));
2817+
2818+ gconf_log(GCL_DEBUG, _("No configuration files found. Trying to use the default configuration source `%s'"), (char *)addresses->data);
2819+ }
2820+
2821+ if (addresses == NULL)
2822+ {
2823+ /* We want to stay alive but do nothing, because otherwise every
2824+ request would result in another failed gconfd being spawned.
2825+ */
2826+ gconf_log(GCL_ERR, _("No configuration sources in the source path. Configuration won't be saved; edit %s%s"), GCONF_CONFDIR, "/path");
2827+ /* don't request error since there aren't any addresses */
2828+ sources = gconf_sources_new_from_addresses(NULL, NULL);
2829+
2830+ return sources;
2831+ }
2832+ else
2833+ {
2834+ sources = gconf_sources_new_from_addresses(addresses, &error);
2835+
2836+ if (error != NULL)
2837+ {
2838+ gconf_log(GCL_ERR, _("Error loading some configuration sources: %s"),
2839+ error->message);
2840+
2841+ g_error_free(error);
2842+ error = NULL;
2843+ }
2844+
2845+ gconf_address_list_free(addresses);
2846+
2847+ g_assert(sources != NULL);
2848+
2849+ if (sources->sources == NULL)
2850+ gconf_log(GCL_ERR, _("No configuration source addresses successfully resolved. Can't load or store configuration data"));
2851+
2852+ tmp = sources->sources;
2853+
2854+ while (tmp != NULL)
2855+ {
2856+ if (((GConfSource*)tmp->data)->flags & GCONF_SOURCE_ALL_WRITEABLE)
2857+ {
2858+ have_writable = TRUE;
2859+ break;
2860+ }
2861+
2862+ tmp = g_list_next(tmp);
2863+ }
2864+
2865+ /* In this case, some sources may still return TRUE from their writable() function */
2866+ if (!have_writable)
2867+ gconf_log(GCL_WARNING, _("No writable configuration sources successfully resolved. May be unable to save some configuration changes"));
2868+
2869+ return sources;
2870+ }
2871+}
2872+
2873+static void
2874+gconf_server_load_sources(void)
2875+{
2876+ GConfSources* sources;
2877+
2878+ sources = gconf_server_get_default_sources();
2879+
2880+ /* Install the sources as the default database */
2881+ set_default_database (gconf_database_new(sources));
2882+}
2883+
2884+/*
2885+ * Signal handlers should not log debug messages as this code is non-reentrant.
2886+ * Please avoid calling gconf_log in this function.
2887+ */
2888+static void
2889+signal_handler (int signo)
2890+{
2891+ static gint in_fatal = 0;
2892+
2893+ /* avoid loops */
2894+ if (in_fatal > 0)
2895+ return;
2896+
2897+ ++in_fatal;
2898+
2899+ switch (signo) {
2900+ case SIGFPE:
2901+#ifdef SIGPIPE
2902+ case SIGPIPE:
2903+#endif
2904+ /* Go ahead and try the full cleanup on these,
2905+ * though it could well not work out very well.
2906+ */
2907+ enter_shutdown ();
2908+
2909+ /* let the fatal signals interrupt us */
2910+ --in_fatal;
2911+
2912+ if (gconf_main_is_running ())
2913+ gconfd_main_quit ();
2914+
2915+ break;
2916+
2917+ case SIGTERM:
2918+ enter_shutdown ();
2919+
2920+ /* let the fatal signals interrupt us */
2921+ --in_fatal;
2922+
2923+ if (gconf_main_is_running ())
2924+ gconfd_main_quit ();
2925+ break;
2926+
2927+#ifdef SIGHUP
2928+ case SIGHUP:
2929+ --in_fatal;
2930+
2931+ /* reload sources during next periodic_cleanup() */
2932+ need_db_reload = TRUE;
2933+ break;
2934+#endif
2935+
2936+#ifdef SIGUSR1
2937+ case SIGUSR1:
2938+ --in_fatal;
2939+
2940+ /* it'd be nice to log a message here but it's not very safe, so */
2941+ gconf_log_debug_messages = !gconf_log_debug_messages;
2942+ break;
2943+#endif
2944+
2945+ default:
2946+#ifndef HAVE_SIGACTION
2947+ signal (signo, signal_handler);
2948+#endif
2949+ break;
2950+ }
2951+}
2952+
2953+#ifdef HAVE_CORBA
2954+PortableServer_POA
2955+gconf_get_poa (void)
2956+{
2957+ return the_poa;
2958+}
2959+#endif
2960+
2961+#ifdef HAVE_CORBA
2962+static const char *
2963+get_introspection_xml (void)
2964+{
2965+ return "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
2966+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
2967+ "<node>\n"
2968+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
2969+ " <method name=\"Introspect\">\n"
2970+ " <arg name=\"introspection_xml\" direction=\"out\" type=\"s\"/>\n"
2971+ " </method>\n"
2972+ " </interface>\n"
2973+ " <interface name=\"org.gnome.GConf\">\n"
2974+ " <method name=\"GetIOR\">\n"
2975+ " <arg name=\"ior\" direction=\"out\" type=\"s\"/>\n"
2976+ " </method>\n"
2977+ " </interface>\n"
2978+ "</node>\n";
2979+}
2980+
2981+static DBusHandlerResult
2982+bus_message_handler (DBusConnection *connection,
2983+ DBusMessage *message,
2984+ void *user_data)
2985+{
2986+ DBusMessage *reply;
2987+
2988+ reply = NULL;
2989+
2990+ if (dbus_message_is_signal (message,
2991+ DBUS_INTERFACE_LOCAL,
2992+ "Disconnected"))
2993+ {
2994+ gconfd_main_quit ();
2995+ return DBUS_HANDLER_RESULT_HANDLED;
2996+ }
2997+ else if (dbus_message_is_method_call (message,
2998+ "org.freedesktop.DBus.Introspectable",
2999+ "Introspect"))
3000+ {
3001+ const char *introspection_xml;
3002+
3003+ introspection_xml = get_introspection_xml ();
3004+
3005+ reply = dbus_message_new_method_return (message);
3006+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &introspection_xml,
3007+ DBUS_TYPE_INVALID);
3008+
3009+ }
3010+ else if (dbus_message_is_method_call (message,
3011+ "org.gnome.GConf",
3012+ "GetIOR"))
3013+ {
3014+ const char *ior;
3015+
3016+ ior = gconf_get_daemon_ior ();
3017+
3018+ reply = dbus_message_new_method_return (message);
3019+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &ior, DBUS_TYPE_INVALID);
3020+ }
3021+
3022+ if (reply != NULL)
3023+ {
3024+ dbus_connection_send (connection, reply, NULL);
3025+ dbus_message_unref (reply);
3026+ return DBUS_HANDLER_RESULT_HANDLED;
3027+ }
3028+
3029+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3030+}
3031+
3032+static DBusConnection *
3033+get_on_d_bus (void)
3034+{
3035+ DBusConnection *connection;
3036+ DBusError bus_error;
3037+ int result;
3038+
3039+ dbus_error_init (&bus_error);
3040+ connection = dbus_bus_get (DBUS_BUS_SESSION, &bus_error);
3041+
3042+ if (dbus_error_is_set (&bus_error))
3043+ {
3044+ gconf_log (GCL_ERR, _("Could not connect to session bus: %s"), bus_error.message);
3045+ dbus_error_free (&bus_error);
3046+ return NULL;
3047+ }
3048+
3049+ dbus_connection_setup_with_g_main (connection, NULL);
3050+
3051+ if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
3052+ bus_message_handler, NULL, NULL))
3053+ {
3054+ dbus_connection_unref (connection);
3055+ return NULL;
3056+ }
3057+
3058+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
3059+
3060+ result = dbus_bus_request_name (connection, "org.gnome.GConf",
3061+ 0, &bus_error);
3062+
3063+ if (dbus_error_is_set (&bus_error))
3064+ {
3065+ gconf_log (GCL_WARNING,
3066+ _("Failed to get bus name for daemon, exiting: %s"),
3067+ bus_error.message);
3068+ dbus_error_free (&bus_error);
3069+ }
3070+
3071+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
3072+ {
3073+ dbus_connection_unref (connection);
3074+ return NULL;
3075+ }
3076+
3077+ return connection;
3078+}
3079+#endif
3080+
3081+#ifdef ENABLE_DEFAULTS_SERVICE
3082+/* listen on system bus for defaults changes */
3083+
3084+static DBusHandlerResult
3085+system_bus_message_handler (DBusConnection *connection,
3086+ DBusMessage *message,
3087+ void *user_data)
3088+{
3089+ DBusMessage *reply;
3090+
3091+ reply = NULL;
3092+
3093+ if (dbus_message_is_signal (message,
3094+ "org.gnome.GConf.Defaults",
3095+ "SystemSet"))
3096+ {
3097+ DBusError bus_error;
3098+ char **keys;
3099+ int n_keys;
3100+
3101+ dbus_error_init (&bus_error);
3102+ if (dbus_message_get_args (message, &bus_error,
3103+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys,
3104+ DBUS_TYPE_INVALID))
3105+ {
3106+ char **key;
3107+ GConfSources *system_sources;
3108+ GSList addresses;
3109+
3110+ gconf_log (GCL_DEBUG, "System defaults changed. Notifying.");
3111+
3112+ addresses.data = "xml:merged:" GCONF_ETCDIR "/gconf.xml.system";
3113+ addresses.next = NULL;
3114+ system_sources = gconf_sources_new_from_addresses (&addresses, NULL);
3115+
3116+ gconfd_clear_cache_for_sources (system_sources);
3117+
3118+ for (key = keys; *key; key++)
3119+ gconfd_notify_other_listeners (NULL, system_sources, *key);
3120+
3121+ gconf_sources_free (system_sources);
3122+
3123+ dbus_free_string_array (keys);
3124+ }
3125+ else
3126+ {
3127+ gconf_log (GCL_DEBUG, "SystemSet signal received, but error getting message: %s", bus_error.message);
3128+ }
3129+ dbus_error_free (&bus_error);
3130+
3131+ return DBUS_HANDLER_RESULT_HANDLED;
3132+ }
3133+
3134+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3135+}
3136+
3137+static DBusConnection *
3138+get_on_system_bus (void)
3139+{
3140+ DBusConnection *connection;
3141+ DBusError bus_error;
3142+
3143+ dbus_error_init (&bus_error);
3144+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &bus_error);
3145+
3146+ if (dbus_error_is_set (&bus_error))
3147+ {
3148+ gconf_log (GCL_ERR, _("Could not connect to system bus: %s"), bus_error.message);
3149+ dbus_error_free (&bus_error);
3150+ return NULL;
3151+ }
3152+
3153+ dbus_connection_setup_with_g_main (connection, NULL);
3154+
3155+ dbus_bus_add_match (connection, "type='signal',interface='org.gnome.GConf.Defaults'", &bus_error);
3156+ dbus_connection_flush(connection);
3157+ if (dbus_error_is_set (&bus_error))
3158+ {
3159+ gconf_log (GCL_DEBUG, "Failed to add signal match to system bus: %s", bus_error.message);
3160+ dbus_connection_unref (connection);
3161+ return NULL;
3162+ }
3163+
3164+ if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
3165+ system_bus_message_handler, NULL, NULL))
3166+ {
3167+ gconf_log (GCL_DEBUG, "Failed to add message filter to system bus.");
3168+ dbus_connection_unref (connection);
3169+ return NULL;
3170+ }
3171+
3172+ return connection;
3173+}
3174+#endif /* ENABLE_DEFAULTS_SERVICE */
3175+
3176+#ifdef G_OS_WIN32
3177+
3178+static void
3179+wait_console_window (void)
3180+{
3181+ SetConsoleTitle ("GConf daemon exiting. Type any character to close this window.");
3182+ printf ("\n"
3183+ "(GConf daemon exiting. Type any character to close this window)\n");
3184+ _getch ();
3185+}
3186+
3187+#endif
3188+
3189+int
3190+main(int argc, char** argv)
3191+{
3192+#ifdef HAVE_SIGACTION
3193+ struct sigaction act;
3194+ sigset_t empty_mask;
3195+ sigset_t full_mask;
3196+#endif
3197+
3198+#ifdef HAVE_CORBA
3199+ CORBA_Environment ev;
3200+ CORBA_ORB orb;
3201+ gchar* ior;
3202+ DBusConnection *connection;
3203+#endif
3204+
3205+ int dev_null_fd;
3206+ int exit_code = 0;
3207+ int write_byte_fd;
3208+
3209+ _gconf_init_i18n ();
3210+ setlocale (LC_ALL, "");
3211+ textdomain (GETTEXT_PACKAGE);
3212+
3213+ /* Now this is an argument parser */
3214+ if (argc > 1)
3215+ write_byte_fd = atoi (argv[1]);
3216+ else
3217+ write_byte_fd = -1;
3218+
3219+ /* This is so we don't prevent unmounting of devices. We divert
3220+ * all messages to syslog
3221+ */
3222+ if (g_chdir ("/") < 0)
3223+ {
3224+ g_printerr ("Could not change to root directory: %s\n",
3225+ g_strerror (errno));
3226+ exit (1);
3227+ }
3228+
3229+ if (!g_getenv ("GCONF_DEBUG_OUTPUT"))
3230+ {
3231+ dev_null_fd = open (DEV_NULL, O_RDWR);
3232+ if (dev_null_fd >= 0)
3233+ {
3234+ dup2 (dev_null_fd, 0);
3235+ dup2 (dev_null_fd, 1);
3236+ dup2 (dev_null_fd, 2);
3237+ }
3238+ }
3239+ else
3240+ {
3241+ gconf_log_debug_messages = TRUE;
3242+#ifdef G_OS_WIN32
3243+ if (fileno (stdout) != -1 &&
3244+ _get_osfhandle (fileno (stdout)) != -1)
3245+ {
3246+ /* stdout is fine, presumably redirected to a file or pipe */
3247+ }
3248+ else
3249+ {
3250+ int allocated_new_console = FALSE;
3251+
3252+ typedef BOOL (* WINAPI AttachConsole_t) (DWORD);
3253+
3254+ AttachConsole_t p_AttachConsole =
3255+ (AttachConsole_t) GetProcAddress (GetModuleHandle ("kernel32.dll"), "AttachConsole");
3256+
3257+ if (p_AttachConsole != NULL)
3258+ {
3259+ if (!AttachConsole (ATTACH_PARENT_PROCESS))
3260+ {
3261+ if (AllocConsole ())
3262+ allocated_new_console = TRUE;
3263+ }
3264+
3265+ freopen ("CONOUT$", "w", stdout);
3266+ dup2 (fileno (stdout), 1);
3267+ freopen ("CONOUT$", "w", stderr);
3268+ dup2 (fileno (stderr), 2);
3269+
3270+ if (allocated_new_console)
3271+ {
3272+ SetConsoleTitle ("GConf daemon debugging output. You can minimize this window, but don't close it.");
3273+ printf ("You asked for debugging output by setting the GCONF_DEBUG_OUTPUT\n"
3274+ "environment variable, so here it is.\n"
3275+ "\n");
3276+ atexit (wait_console_window);
3277+ }
3278+ }
3279+ }
3280+#endif
3281+ }
3282+
3283+ umask (022);
3284+
3285+ gconf_set_daemon_mode(TRUE);
3286+
3287+ gconf_log (GCL_DEBUG, _("starting (version %s), pid %u user '%s'"),
3288+ VERSION, (guint)getpid(), g_get_user_name());
3289+
3290+#ifdef GCONF_ENABLE_DEBUG
3291+ gconf_log (GCL_DEBUG, "GConf was built with debugging features enabled");
3292+#endif
3293+
3294+ /* Session setup */
3295+#ifdef HAVE_SIGACTION
3296+ sigfillset (&full_mask);
3297+ sigprocmask (SIG_UNBLOCK, &full_mask, NULL);
3298+
3299+ sigemptyset (&empty_mask);
3300+ act.sa_handler = signal_handler;
3301+ act.sa_mask = empty_mask;
3302+ act.sa_flags = 0;
3303+ sigaction (SIGTERM, &act, NULL);
3304+ sigaction (SIGHUP, &act, NULL);
3305+ sigaction (SIGUSR1, &act, NULL);
3306+
3307+ act.sa_handler = SIG_IGN;
3308+ sigaction (SIGINT, &act, NULL);
3309+#else
3310+ signal (SIGTERM, signal_handler);
3311+#ifdef SIGHUP
3312+ signal (SIGHUP, signal_handler);
3313+#endif
3314+#ifdef SIGUSR1
3315+ signal (SIGUSR1, signal_handler);
3316+#endif
3317+#endif
3318+
3319+#ifdef HAVE_CORBA
3320+ CORBA_exception_init(&ev);
3321+#endif
3322+
3323+ init_databases ();
3324+
3325+#ifdef HAVE_DBUS
3326+ if (!gconfd_dbus_init ())
3327+ return 1;
3328+#endif
3329+
3330+#ifdef HAVE_CORBA
3331+ orb = gconf_orb_get ();
3332+
3333+ POA_ConfigServer2__init (&poa_server_servant, &ev);
3334+
3335+ the_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
3336+ PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(the_poa, &ev), &ev);
3337+
3338+ server = PortableServer_POA_servant_to_reference(the_poa,
3339+ &poa_server_servant,
3340+ &ev);
3341+ if (CORBA_Object_is_nil(server, &ev))
3342+ {
3343+ gconf_log(GCL_ERR, _("Failed to get object reference for ConfigServer"));
3344+ return 1;
3345+ }
3346+
3347+ /* Needs to be done before loading sources */
3348+ ior = CORBA_ORB_object_to_string (orb, server, &ev);
3349+ gconf_set_daemon_ior (ior);
3350+ CORBA_free (ior);
3351+
3352+ connection = get_on_d_bus ();
3353+
3354+ if (connection != NULL)
3355+ {
3356+ /* This loads backends and so on. It needs to be done before
3357+ * we can handle any requests, so before we hit the
3358+ * main loop. if daemon_lock == NULL we won't hit the
3359+ * main loop.
3360+ */
3361+ gconf_server_load_sources ();
3362+ }
3363+#endif
3364+
3365+#ifdef HAVE_DBUS
3366+ gconf_server_load_sources ();
3367+#endif
3368+
3369+#ifdef HAVE_CORBA
3370+ /* notify caller that we're done either getting the lock
3371+ * or not getting it
3372+ */
3373+ if (write_byte_fd >= 0)
3374+ {
3375+ char buf[1] = { 'g' };
3376+ if (write (write_byte_fd, buf, 1) != 1)
3377+ {
3378+ gconf_log (GCL_ERR, _("Failed to write byte to pipe file descriptor %d so client program may hang: %s"), write_byte_fd, g_strerror (errno));
3379+ }
3380+
3381+ close (write_byte_fd);
3382+ }
3383+
3384+ if (connection == NULL)
3385+ {
3386+ enter_shutdown ();
3387+ shutdown_databases ();
3388+
3389+ return 1;
3390+ }
3391+
3392+ /* Read saved log file, if any */
3393+ logfile_read ();
3394+#endif
3395+
3396+#ifdef ENABLE_DEFAULTS_SERVICE
3397+ get_on_system_bus ();
3398+#endif
3399+
3400+ gconf_main ();
3401+
3402+ if (in_shutdown)
3403+ exit_code = 1; /* means someone already called enter_shutdown() */
3404+
3405+ /* This starts bouncing all incoming requests (and we aren't running
3406+ * the main loop anyway, so they won't get processed)
3407+ */
3408+ enter_shutdown ();
3409+
3410+#ifdef HAVE_CORBA
3411+ /* Save current state in logfile (may compress the logfile a good
3412+ * bit)
3413+ */
3414+ logfile_save ();
3415+#endif
3416+
3417+ shutdown_databases ();
3418+
3419+ gconfd_locale_cache_drop ();
3420+
3421+#ifdef HAVE_CORBA
3422+ if (daemon_lock)
3423+ {
3424+ GError *err;
3425+
3426+ err = NULL;
3427+ gconf_release_lock (daemon_lock, &err);
3428+ if (err != NULL)
3429+ {
3430+ gconf_log (GCL_WARNING, _("Error releasing lockfile: %s"),
3431+ err->message);
3432+ g_error_free (err);
3433+ }
3434+ }
3435+
3436+ daemon_lock = NULL;
3437+#endif
3438+
3439+ gconf_log (GCL_DEBUG, _("Exiting"));
3440+
3441+ return exit_code;
3442+}
3443+
3444+/*
3445+ * Main loop
3446+ */
3447+
3448+static GSList* main_loops = NULL;
3449+static guint timeout_id = 0;
3450+static gboolean need_log_cleanup = FALSE;
3451+
3452+static gboolean
3453+periodic_cleanup_timeout(gpointer data)
3454+{
3455+ if (need_db_reload)
3456+ {
3457+ gconf_log (GCL_INFO, _("SIGHUP received, reloading all databases"));
3458+
3459+ need_db_reload = FALSE;
3460+#ifdef HAVE_CORBA
3461+ logfile_save ();
3462+ shutdown_databases ();
3463+ init_databases ();
3464+ gconf_server_load_sources ();
3465+ logfile_read ();
3466+#endif
3467+#ifdef HAVE_DBUS
3468+ reload_databases ();
3469+#endif
3470+ }
3471+
3472+ gconf_log (GCL_DEBUG, "Performing periodic cleanup, expiring cache cruft");
3473+
3474+#ifdef HAVE_CORBA
3475+ drop_old_clients ();
3476+#endif
3477+ drop_old_databases ();
3478+
3479+#ifdef HAVE_DBUS
3480+ if (no_databases_in_use () && gconfd_dbus_client_count () == 0)
3481+#else
3482+ if (no_databases_in_use () && client_count () == 0)
3483+#endif
3484+ {
3485+ gconf_log (GCL_INFO, _("GConf server is not in use, shutting down."));
3486+ gconfd_main_quit ();
3487+ return FALSE;
3488+ }
3489+
3490+ /* expire old locale cache entries */
3491+ gconfd_locale_cache_expire ();
3492+
3493+#ifdef HAVE_CORBA
3494+ if (!need_log_cleanup)
3495+ {
3496+ gconf_log (GCL_DEBUG, "No log file saving needed in periodic cleanup handler");
3497+ return TRUE;
3498+ }
3499+
3500+ /* Compress the running state file */
3501+ logfile_save ();
3502+#endif
3503+
3504+ need_log_cleanup = FALSE;
3505+
3506+ return TRUE;
3507+}
3508+
3509+void
3510+gconfd_need_log_cleanup (void)
3511+{
3512+ need_log_cleanup = TRUE;
3513+}
3514+
3515+static void
3516+gconf_main(void)
3517+{
3518+ GMainLoop* loop;
3519+
3520+ loop = g_main_loop_new (NULL, TRUE);
3521+
3522+ if (main_loops == NULL)
3523+ {
3524+ gulong timeout_len = 60*0.5; /* 60 s/min * .5 min */
3525+
3526+ g_assert(timeout_id == 0);
3527+ timeout_id = g_timeout_add_seconds (timeout_len,
3528+ periodic_cleanup_timeout,
3529+ NULL);
3530+
3531+ }
3532+
3533+ main_loops = g_slist_prepend(main_loops, loop);
3534+
3535+ g_main_loop_run (loop);
3536+
3537+ main_loops = g_slist_remove(main_loops, loop);
3538+
3539+ if (main_loops == NULL)
3540+ {
3541+ g_assert(timeout_id != 0);
3542+ g_source_remove(timeout_id);
3543+ timeout_id = 0;
3544+ }
3545+
3546+ g_main_loop_unref (loop);
3547+}
3548+
3549+void
3550+gconfd_main_quit(void)
3551+{
3552+ g_return_if_fail(main_loops != NULL);
3553+
3554+ g_main_loop_quit (main_loops->data);
3555+}
3556+
3557+static gboolean
3558+gconf_main_is_running (void)
3559+{
3560+ return main_loops != NULL;
3561+}
3562+
3563+/*
3564+ * Database storage
3565+ */
3566+
3567+static GList* db_list = NULL;
3568+static GHashTable* dbs_by_addresses = NULL;
3569+static GConfDatabase *default_db = NULL;
3570+
3571+static void
3572+init_databases (void)
3573+{
3574+ gconfd_need_log_cleanup ();
3575+
3576+ g_assert(db_list == NULL);
3577+ g_assert(dbs_by_addresses == NULL);
3578+
3579+ dbs_by_addresses = g_hash_table_new (g_str_hash, g_str_equal);
3580+}
3581+
3582+static void
3583+set_default_database (GConfDatabase* db)
3584+{
3585+ gconfd_need_log_cleanup ();
3586+
3587+ default_db = db;
3588+
3589+ register_database (db);
3590+}
3591+
3592+static void
3593+register_database (GConfDatabase *db)
3594+{
3595+ gconfd_need_log_cleanup ();
3596+
3597+ if (db->sources->sources)
3598+ safe_g_hash_table_insert (dbs_by_addresses,
3599+ (char *) gconf_database_get_persistent_name (db),
3600+ db);
3601+
3602+ db_list = g_list_prepend (db_list, db);
3603+}
3604+
3605+static void
3606+unregister_database (GConfDatabase *db)
3607+{
3608+ gconfd_need_log_cleanup ();
3609+
3610+ if (db->sources->sources)
3611+ {
3612+ g_hash_table_remove (dbs_by_addresses,
3613+ gconf_database_get_persistent_name (db));
3614+ }
3615+
3616+ db_list = g_list_remove (db_list, db);
3617+
3618+ gconf_database_free (db);
3619+}
3620+
3621+static GConfDatabase*
3622+lookup_database (GSList *addresses)
3623+{
3624+ GConfDatabase *retval;
3625+ char *key;
3626+
3627+ if (addresses == NULL)
3628+ return default_db;
3629+
3630+ key = gconf_address_list_get_persistent_name (addresses);
3631+
3632+ retval = g_hash_table_lookup (dbs_by_addresses, key);
3633+
3634+ g_free (key);
3635+
3636+ return retval;
3637+}
3638+
3639+GConfDatabase *
3640+gconfd_obtain_database (GSList *addresses,
3641+ GError **err)
3642+{
3643+ GConfSources* sources;
3644+ GError* error = NULL;
3645+ GConfDatabase *db;
3646+
3647+ db = lookup_database (addresses);
3648+
3649+ if (db)
3650+ return db;
3651+
3652+ sources = gconf_sources_new_from_addresses(addresses, &error);
3653+
3654+ if (error != NULL)
3655+ {
3656+ if (err)
3657+ *err = error;
3658+ else
3659+ g_error_free (error);
3660+
3661+ return NULL;
3662+ }
3663+
3664+ if (sources == NULL)
3665+ return NULL;
3666+
3667+ db = gconf_database_new (sources);
3668+
3669+ register_database (db);
3670+
3671+ return db;
3672+}
3673+
3674+static void
3675+drop_old_databases(void)
3676+{
3677+ GList *tmp_list;
3678+ GList *dead = NULL;
3679+ GTime now;
3680+
3681+ now = time(NULL);
3682+
3683+ gconf_database_drop_dead_listeners (default_db);
3684+
3685+ tmp_list = db_list;
3686+ while (tmp_list)
3687+ {
3688+ GConfDatabase* db = tmp_list->data;
3689+
3690+ if (db == default_db)
3691+ {
3692+ tmp_list = g_list_next (tmp_list);
3693+ continue;
3694+ }
3695+
3696+ /* Drop any listeners whose clients are gone. */
3697+ gconf_database_drop_dead_listeners (db);
3698+
3699+ if (db->listeners && /* not already hibernating */
3700+ gconf_listeners_count(db->listeners) == 0 && /* Can hibernate */
3701+#ifdef HAVE_DBUS
3702+ db->listening_clients &&
3703+ g_hash_table_size (db->listening_clients) == 0 &&
3704+#endif
3705+ (now - db->last_access) > (60*20)) /* 20 minutes without access */
3706+ {
3707+ dead = g_list_prepend (dead, db);
3708+ }
3709+
3710+ tmp_list = g_list_next (tmp_list);
3711+ }
3712+
3713+ tmp_list = dead;
3714+ while (tmp_list)
3715+ {
3716+ GConfDatabase* db = tmp_list->data;
3717+
3718+ unregister_database (db);
3719+
3720+ tmp_list = g_list_next (tmp_list);
3721+ }
3722+
3723+ g_list_free (dead);
3724+}
3725+
3726+static void
3727+shutdown_databases (void)
3728+{
3729+ GList *tmp_list;
3730+
3731+ /* This may be called before we init fully,
3732+ * so check that everything != NULL
3733+ */
3734+
3735+ tmp_list = db_list;
3736+
3737+ while (tmp_list)
3738+ {
3739+ GConfDatabase *db = tmp_list->data;
3740+
3741+ gconf_database_free (db);
3742+
3743+ tmp_list = g_list_next (tmp_list);
3744+ }
3745+
3746+ g_list_free (db_list);
3747+ db_list = NULL;
3748+
3749+ if (dbs_by_addresses)
3750+ g_hash_table_destroy(dbs_by_addresses);
3751+
3752+ dbs_by_addresses = NULL;
3753+ default_db = NULL;
3754+}
3755+
3756+#ifdef HAVE_DBUS
3757+static void
3758+reload_databases (void)
3759+{
3760+ GConfSources* sources;
3761+ GList *tmp_list;
3762+
3763+ sources = gconf_server_get_default_sources ();
3764+ gconf_database_set_sources (default_db, sources);
3765+
3766+ tmp_list = db_list;
3767+ while (tmp_list)
3768+ {
3769+ GConfDatabase* db = tmp_list->data;
3770+ GList *l;
3771+ GConfSource *source;
3772+ GSList *addresses = NULL;
3773+ GError *error = NULL;
3774+
3775+ if (db == default_db)
3776+ {
3777+ tmp_list = g_list_next (tmp_list);
3778+ continue;
3779+ }
3780+
3781+ for (l = db->sources->sources; l != NULL; l = l->next)
3782+ {
3783+ source = l->data;
3784+ addresses = g_slist_prepend (addresses, source->address);
3785+ }
3786+
3787+ addresses = g_slist_reverse (addresses);
3788+ sources = gconf_sources_new_from_addresses (addresses, &error);
3789+
3790+ if (error == NULL)
3791+ {
3792+ gconf_database_set_sources (db, sources);
3793+ }
3794+ else
3795+ {
3796+ /* if we got an error, keep our old sources -- that's better than
3797+ * nothing */
3798+ g_error_free (error);
3799+ }
3800+
3801+ tmp_list = g_list_next (tmp_list);
3802+ }
3803+}
3804+#endif
3805+
3806+static gboolean
3807+no_databases_in_use (void)
3808+{
3809+ /* Only the default database still open, and
3810+ * it has no listeners
3811+ */
3812+
3813+ if (db_list == NULL)
3814+ return TRUE;
3815+
3816+ if (db_list->next == NULL &&
3817+ db_list->data == default_db)
3818+ return gconf_listeners_count (default_db->listeners) == 0;
3819+
3820+ return FALSE;
3821+}
3822+
3823+void
3824+gconfd_notify_other_listeners (GConfDatabase *modified_db,
3825+ GConfSources *modified_sources,
3826+ const char *key)
3827+{
3828+ GList *tmp;
3829+
3830+ if (!modified_sources)
3831+ return;
3832+
3833+ tmp = db_list;
3834+ while (tmp != NULL)
3835+ {
3836+ GConfDatabase *db = tmp->data;
3837+
3838+ if (db != modified_db)
3839+ {
3840+ GList *tmp2;
3841+
3842+ tmp2 = modified_sources->sources;
3843+ while (tmp2)
3844+ {
3845+ GConfSource *modified_source = tmp2->data;
3846+
3847+ if (gconf_sources_is_affected (db->sources, modified_source, key))
3848+ {
3849+ GConfValue *value;
3850+#ifdef HAVE_CORBA
3851+ ConfigValue *cvalue;
3852+#endif
3853+ GError *error;
3854+ gboolean is_default;
3855+ gboolean is_writable;
3856+
3857+ error = NULL;
3858+ value = gconf_database_query_value (db,
3859+ key,
3860+ NULL,
3861+ TRUE,
3862+ NULL,
3863+ &is_default,
3864+ &is_writable,
3865+ &error);
3866+ if (error != NULL)
3867+ {
3868+ gconf_log (GCL_WARNING,
3869+ _("Error obtaining new value for `%s': %s"),
3870+ key, error->message);
3871+ g_error_free (error);
3872+ return;
3873+ }
3874+
3875+#if HAVE_CORBA
3876+ if (value != NULL)
3877+ {
3878+ cvalue = gconf_corba_value_from_gconf_value (value);
3879+ gconf_value_free (value);
3880+ }
3881+ else
3882+ {
3883+ cvalue = gconf_invalid_corba_value ();
3884+ }
3885+
3886+ gconf_database_notify_listeners (db,
3887+ NULL,
3888+ key,
3889+ cvalue,
3890+ is_default,
3891+ is_writable,
3892+ FALSE);
3893+ CORBA_free (cvalue);
3894+#endif
3895+#ifdef HAVE_DBUS
3896+ gconf_database_dbus_notify_listeners (db,
3897+ NULL,
3898+ key,
3899+ value,
3900+ is_default,
3901+ is_writable,
3902+ FALSE);
3903+#endif
3904+ }
3905+
3906+ tmp2 = tmp2->next;
3907+ }
3908+ }
3909+
3910+ tmp = tmp->next;
3911+ }
3912+}
3913+
3914+void
3915+gconfd_clear_cache_for_sources (GConfSources *sources)
3916+{
3917+ GList *tmp;
3918+
3919+ tmp = db_list;
3920+ while (tmp != NULL)
3921+ {
3922+ GConfDatabase *db = tmp->data;
3923+
3924+ gconf_database_clear_cache_for_sources (db, sources, NULL);
3925+
3926+ tmp = tmp->next;
3927+ }
3928+}
3929+
3930+/*
3931+ * Cleanup
3932+ */
3933+
3934+static void
3935+enter_shutdown(void)
3936+{
3937+ in_shutdown = TRUE;
3938+}
3939+
3940+
3941+#ifdef HAVE_CORBA
3942+/* Exceptions */
3943+
3944+gboolean
3945+gconf_set_exception(GError** error,
3946+ CORBA_Environment* ev)
3947+{
3948+ GConfError en;
3949+
3950+ if (error == NULL)
3951+ return FALSE;
3952+
3953+ if (*error == NULL)
3954+ return FALSE;
3955+
3956+ en = (*error)->code;
3957+
3958+ /* success is not supposed to get set */
3959+ g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);
3960+
3961+ {
3962+ ConfigException* ce;
3963+
3964+ ce = ConfigException__alloc();
3965+ g_assert(error != NULL);
3966+ g_assert(*error != NULL);
3967+ g_assert((*error)->message != NULL);
3968+ ce->message = CORBA_string_dup((gchar*)(*error)->message); /* cast const */
3969+
3970+ switch (en)
3971+ {
3972+ case GCONF_ERROR_FAILED:
3973+ ce->err_no = ConfigFailed;
3974+ break;
3975+ case GCONF_ERROR_NO_PERMISSION:
3976+ ce->err_no = ConfigNoPermission;
3977+ break;
3978+ case GCONF_ERROR_BAD_ADDRESS:
3979+ ce->err_no = ConfigBadAddress;
3980+ break;
3981+ case GCONF_ERROR_BAD_KEY:
3982+ ce->err_no = ConfigBadKey;
3983+ break;
3984+ case GCONF_ERROR_PARSE_ERROR:
3985+ ce->err_no = ConfigParseError;
3986+ break;
3987+ case GCONF_ERROR_CORRUPT:
3988+ ce->err_no = ConfigCorrupt;
3989+ break;
3990+ case GCONF_ERROR_TYPE_MISMATCH:
3991+ ce->err_no = ConfigTypeMismatch;
3992+ break;
3993+ case GCONF_ERROR_IS_DIR:
3994+ ce->err_no = ConfigIsDir;
3995+ break;
3996+ case GCONF_ERROR_IS_KEY:
3997+ ce->err_no = ConfigIsKey;
3998+ break;
3999+ case GCONF_ERROR_NO_WRITABLE_DATABASE:
4000+ ce->err_no = ConfigNoWritableDatabase;
4001+ break;
4002+ case GCONF_ERROR_IN_SHUTDOWN:
4003+ ce->err_no = ConfigInShutdown;
4004+ break;
4005+ case GCONF_ERROR_OVERRIDDEN:
4006+ ce->err_no = ConfigOverridden;
4007+ break;
4008+ case GCONF_ERROR_LOCK_FAILED:
4009+ ce->err_no = ConfigLockFailed;
4010+ break;
4011+
4012+ case GCONF_ERROR_OAF_ERROR:
4013+ case GCONF_ERROR_LOCAL_ENGINE:
4014+ case GCONF_ERROR_NO_SERVER:
4015+ case GCONF_ERROR_SUCCESS:
4016+ default:
4017+ gconf_log (GCL_ERR, "Unhandled error code %d", en);
4018+ g_assert_not_reached();
4019+ break;
4020+ }
4021+
4022+ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
4023+ ex_ConfigException, ce);
4024+
4025+ gconf_log(GCL_DEBUG, _("Returning exception: %s"), (*error)->message);
4026+
4027+ g_error_free(*error);
4028+ *error = NULL;
4029+
4030+ return TRUE;
4031+ }
4032+}
4033+
4034+gboolean
4035+gconfd_check_in_shutdown (CORBA_Environment *ev)
4036+{
4037+ if (in_shutdown)
4038+ {
4039+ ConfigException* ce;
4040+
4041+ ce = ConfigException__alloc();
4042+ ce->message = CORBA_string_dup("Configuration server is currently shutting down");
4043+ ce->err_no = ConfigInShutdown;
4044+
4045+ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
4046+ ex_ConfigException, ce);
4047+
4048+ return TRUE;
4049+ }
4050+ else
4051+ return FALSE;
4052+}
4053+
4054+/*
4055+ * Logging
4056+ */
4057+
4058+/*
4059+ The log file records the current listeners we have registered,
4060+ so we can restore them if we exit and restart.
4061+
4062+ Basically:
4063+
4064+ 1) On startup, we parse any logfile and try to restore the
4065+ listeners contained therein. As we restore each listener (give
4066+ clients a new listener ID) we append a removal of the previous
4067+ daemon's listener and the addition of our own listener to the
4068+ logfile; this means that if we crash and have to restore a
4069+ client's listener a second time, we'll have the client's current
4070+ listener ID. If all goes well we then atomically rewrite the
4071+ parsed logfile with the resulting current state, to keep the logfile
4072+ compact.
4073+
4074+ 2) While running, we keep a FILE* open and whenever we add/remove
4075+ a listener we write a line to the logfile recording it,
4076+ to keep the logfile always up-to-date.
4077+
4078+ 3) On normal exit, and also periodically (every hour or so, say) we
4079+ atomically write over the running log with our complete current
4080+ state, to keep the running log from growing without bound.
4081+*/
4082+
4083+static void
4084+get_log_names (gchar **logdir, gchar **logfile)
4085+{
4086+#ifndef G_OS_WIN32
4087+ const char *home = g_get_home_dir ();
4088+#else
4089+ const char *home = _gconf_win32_get_home_dir ();
4090+#endif
4091+
4092+ *logdir = g_build_filename (home, ".gconfd", NULL);
4093+ *logfile = g_build_filename (*logdir, "saved_state", NULL);
4094+}
4095+
4096+static void close_append_handle (void);
4097+
4098+static FILE* append_handle = NULL;
4099+static guint append_handle_timeout = 0;
4100+
4101+static gboolean
4102+close_append_handle_timeout(gpointer data)
4103+{
4104+ close_append_handle ();
4105+
4106+ /* uninstall the timeout */
4107+ append_handle_timeout = 0;
4108+ return FALSE;
4109+}
4110+
4111+static gboolean
4112+open_append_handle (GError **err)
4113+{
4114+ if (append_handle == NULL)
4115+ {
4116+ gchar *logdir;
4117+ gchar *logfile;
4118+
4119+ get_log_names (&logdir, &logfile);
4120+
4121+ g_mkdir (logdir, 0700); /* ignore failure, we'll catch failures
4122+ * that matter on open()
4123+ */
4124+
4125+ append_handle = g_fopen (logfile, "a");
4126+
4127+ if (append_handle == NULL)
4128+ {
4129+ gconf_set_error (err,
4130+ GCONF_ERROR_FAILED,
4131+ _("Failed to open gconfd logfile; won't be able to restore listeners after gconfd shutdown (%s)"),
4132+ g_strerror (errno));
4133+
4134+ g_free (logdir);
4135+ g_free (logfile);
4136+
4137+ return FALSE;
4138+ }
4139+
4140+ g_free (logdir);
4141+ g_free (logfile);
4142+
4143+
4144+ {
4145+ const gulong timeout_len = 60*0.5; /* 60 s/min * 0.5 min */
4146+
4147+ if (append_handle_timeout != 0)
4148+ g_source_remove (append_handle_timeout);
4149+
4150+ append_handle_timeout = g_timeout_add_seconds (timeout_len,
4151+ close_append_handle_timeout,
4152+ NULL);
4153+ }
4154+ }
4155+
4156+ return TRUE;
4157+}
4158+
4159+static void
4160+close_append_handle (void)
4161+{
4162+ if (append_handle)
4163+ {
4164+ if (fclose (append_handle) < 0)
4165+ gconf_log (GCL_WARNING,
4166+ _("Failed to close gconfd logfile; data may not have been properly saved (%s)"),
4167+ g_strerror (errno));
4168+
4169+ append_handle = NULL;
4170+
4171+ if (append_handle_timeout != 0)
4172+ {
4173+ g_source_remove (append_handle_timeout);
4174+ append_handle_timeout = 0;
4175+ }
4176+ }
4177+}
4178+
4179+/* Atomically save our current state, if possible; otherwise
4180+ * leave the running log in place.
4181+ */
4182+static void
4183+logfile_save (void)
4184+{
4185+ GList *tmp_list;
4186+ gchar *logdir = NULL;
4187+ gchar *logfile = NULL;
4188+ gchar *tmpfile = NULL;
4189+ gchar *tmpfile2 = NULL;
4190+ GString *saveme = NULL;
4191+ gint fd = -1;
4192+
4193+ /* Close the running log */
4194+ close_append_handle ();
4195+
4196+ get_log_names (&logdir, &logfile);
4197+
4198+ g_mkdir (logdir, 0700); /* ignore failure, we'll catch failures
4199+ * that matter on open()
4200+ */
4201+
4202+ saveme = g_string_new (NULL);
4203+
4204+ /* Clients */
4205+ log_clients_to_string (saveme);
4206+
4207+ /* Databases */
4208+ tmp_list = db_list;
4209+ while (tmp_list)
4210+ {
4211+ GConfDatabase *db = tmp_list->data;
4212+
4213+ gconf_database_log_listeners_to_string (db,
4214+ db == default_db ? TRUE : FALSE,
4215+ saveme);
4216+
4217+ tmp_list = g_list_next (tmp_list);
4218+ }
4219+
4220+ /* Now try saving the string to a temporary file */
4221+ tmpfile = g_strconcat (logfile, ".tmp", NULL);
4222+
4223+ fd = g_open (tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
4224+
4225+ if (fd < 0)
4226+ {
4227+ gconf_log (GCL_WARNING,
4228+ _("Could not open saved state file '%s' for writing: %s"),
4229+ tmpfile, g_strerror (errno));
4230+
4231+ goto out;
4232+ }
4233+
4234+ again:
4235+
4236+ if (write (fd, saveme->str, saveme->len) < 0)
4237+ {
4238+ if (errno == EINTR)
4239+ goto again;
4240+
4241+ gconf_log (GCL_WARNING,
4242+ _("Could not write saved state file '%s' fd: %d: %s"),
4243+ tmpfile, fd, g_strerror (errno));
4244+
4245+ goto out;
4246+ }
4247+
4248+ if (fsync (fd) < 0)
4249+ {
4250+ gconf_log (GCL_WARNING,
4251+ _("Could not flush saved state file '%s' to disk: %s"),
4252+ tmpfile, g_strerror (errno));
4253+ }
4254+
4255+ if (close (fd) < 0)
4256+ {
4257+ gconf_log (GCL_WARNING,
4258+ _("Failed to close new saved state file '%s': %s"),
4259+ tmpfile, g_strerror (errno));
4260+ goto out;
4261+ }
4262+
4263+ fd = -1;
4264+
4265+ /* Move the main saved state file aside, if it exists */
4266+ if (g_file_test(logfile, G_FILE_TEST_EXISTS))
4267+ {
4268+ tmpfile2 = g_strconcat (logfile, ".orig", NULL);
4269+ if (g_rename (logfile, tmpfile2) < 0)
4270+ {
4271+ gconf_log (GCL_WARNING,
4272+ _("Could not move aside old saved state file '%s': %s"),
4273+ logfile, g_strerror (errno));
4274+ goto out;
4275+ }
4276+ }
4277+
4278+ /* Move the new saved state file into place */
4279+ if (g_rename (tmpfile, logfile) < 0)
4280+ {
4281+ gconf_log (GCL_WARNING,
4282+ _("Failed to move new saved state file into place: %s"),
4283+ g_strerror (errno));
4284+
4285+ /* Try to restore old file */
4286+ if (tmpfile2)
4287+ {
4288+ if (g_rename (tmpfile2, logfile) < 0)
4289+ {
4290+ gconf_log (GCL_WARNING,
4291+ _("Failed to restore original saved state file that had been moved to '%s': %s"),
4292+ tmpfile2, g_strerror (errno));
4293+
4294+ }
4295+ }
4296+
4297+ goto out;
4298+ }
4299+
4300+ /* Get rid of original saved state file if everything succeeded */
4301+ if (tmpfile2)
4302+ g_unlink (tmpfile2);
4303+
4304+ out:
4305+ if (saveme)
4306+ g_string_free (saveme, TRUE);
4307+ g_free (logdir);
4308+ g_free (logfile);
4309+ g_free (tmpfile);
4310+ g_free (tmpfile2);
4311+
4312+ if (fd >= 0)
4313+ close (fd);
4314+}
4315+
4316+typedef struct _ListenerLogEntry ListenerLogEntry;
4317+
4318+struct _ListenerLogEntry
4319+{
4320+ guint connection_id;
4321+ gchar *ior;
4322+ gchar *address;
4323+ gchar *location;
4324+};
4325+
4326+static guint
4327+listener_logentry_hash (gconstpointer v)
4328+{
4329+ const ListenerLogEntry *lle = v;
4330+
4331+ return
4332+ (lle->connection_id & 0xff000000) |
4333+ (g_str_hash (lle->ior) & 0x00ff0000) |
4334+ (g_str_hash (lle->address) & 0x0000ff00) |
4335+ (g_str_hash (lle->location) & 0x000000ff);
4336+}
4337+
4338+static gboolean
4339+listener_logentry_equal (gconstpointer ap, gconstpointer bp)
4340+{
4341+ const ListenerLogEntry *a = ap;
4342+ const ListenerLogEntry *b = bp;
4343+
4344+ return
4345+ a->connection_id == b->connection_id &&
4346+ strcmp (a->location, b->location) == 0 &&
4347+ strcmp (a->ior, b->ior) == 0 &&
4348+ strcmp (a->address, b->address) == 0;
4349+}
4350+
4351+/* Return value indicates whether we "handled" this line of text */
4352+static gboolean
4353+parse_listener_entry (GHashTable *entries,
4354+ gchar *text)
4355+{
4356+ gboolean add;
4357+ gchar *p;
4358+ gchar *ior;
4359+ gchar *address;
4360+ gchar *location;
4361+ gchar *end;
4362+ guint connection_id;
4363+ GError *err;
4364+ ListenerLogEntry *lle;
4365+ ListenerLogEntry *old;
4366+
4367+ if (strncmp (text, "ADD", 3) == 0)
4368+ {
4369+ add = TRUE;
4370+ p = text + 3;
4371+ }
4372+ else if (strncmp (text, "REMOVE", 6) == 0)
4373+ {
4374+ add = FALSE;
4375+ p = text + 6;
4376+ }
4377+ else
4378+ {
4379+ return FALSE;
4380+ }
4381+
4382+ while (*p && g_ascii_isspace (*p))
4383+ ++p;
4384+
4385+ errno = 0;
4386+ end = NULL;
4387+ connection_id = strtoul (p, &end, 10);
4388+ if (end == p || errno != 0)
4389+ {
4390+ gconf_log (GCL_DEBUG,
4391+ "Failed to parse connection ID in saved state file");
4392+
4393+ return TRUE;
4394+ }
4395+
4396+ if (connection_id == 0)
4397+ {
4398+ gconf_log (GCL_DEBUG,
4399+ "Connection ID 0 in saved state file is not valid");
4400+ return TRUE;
4401+ }
4402+
4403+ p = end;
4404+
4405+ while (*p && g_ascii_isspace (*p))
4406+ ++p;
4407+
4408+ err = NULL;
4409+ end = NULL;
4410+ gconf_unquote_string_inplace (p, &end, &err);
4411+ if (err != NULL)
4412+ {
4413+ gconf_log (GCL_DEBUG,
4414+ "Failed to unquote configuration source address from saved state file: %s",
4415+ err->message);
4416+
4417+ g_error_free (err);
4418+
4419+ return TRUE;
4420+ }
4421+
4422+ address = p;
4423+ p = end;
4424+
4425+ while (*p && g_ascii_isspace (*p))
4426+ ++p;
4427+
4428+ err = NULL;
4429+ end = NULL;
4430+ gconf_unquote_string_inplace (p, &end, &err);
4431+ if (err != NULL)
4432+ {
4433+ gconf_log (GCL_DEBUG,
4434+ "Failed to unquote listener location from saved state file: %s",
4435+ err->message);
4436+
4437+ g_error_free (err);
4438+
4439+ return TRUE;
4440+ }
4441+
4442+ location = p;
4443+ p = end;
4444+
4445+ while (*p && g_ascii_isspace (*p))
4446+ ++p;
4447+
4448+ err = NULL;
4449+ end = NULL;
4450+ gconf_unquote_string_inplace (p, &end, &err);
4451+ if (err != NULL)
4452+ {
4453+ gconf_log (GCL_DEBUG,
4454+ "Failed to unquote IOR from saved state file: %s",
4455+ err->message);
4456+
4457+ g_error_free (err);
4458+
4459+ return TRUE;
4460+ }
4461+
4462+ ior = p;
4463+ p = end;
4464+
4465+ lle = g_new (ListenerLogEntry, 1);
4466+ lle->connection_id = connection_id;
4467+ lle->address = address;
4468+ lle->ior = ior;
4469+ lle->location = location;
4470+
4471+ if (*(lle->address) == '\0' ||
4472+ *(lle->ior) == '\0' ||
4473+ *(lle->location) == '\0')
4474+ {
4475+ gconf_log (GCL_DEBUG,
4476+ "Saved state file listener entry didn't contain all the fields; ignoring.");
4477+
4478+ g_free (lle);
4479+
4480+ return TRUE;
4481+ }
4482+
4483+ old = g_hash_table_lookup (entries, lle);
4484+
4485+ if (old)
4486+ {
4487+ if (add)
4488+ {
4489+ gconf_log (GCL_DEBUG,
4490+ "Saved state file records the same listener added twice; ignoring the second instance");
4491+ goto quit;
4492+ }
4493+ else
4494+ {
4495+ /* This entry was added, then removed. */
4496+ g_hash_table_remove (entries, lle);
4497+ goto quit;
4498+ }
4499+ }
4500+ else
4501+ {
4502+ if (add)
4503+ {
4504+ g_hash_table_insert (entries, lle, lle);
4505+
4506+ return TRUE;
4507+ }
4508+ else
4509+ {
4510+ gconf_log (GCL_DEBUG,
4511+ "Saved state file had a removal of a listener that wasn't added; ignoring the removal.");
4512+ goto quit;
4513+ }
4514+ }
4515+
4516+ quit:
4517+ g_free (lle);
4518+
4519+ return TRUE;
4520+}
4521+
4522+/* Return value indicates whether we "handled" this line of text */
4523+static gboolean
4524+parse_client_entry (GHashTable *clients,
4525+ gchar *text)
4526+{
4527+ gboolean add;
4528+ gchar *ior;
4529+ GError *err;
4530+ gchar *old;
4531+ gchar *p;
4532+ gchar *end;
4533+
4534+ if (strncmp (text, "CLIENTADD", 9) == 0)
4535+ {
4536+ add = TRUE;
4537+ p = text + 9;
4538+ }
4539+ else if (strncmp (text, "CLIENTREMOVE", 12) == 0)
4540+ {
4541+ add = FALSE;
4542+ p = text + 12;
4543+ }
4544+ else
4545+ {
4546+ return FALSE;
4547+ }
4548+
4549+ while (*p && g_ascii_isspace (*p))
4550+ ++p;
4551+
4552+ err = NULL;
4553+ end = NULL;
4554+ gconf_unquote_string_inplace (p, &end, &err);
4555+ if (err != NULL)
4556+ {
4557+ gconf_log (GCL_DEBUG,
4558+ "Failed to unquote IOR from saved state file: %s",
4559+ err->message);
4560+
4561+ g_error_free (err);
4562+
4563+ return TRUE;
4564+ }
4565+
4566+ ior = p;
4567+ p = end;
4568+
4569+ old = g_hash_table_lookup (clients, ior);
4570+
4571+ if (old)
4572+ {
4573+ if (add)
4574+ {
4575+ gconf_log (GCL_DEBUG,
4576+ "Saved state file records the same client added twice; ignoring the second instance");
4577+ goto quit;
4578+ }
4579+ else
4580+ {
4581+ /* This entry was added, then removed. */
4582+ g_hash_table_remove (clients, ior);
4583+ goto quit;
4584+ }
4585+ }
4586+ else
4587+ {
4588+ if (add)
4589+ {
4590+ g_hash_table_insert (clients, ior, ior);
4591+
4592+ return TRUE;
4593+ }
4594+ else
4595+ {
4596+ gconf_log (GCL_DEBUG,
4597+ "Saved state file had a removal of a client that wasn't added; ignoring the removal.");
4598+ goto quit;
4599+ }
4600+ }
4601+
4602+ quit:
4603+
4604+ return TRUE;
4605+}
4606+
4607+static void
4608+restore_client (const gchar *ior)
4609+{
4610+ ConfigListener cl;
4611+ CORBA_Environment ev;
4612+
4613+ CORBA_exception_init (&ev);
4614+
4615+ cl = CORBA_ORB_string_to_object (gconf_orb_get (), (gchar*)ior, &ev);
4616+
4617+ CORBA_exception_free (&ev);
4618+
4619+ if (CORBA_Object_is_nil (cl, &ev))
4620+ {
4621+ CORBA_exception_free (&ev);
4622+
4623+ gconf_log (GCL_DEBUG,
4624+ "Client in saved state file no longer exists, not restoring it as a client");
4625+
4626+ return;
4627+ }
4628+
4629+ ConfigListener_drop_all_caches (cl, &ev);
4630+
4631+ if (ev._major != CORBA_NO_EXCEPTION)
4632+ {
4633+ gconf_log (GCL_DEBUG, "Failed to update client in saved state file, the client probably no longer exists");
4634+
4635+ goto finished;
4636+ }
4637+
4638+ /* Add the client, since it still exists. Note that the client still
4639+ * has the wrong server object reference, so next time it tries to
4640+ * contact the server it will re-add itself; we just live with that,
4641+ * it's not a problem.
4642+ */
4643+ add_client (cl);
4644+
4645+ finished:
4646+ CORBA_Object_release (cl, &ev);
4647+
4648+ CORBA_exception_free (&ev);
4649+}
4650+
4651+static void
4652+restore_listener (GConfDatabase* db,
4653+ ListenerLogEntry *lle)
4654+{
4655+ ConfigListener cl;
4656+ CORBA_Environment ev;
4657+ guint new_cnxn;
4658+ GError *err;
4659+
4660+ CORBA_exception_init (&ev);
4661+
4662+ cl = CORBA_ORB_string_to_object (gconf_orb_get (), lle->ior, &ev);
4663+
4664+ CORBA_exception_free (&ev);
4665+
4666+ if (CORBA_Object_is_nil (cl, &ev))
4667+ {
4668+ CORBA_exception_free (&ev);
4669+
4670+ gconf_log (GCL_DEBUG,
4671+ "Client in saved state file no longer exists, not updating its listener connections");
4672+
4673+ return;
4674+ }
4675+
4676+ /* "Cancel" the addition of the listener in the saved state file,
4677+ * so that if we reload the saved state file a second time
4678+ * for some reason, we don't try to add this listener that time.
4679+ */
4680+
4681+ err = NULL;
4682+ if (!gconfd_logfile_change_listener (db,
4683+ FALSE, /* remove */
4684+ lle->connection_id,
4685+ cl,
4686+ lle->location,
4687+ &err))
4688+ {
4689+ gconf_log (GCL_DEBUG,
4690+ "Failed to cancel previous daemon's listener in saved state file: %s",
4691+ err->message);
4692+ g_error_free (err);
4693+ }
4694+
4695+ new_cnxn = gconf_database_readd_listener (db, cl, "from-saved-state", lle->location);
4696+
4697+ gconf_log (GCL_DEBUG, "Attempting to update listener from saved state file, old connection %u, new connection %u", (guint) lle->connection_id, (guint) new_cnxn);
4698+
4699+ ConfigListener_update_listener (cl,
4700+ db->objref,
4701+ lle->address,
4702+ lle->connection_id,
4703+ lle->location,
4704+ new_cnxn,
4705+ &ev);
4706+
4707+ if (ev._major != CORBA_NO_EXCEPTION)
4708+ {
4709+ gconf_log (GCL_DEBUG, "Failed to update listener in saved state file, probably the client no longer exists");
4710+
4711+ /* listener will get removed next time we try to notify -
4712+ * we already appended a cancel of the listener to the
4713+ * saved state file.
4714+ */
4715+ goto finished;
4716+ }
4717+
4718+ /* Successfully notified client of new connection ID, so put that
4719+ * connection ID in the saved state file.
4720+ */
4721+ err = NULL;
4722+ if (!gconfd_logfile_change_listener (db,
4723+ TRUE, /* add */
4724+ new_cnxn,
4725+ cl,
4726+ lle->location,
4727+ &err))
4728+ {
4729+ gconf_log (GCL_DEBUG,
4730+ "Failed to re-add this daemon's listener ID in saved state file: %s",
4731+ err->message);
4732+ g_error_free (err);
4733+ }
4734+
4735+ /* We updated the listener, and logged that to the saved state
4736+ * file. Yay!
4737+ */
4738+
4739+ finished:
4740+
4741+ CORBA_Object_release (cl, &ev);
4742+
4743+ CORBA_exception_free (&ev);
4744+}
4745+
4746+static void
4747+listener_logentry_restore_and_destroy_foreach (gpointer key,
4748+ gpointer value,
4749+ gpointer data)
4750+{
4751+ ListenerLogEntry *lle = key;
4752+ GConfDatabase *db = NULL;
4753+
4754+ if (strcmp (lle->address, "def") == 0)
4755+ db = default_db;
4756+ else
4757+ {
4758+ GSList *addresses;
4759+
4760+ addresses = gconf_persistent_name_get_address_list (lle->address);
4761+
4762+ db = gconfd_obtain_database (addresses, NULL);
4763+
4764+ gconf_address_list_free (addresses);
4765+ }
4766+
4767+ if (db == NULL)
4768+ {
4769+ gconf_log (GCL_WARNING,
4770+ _("Unable to restore a listener on address '%s', couldn't resolve the database"),
4771+ lle->address);
4772+ return;
4773+ }
4774+
4775+ restore_listener (db, lle);
4776+
4777+ /* We don't need it anymore */
4778+ g_free (lle);
4779+}
4780+
4781+static void
4782+restore_client_foreach (gpointer key,
4783+ gpointer value,
4784+ gpointer data)
4785+{
4786+ restore_client (key);
4787+}
4788+
4789+
4790+static gchar*
4791+read_line (FILE *f)
4792+{
4793+#define BUF_SIZE 2048
4794+
4795+ char buf[BUF_SIZE] = { '\0' };
4796+ char *retval = NULL;
4797+ int len = 0;
4798+
4799+ do
4800+ {
4801+ if (fgets (buf, BUF_SIZE, f) == NULL)
4802+ {
4803+ if (ferror (f))
4804+ {
4805+ gconf_log (GCL_ERR,
4806+ _("Error reading saved state file: %s"),
4807+ g_strerror (errno));
4808+ }
4809+ break;
4810+ }
4811+
4812+ len = strlen (buf);
4813+ if (len > 0 && buf[len - 1] == '\n')
4814+ buf[--len] = '\0';
4815+
4816+ if (retval == NULL)
4817+ {
4818+ retval = g_strndup (buf, len);
4819+ }
4820+ else
4821+ {
4822+ char *freeme = retval;
4823+
4824+ retval = g_strconcat (retval, buf, NULL);
4825+ g_free (freeme);
4826+ }
4827+ }
4828+ while (len == BUF_SIZE - 1);
4829+
4830+ return retval;
4831+
4832+#undef BUF_SIZE
4833+}
4834+
4835+static void
4836+logfile_read (void)
4837+{
4838+ gchar *logfile;
4839+ gchar *logdir;
4840+ GHashTable *entries;
4841+ GHashTable *clients;
4842+ FILE *f;
4843+ gchar *line;
4844+ GSList *lines = NULL;
4845+
4846+ /* Just for good form */
4847+ close_append_handle ();
4848+
4849+ get_log_names (&logdir, &logfile);
4850+
4851+ f = g_fopen (logfile, "r");
4852+
4853+ if (f == NULL)
4854+ {
4855+ if (errno != ENOENT)
4856+ gconf_log (GCL_ERR, _("Unable to open saved state file '%s': %s"),
4857+ logfile, g_strerror (errno));
4858+
4859+ goto finished;
4860+ }
4861+
4862+ entries = g_hash_table_new (listener_logentry_hash, listener_logentry_equal);
4863+ clients = g_hash_table_new (g_str_hash, g_str_equal);
4864+
4865+ line = read_line (f);
4866+ while (line)
4867+ {
4868+ if (!parse_listener_entry (entries, line))
4869+ {
4870+ if (!parse_client_entry (clients, line))
4871+ {
4872+ gconf_log (GCL_DEBUG,
4873+ "Didn't understand line in saved state file: '%s'",
4874+ line);
4875+ g_free (line);
4876+ line = NULL;
4877+ }
4878+ }
4879+
4880+ if (line)
4881+ lines = g_slist_prepend (lines, line);
4882+
4883+ line = read_line (f);
4884+ }
4885+
4886+ /* Restore clients first */
4887+ g_hash_table_foreach (clients,
4888+ restore_client_foreach,
4889+ NULL);
4890+
4891+ /* Entries that still remain in the listener hash table were added
4892+ * but not removed, so add them in this daemon instantiation and
4893+ * update their listeners with the new connection ID etc.
4894+ */
4895+ g_hash_table_foreach (entries,
4896+ listener_logentry_restore_and_destroy_foreach,
4897+ NULL);
4898+
4899+ g_hash_table_destroy (entries);
4900+ g_hash_table_destroy (clients);
4901+
4902+ /* Note that we need the strings to remain valid until we are totally
4903+ * finished, because we store pointers to them in the log entry
4904+ * hash.
4905+ */
4906+ g_slist_foreach (lines, (GFunc)g_free, NULL);
4907+ g_slist_free (lines);
4908+
4909+ finished:
4910+ if (f != NULL)
4911+ fclose (f);
4912+
4913+ g_free (logfile);
4914+ g_free (logdir);
4915+}
4916+
4917+gboolean
4918+gconfd_logfile_change_listener (GConfDatabase *db,
4919+ gboolean add,
4920+ guint connection_id,
4921+ ConfigListener listener,
4922+ const gchar *where,
4923+ GError **err)
4924+{
4925+ gchar *ior = NULL;
4926+ gchar *quoted_db_name;
4927+ gchar *quoted_where;
4928+ gchar *quoted_ior;
4929+
4930+ if (!open_append_handle (err))
4931+ return FALSE;
4932+
4933+ ior = gconf_object_to_string (listener, err);
4934+
4935+ if (ior == NULL)
4936+ return FALSE;
4937+
4938+ quoted_ior = gconf_quote_string (ior);
4939+ g_free (ior);
4940+ ior = NULL;
4941+
4942+ if (db == default_db)
4943+ quoted_db_name = gconf_quote_string ("def");
4944+ else
4945+ {
4946+ const gchar *db_name;
4947+
4948+ db_name = gconf_database_get_persistent_name (db);
4949+
4950+ quoted_db_name = gconf_quote_string (db_name);
4951+ }
4952+
4953+ quoted_where = gconf_quote_string (where);
4954+
4955+ /* KEEP IN SYNC with gconf-database.c log to string function */
4956+ if (fprintf (append_handle, "%s %u %s %s %s\n",
4957+ add ? "ADD" : "REMOVE", connection_id,
4958+ quoted_db_name, quoted_where, quoted_ior) < 0)
4959+ goto error;
4960+
4961+ if (fflush (append_handle) < 0)
4962+ goto error;
4963+
4964+ g_free (quoted_db_name);
4965+ g_free (quoted_ior);
4966+ g_free (quoted_where);
4967+
4968+ return TRUE;
4969+
4970+ error:
4971+
4972+ if (add)
4973+ gconf_set_error (err,
4974+ GCONF_ERROR_FAILED,
4975+ _("Failed to log addition of listener to gconfd logfile; won't be able to re-add the listener if gconfd exits or shuts down (%s)"),
4976+ g_strerror (errno));
4977+ else
4978+ gconf_set_error (err,
4979+ GCONF_ERROR_FAILED,
4980+ _("Failed to log removal of listener to gconfd logfile; might erroneously re-add the listener if gconfd exits or shuts down (%s)"),
4981+ g_strerror (errno));
4982+
4983+ g_free (quoted_db_name);
4984+ g_free (quoted_ior);
4985+ g_free (quoted_where);
4986+
4987+ return FALSE;
4988+}
4989+
4990+static void
4991+log_client_change (const ConfigListener client,
4992+ gboolean add)
4993+{
4994+ gchar *ior = NULL;
4995+ gchar *quoted_ior = NULL;
4996+ GError *err;
4997+
4998+ err = NULL;
4999+ ior = gconf_object_to_string (client, &err);
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: