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
=== added directory '.pc/01_defaults_path.patch'
=== removed directory '.pc/01_defaults_path.patch'
=== added directory '.pc/01_defaults_path.patch/defaults'
=== removed directory '.pc/01_defaults_path.patch/defaults'
=== added file '.pc/01_defaults_path.patch/defaults/gconf-defaults.c'
--- .pc/01_defaults_path.patch/defaults/gconf-defaults.c 1970-01-01 00:00:00 +0000
+++ .pc/01_defaults_path.patch/defaults/gconf-defaults.c 2012-03-06 01:10:25 +0000
@@ -0,0 +1,1199 @@
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20
21#include <config.h>
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <string.h>
28#include <sys/wait.h>
29#include <errno.h>
30#include <sys/time.h>
31#include <sys/types.h>
32#include <pwd.h>
33
34#include <glib.h>
35#include <glib-object.h>
36
37#include <dbus/dbus-glib.h>
38#include <dbus/dbus-glib-lowlevel.h>
39
40#include <polkit/polkit.h>
41
42#define GCONF_ENABLE_INTERNALS
43#include <gconf/gconf-client.h>
44#include <gconf/gconf-engine.h>
45
46#include "gconf-defaults.h"
47#include "gconf-defaults-glue.h"
48
49static gboolean
50do_exit (gpointer user_data)
51{
52 g_debug ("Exiting due to inactivity");
53 exit (1);
54 return FALSE;
55}
56
57static guint timer_id = 0;
58gboolean disable_killtimer = FALSE;
59
60static void
61stop_killtimer (void)
62{
63 if (disable_killtimer)
64 return;
65
66 if (timer_id > 0) {
67 g_source_remove (timer_id);
68 timer_id = 0;
69 }
70}
71
72static void
73start_killtimer (void)
74{
75 if (disable_killtimer)
76 return;
77
78 if (timer_id == 0) {
79 g_debug ("Setting killtimer to 30 seconds...");
80 timer_id = g_timeout_add_seconds (30, do_exit, NULL);
81 }
82}
83
84static gint operations = 0;
85
86static void
87start_operation (void)
88{
89 if (operations == 0)
90 stop_killtimer ();
91 operations++;
92}
93
94static void
95stop_operation (void)
96{
97 if (operations == 1)
98 start_killtimer ();
99 operations --;
100}
101
102struct GConfDefaultsPrivate
103{
104 DBusGConnection *system_bus_connection;
105 DBusGProxy *system_bus_proxy;
106 PolkitAuthority *auth;
107};
108
109static void gconf_defaults_finalize (GObject *object);
110
111G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
112
113#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
114
115GQuark
116gconf_defaults_error_quark (void)
117{
118 static GQuark ret = 0;
119
120 if (ret == 0) {
121 ret = g_quark_from_static_string ("gconf_defaults_error");
122 }
123
124 return ret;
125}
126
127
128#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
129
130GType
131gconf_defaults_error_get_type (void)
132{
133 static GType etype = 0;
134
135 if (etype == 0)
136 {
137 static const GEnumValue values[] =
138 {
139 ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
140 ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
141 { 0, 0, 0 }
142 };
143
144 g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
145
146 etype = g_enum_register_static ("GConfDefaultsError", values);
147 }
148
149 return etype;
150}
151
152
153static GObject *
154gconf_defaults_constructor (GType type,
155 guint n_construct_properties,
156 GObjectConstructParam *construct_properties)
157{
158 GConfDefaults *mechanism;
159 GConfDefaultsClass *klass;
160
161 klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
162
163 mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
164 type,
165 n_construct_properties,
166 construct_properties));
167
168 return G_OBJECT (mechanism);
169}
170
171enum {
172 SYSTEM_SET,
173 LAST_SIGNAL
174};
175
176static guint signals[LAST_SIGNAL] = { 0 };
177
178static void
179gconf_defaults_class_init (GConfDefaultsClass *klass)
180{
181 GObjectClass *object_class = G_OBJECT_CLASS (klass);
182
183 object_class->constructor = gconf_defaults_constructor;
184 object_class->finalize = gconf_defaults_finalize;
185
186 signals[SYSTEM_SET] = g_signal_new ("system-set",
187 G_OBJECT_CLASS_TYPE (object_class),
188 G_SIGNAL_RUN_FIRST,
189 G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__BOXED,
192 G_TYPE_NONE, 1, G_TYPE_STRV);
193
194 g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
195
196 dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
197
198 dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
199
200}
201
202static void
203gconf_defaults_init (GConfDefaults *mechanism)
204{
205 mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
206}
207
208static void
209gconf_defaults_finalize (GObject *object)
210{
211 GConfDefaults *mechanism;
212
213 g_return_if_fail (object != NULL);
214 g_return_if_fail (GCONF_IS_DEFAULTS (object));
215
216 mechanism = GCONF_DEFAULTS (object);
217
218 g_return_if_fail (mechanism->priv != NULL);
219
220 g_object_unref (mechanism->priv->auth);
221 g_object_unref (mechanism->priv->system_bus_proxy);
222
223 G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
224}
225
226static gboolean
227register_mechanism (GConfDefaults *mechanism)
228{
229 GError *error = NULL;
230
231 mechanism->priv->auth = polkit_authority_get ();
232
233 error = NULL;
234 mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
235 if (mechanism->priv->system_bus_connection == NULL) {
236 if (error != NULL) {
237 g_critical ("error getting system bus: %s", error->message);
238 g_error_free (error);
239 }
240 goto error;
241 }
242
243 dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
244 G_OBJECT (mechanism));
245
246 mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
247 DBUS_SERVICE_DBUS,
248 DBUS_PATH_DBUS,
249 DBUS_INTERFACE_DBUS);
250
251 start_killtimer ();
252
253 return TRUE;
254
255error:
256 return FALSE;
257}
258
259
260GConfDefaults *
261gconf_defaults_new (void)
262{
263 GObject *object;
264 gboolean res;
265
266 object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
267
268 res = register_mechanism (GCONF_DEFAULTS (object));
269 if (! res) {
270 g_object_unref (object);
271 return NULL;
272 }
273
274 return GCONF_DEFAULTS (object);
275}
276
277static const char *
278polkit_action_for_gconf_path (GConfDefaults *mechanism,
279 GList *action_descriptions,
280 const char *annotation_key,
281 const char *path)
282{
283 char *prefix, *p;
284 const char *action;
285 GList *l;
286 PolkitActionDescription *action_description;
287 const gchar *annotation;
288
289 g_debug ("finding action for path '%s'", path);
290 prefix = g_strdup (path);
291 while (1) {
292 for (l = action_descriptions; l; l = l->next) {
293 action_description = l->data;
294
295 annotation = polkit_action_description_get_annotation (action_description, annotation_key);
296 if (g_strcmp0 (prefix, annotation) == 0) {
297 action = polkit_action_description_get_action_id (action_description);
298 g_debug ("action for prefix '%s': '%s'\n", prefix, action);
299 goto found;
300 }
301 }
302
303 p = strrchr (prefix, '/');
304
305 if (p == NULL || p == prefix) {
306 action = NULL;
307 break;
308 }
309
310 *p = 0;
311 }
312
313 found:
314 g_free (prefix);
315
316 return action;
317}
318
319static void
320throw_error (DBusGMethodInvocation *context,
321 gint error_code,
322 const gchar *format,
323 ...)
324{
325 GError *error;
326 va_list args;
327 gchar *message;
328
329 va_start (args, format);
330 message = g_strdup_vprintf (format, args);
331 va_end (args);
332
333 error = g_error_new (GCONF_DEFAULTS_ERROR,
334 error_code,
335 "%s", message);
336 dbus_g_method_return_error (context, error);
337 g_error_free (error);
338 g_free (message);
339}
340
341typedef void (*AuthObtainedCallback) (GConfDefaults *mechanism,
342 DBusGMethodInvocation *context,
343 gpointer user_data);
344
345typedef struct
346{
347 GConfDefaults *mechanism;
348 DBusGMethodInvocation *context;
349 gchar **actions;
350 gint id;
351 gint flags;
352 AuthObtainedCallback auth_obtained_callback;
353 GAsyncReadyCallback check_auth_callback;
354 gpointer user_data;
355 GDestroyNotify destroy;
356 PolkitSubject *subject;
357 gboolean challenge;
358} CheckAuthData;
359
360static void
361check_auth_data_free (CheckAuthData *data)
362{
363 g_object_unref (data->mechanism);
364 g_strfreev (data->actions);
365 if (data->destroy)
366 data->destroy (data->user_data);
367 g_object_unref (data->subject);
368 g_free (data);
369}
370
371static void check_next_action (CheckAuthData *data);
372
373static void
374check_authorization_callback (PolkitAuthority *authority,
375 GAsyncResult *res,
376 gpointer user_data)
377{
378 CheckAuthData *data = user_data;
379 PolkitAuthorizationResult *result;
380 GError *error;
381 gboolean is_authorized;
382
383 is_authorized = FALSE;
384
385 error = NULL;
386 result = polkit_authority_check_authorization_finish (authority,
387 res,
388 &error);
389 if (error != NULL) {
390 g_debug ("error checking action '%s'\n", error->message);
391 throw_error (data->context,
392 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
393 "Not Authorized: %s", error->message);
394 g_error_free (error);
395 }
396 else {
397 if (polkit_authorization_result_get_is_authorized (result)) {
398 g_debug ("result for '%s': authorized\n",
399 data->actions[data->id]);
400 is_authorized = TRUE;
401 }
402 else if (polkit_authorization_result_get_is_challenge (result)) {
403 g_debug ("result for '%s': challenge\n",
404 data->actions[data->id]);
405 throw_error (data->context,
406 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
407 "Authorization is required");
408 }
409 else {
410 g_debug ("result for '%s': not authorized\n",
411 data->actions[data->id]);
412 throw_error (data->context,
413 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
414 "Not Authorized");
415 }
416 }
417
418 if (is_authorized) {
419 data->id++;
420 if (data->actions[data->id] == NULL)
421 data->auth_obtained_callback (data->mechanism,
422 data->context,
423 data->user_data);
424 else {
425 check_next_action (data);
426 return; /* continue operation */
427 }
428 }
429
430 check_auth_data_free (data);
431 g_object_unref (result);
432 stop_operation ();
433}
434
435static void
436check_next_action (CheckAuthData *data)
437{
438 g_debug ("checking action '%s'\n", data->actions[data->id]);
439 polkit_authority_check_authorization (data->mechanism->priv->auth,
440 data->subject,
441 data->actions[data->id],
442 NULL,
443 data->flags,
444 NULL,
445 data->check_auth_callback,
446 data);
447}
448
449static void
450check_polkit_for_actions (GConfDefaults *mechanism,
451 DBusGMethodInvocation *context,
452 gchar **actions,
453 AuthObtainedCallback auth_obtained_callback,
454 gpointer user_data,
455 GDestroyNotify destroy)
456{
457 CheckAuthData *data;
458
459 data = g_new0 (CheckAuthData, 1);
460 data->mechanism = g_object_ref (mechanism);
461 data->context = context;
462 data->actions = actions;
463 data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
464 data->id = 0;
465 data->auth_obtained_callback = auth_obtained_callback;
466 data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback;
467 data->user_data = user_data;
468 data->destroy = destroy;
469 data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
470 data->challenge = FALSE;
471
472 check_next_action (data);
473}
474
475static char *
476gconf_address_for_caller (GConfDefaults *mechanism,
477 DBusGMethodInvocation *context,
478 GError **gerror)
479{
480 char *sender;
481 DBusConnection *conn;
482 uid_t uid;
483 struct passwd *pwd;
484 char *result;
485 DBusError error;
486
487 conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
488 sender = dbus_g_method_get_sender (context);
489
490 dbus_error_init (&error);
491 uid = dbus_bus_get_unix_user (conn, sender, &error);
492 g_free (sender);
493 if (uid == (unsigned)-1) {
494 dbus_set_g_error (gerror, &error);
495 dbus_error_free (&error);
496 return NULL;
497 }
498
499 pwd = getpwuid (uid);
500 if (pwd == NULL) {
501 g_set_error (gerror,
502 0, 0,
503 "Failed to get passwd information for uid %d", uid);
504 return NULL;
505 }
506
507 result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
508 return result;
509}
510
511static gboolean
512path_is_excluded (const char *path,
513 const char **excludes)
514{
515 int i;
516
517 for (i = 0; excludes && excludes[i]; i++) {
518 if (g_str_has_prefix (path, excludes[i]))
519 return TRUE;
520 }
521
522 return FALSE;
523}
524
525static void
526copy_tree (GConfClient *src,
527 const char *path,
528 GConfChangeSet *changes,
529 const char **excludes)
530{
531 GSList *list, *l;
532 GConfEntry *entry;
533
534 if (path_is_excluded (path, excludes))
535 return;
536
537 list = gconf_client_all_entries (src, path, NULL);
538 for (l = list; l; l = l->next) {
539 entry = l->data;
540 if (!path_is_excluded (entry->key, excludes))
541 gconf_change_set_set (changes, entry->key, entry->value);
542 }
543 g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
544 g_slist_free (list);
545
546 list = gconf_client_all_dirs (src, path, NULL);
547 for (l = list; l; l = l->next)
548 copy_tree (src, (const char *)l->data, changes, excludes);
549 g_slist_foreach (list, (GFunc)g_free, NULL);
550 g_slist_free (list);
551}
552
553static void
554copy_entry (GConfClient *src,
555 const char *path,
556 GConfChangeSet *changes,
557 const char **excludes)
558{
559 GConfValue *value;
560
561 if (path_is_excluded (path, excludes))
562 return;
563
564 value = gconf_client_get (src, path, NULL);
565 if (value) {
566 gconf_change_set_set (changes, path, value);
567 gconf_value_free (value);
568 }
569}
570
571typedef void (*ChangeSetCallback) (GConfDefaults *mechanism,
572 GConfChangeSet *changes,
573 gpointer data);
574
575typedef struct
576{
577 GConfDefaults *mechanism;
578 DBusGMethodInvocation *context;
579 const char *dest_address;
580 char **actions;
581 char **includes;
582 char **excludes;
583 GConfValue *value;
584 ChangeSetCallback changeset_callback;
585 gpointer user_data;
586 GDestroyNotify destroy;
587} CopyData;
588
589static void
590copy_data_free (gpointer user_data)
591{
592 CopyData *data = user_data;
593
594 g_object_unref (data->mechanism);
595 g_strfreev (data->includes);
596 g_strfreev (data->excludes);
597 g_strfreev (data->actions);
598 if (data->value)
599 gconf_value_free (data->value);
600 if (data->destroy)
601 data->destroy (data->user_data);
602 g_free (data);
603}
604
605static void
606do_copy_authorized (GConfDefaults *mechanism,
607 DBusGMethodInvocation *context,
608 gpointer user_data)
609{
610 CopyData *data = user_data;
611 GConfClient *source = NULL;
612 GConfClient *dest = NULL;
613 GConfChangeSet *changes = NULL;
614 GConfEngine *engine;
615 char *address = NULL;
616 gint i;
617 GError *error;
618
619 error = NULL;
620 engine = gconf_engine_get_local (data->dest_address, &error);
621 if (error)
622 goto cleanup;
623
624 dest = gconf_client_get_for_engine (engine);
625 gconf_engine_unref (engine);
626
627 /* find the address to from the caller id */
628 address = gconf_address_for_caller (data->mechanism, data->context, &error);
629 if (error)
630 goto cleanup;
631
632 engine = gconf_engine_get_local (address, &error);
633 if (error)
634 goto cleanup;
635
636 source = gconf_client_get_for_engine (engine);
637 gconf_engine_unref (engine);
638
639 changes = gconf_change_set_new ();
640
641 if (data->value) {
642 g_assert (data->includes[1] == NULL);
643 g_assert (data->excludes == NULL);
644
645 gconf_change_set_set (changes, data->includes[0], data->value);
646 }
647 else {
648 /* recursively copy each include, leaving out the excludes */
649 for (i = 0; data->includes[i]; i++) {
650 if (gconf_client_dir_exists (source, data->includes[i], NULL))
651 copy_tree (source, data->includes[i], changes, (const char **)data->excludes);
652 else
653 copy_entry (source, data->includes[i], changes, (const char **)data->excludes);
654 }
655 }
656
657 gconf_client_commit_change_set (dest, changes, FALSE, &error);
658 gconf_client_suggest_sync (dest, NULL);
659
660 if (data->changeset_callback) {
661 data->changeset_callback (data->mechanism, changes, data->user_data);
662 }
663
664cleanup:
665 g_free (address);
666 if (changes)
667 gconf_change_set_unref (changes);
668 if (dest)
669 g_object_unref (dest);
670 if (source)
671 g_object_unref (source);
672
673 if (error) {
674 throw_error (data->context,
675 GCONF_DEFAULTS_ERROR_GENERAL,
676 "%s", error->message);
677 g_error_free (error);
678 }
679 else
680 dbus_g_method_return (data->context);
681}
682
683typedef void (*ActionsReadyCallback) (GConfDefaults *mechanism,
684 DBusGMethodInvocation *context,
685 gchar **actions,
686 AuthObtainedCallback auth_obtained_callback,
687 gpointer data,
688 GDestroyNotify destroy);
689
690typedef struct
691{
692 GConfDefaults *mechanism;
693 DBusGMethodInvocation *context;
694 char **includes;
695 const char *default_action;
696 const char *annotation_key;
697 ActionsReadyCallback actions_ready_callback;
698 AuthObtainedCallback auth_obtained_callback;
699 gpointer data;
700 GDestroyNotify destroy;
701} ActionData;
702
703static void
704action_data_free (ActionData *data)
705{
706 g_object_unref (data->mechanism);
707 g_strfreev (data->includes);
708 if (data->destroy)
709 data->destroy (data->data);
710 g_free (data);
711}
712
713static void
714actions_ready_cb (GObject *source,
715 GAsyncResult *res,
716 gpointer user_data)
717{
718 ActionData *data = user_data;
719 GList *action_descriptions;
720 GError *error = NULL;
721 int i;
722 GHashTable *obtained;
723 GHashTableIter iter;
724 const gchar *action;
725 gchar **actions;
726 gpointer key, value;
727
728 action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error);
729
730 if (error) {
731 throw_error (data->context,
732 GCONF_DEFAULTS_ERROR_GENERAL,
733 "Failed to get action descriptions: %s", error->message);
734 g_error_free (error);
735 action_data_free (data);
736 stop_operation ();
737 return;
738 }
739
740 obtained = g_hash_table_new (g_str_hash, g_str_equal);
741
742 for (i = 0; data->includes[i]; i++) {
743 action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]);
744 if (action == NULL) {
745 g_debug ("using default action '%s' for path '%s'",
746 data->default_action, data->includes[i]);
747 action = data->default_action;
748 }
749
750 g_hash_table_insert (obtained, (gpointer)action, (gpointer)action);
751 }
752 actions = g_new0 (char *, g_hash_table_size (obtained) + 1);
753 g_hash_table_iter_init (&iter, obtained);
754 i = 0;
755 while (g_hash_table_iter_next (&iter, &key, &value)) {
756 actions[i] = g_strdup ((char *)key);
757 i++;
758 }
759 g_hash_table_destroy (obtained);
760 g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL);
761 g_list_free (action_descriptions);
762
763 data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy);
764
765 data->destroy = NULL;
766 action_data_free (data);
767}
768
769static void
770do_copy (GConfDefaults *mechanism,
771 gboolean mandatory,
772 const gchar **includes,
773 const gchar **excludes,
774 GConfValue *value,
775 DBusGMethodInvocation *context,
776 ChangeSetCallback changeset_callback,
777 gpointer user_data,
778 GDestroyNotify destroy)
779{
780 CopyData *cdata;
781 ActionData *adata;
782
783 start_operation ();
784
785 cdata = g_new0 (CopyData, 1);
786 cdata->mechanism = g_object_ref (mechanism);
787 cdata->context = context;
788 cdata->includes = g_strdupv ((gchar **)includes);
789 cdata->excludes = g_strdupv ((gchar **)excludes);
790 cdata->value = value;
791 cdata->actions = NULL;
792 cdata->changeset_callback = changeset_callback;
793 cdata->user_data = user_data;
794 cdata->destroy = destroy;
795
796 adata = g_new0 (ActionData, 1);
797 adata->mechanism = g_object_ref (mechanism);
798 adata->context = context;
799 adata->includes = g_strdupv ((gchar **)includes);
800 adata->actions_ready_callback = check_polkit_for_actions;
801 adata->auth_obtained_callback = do_copy_authorized;
802 adata->data = cdata;
803 adata->destroy = copy_data_free;
804
805 /* check privileges for each include */
806 if (mandatory) {
807 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
808 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
809 cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory";
810 }
811 else {
812 adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
813 adata->default_action = "org.gnome.gconf.defaults.set-system";
814 cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system";
815 }
816
817 polkit_authority_enumerate_actions (mechanism->priv->auth,
818 NULL,
819 actions_ready_cb,
820 adata);
821}
822
823static void
824append_key (GConfChangeSet *cs,
825 const gchar *key,
826 GConfValue *value,
827 gpointer user_data)
828{
829 GPtrArray *keys = (GPtrArray *) user_data;
830
831 g_ptr_array_add (keys, (gpointer) key);
832}
833
834static void
835set_system_changes (GConfDefaults *mechanism,
836 GConfChangeSet *changes,
837 gpointer data)
838{
839 GPtrArray *keys;
840
841 keys = g_ptr_array_new ();
842 gconf_change_set_foreach (changes, append_key, keys);
843 g_ptr_array_add (keys, NULL);
844
845 g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
846
847 g_ptr_array_free (keys, TRUE);
848}
849
850void
851gconf_defaults_set_system (GConfDefaults *mechanism,
852 const char **includes,
853 const char **excludes,
854 DBusGMethodInvocation *context)
855{
856 do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL);
857}
858
859void
860gconf_defaults_set_mandatory (GConfDefaults *mechanism,
861 const char **includes,
862 const char **excludes,
863 DBusGMethodInvocation *context)
864{
865 do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL);
866}
867
868static void
869unset_tree (GConfClient *dest,
870 const char *path,
871 GConfChangeSet *changes,
872 const char **excludes)
873{
874 GSList *list, *l;
875 GConfEntry *entry;
876
877 if (path_is_excluded (path, excludes))
878 return;
879
880 list = gconf_client_all_entries (dest, path, NULL);
881 for (l = list; l; l = l->next) {
882 entry = l->data;
883 if (!path_is_excluded (entry->key, excludes))
884 gconf_change_set_unset (changes, entry->key);
885 }
886 g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
887 g_slist_free (list);
888
889 list = gconf_client_all_dirs (dest, path, NULL);
890 for (l = list; l; l = l->next)
891 unset_tree (dest, (const char *)l->data, changes, excludes);
892 g_slist_foreach (list, (GFunc)g_free, NULL);
893 g_slist_free (list);
894}
895
896static void
897unset_entry (GConfClient *dest,
898 const char *path,
899 GConfChangeSet *changes,
900 const char **excludes)
901{
902 if (path_is_excluded (path, excludes))
903 return;
904
905 gconf_change_set_unset (changes, path);
906}
907
908static void
909unset_in_db (GConfDefaults *mechanism,
910 const gchar *address,
911 const gchar **includes,
912 const gchar **excludes,
913 GError **error)
914{
915 GConfEngine *engine;
916 GConfClient *dest = NULL;
917 GConfChangeSet *changes = NULL;
918 int i;
919
920 engine = gconf_engine_get_local (address, error);
921 if (*error)
922 goto out;
923
924 dest = gconf_client_get_for_engine (engine);
925 gconf_engine_unref (engine);
926
927 changes = gconf_change_set_new ();
928
929 /* recursively copy each include, leaving out the excludes */
930 for (i = 0; includes[i]; i++) {
931 if (gconf_client_dir_exists (dest, includes[i], NULL))
932 unset_tree (dest, includes[i], changes, excludes);
933 else
934 unset_entry (dest, includes[i], changes, excludes);
935 }
936
937 gconf_client_commit_change_set (dest, changes, TRUE, error);
938 gconf_client_suggest_sync (dest, NULL);
939
940out:
941 if (dest)
942 g_object_unref (dest);
943 if (changes)
944 gconf_change_set_unref (changes);
945}
946
947typedef struct
948{
949 GConfDefaults *mechanism;
950 DBusGMethodInvocation *context;
951 char **includes;
952 char **excludes;
953} UnsetData;
954
955static void
956unset_data_free (gpointer user_data)
957{
958 UnsetData *data = user_data;
959
960 g_object_unref (data->mechanism);
961 g_strfreev (data->includes);
962 g_strfreev (data->excludes);
963 g_free (data);
964}
965
966static void
967do_unset_authorized (GConfDefaults *mechanism,
968 DBusGMethodInvocation *context,
969 gpointer user_data)
970{
971 UnsetData *data = user_data;
972 GError *error;
973
974 error = NULL;
975 unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory",
976 (const gchar **)data->includes,
977 (const gchar **)data->excludes, &error);
978
979 if (error) {
980 throw_error (data->context,
981 GCONF_DEFAULTS_ERROR,
982 GCONF_DEFAULTS_ERROR_GENERAL,
983 "%s", error->message);
984 g_error_free (error);
985 }
986 else
987 dbus_g_method_return (data->context);
988}
989
990void
991gconf_defaults_unset_mandatory (GConfDefaults *mechanism,
992 const char **includes,
993 const char **excludes,
994 DBusGMethodInvocation *context)
995{
996 UnsetData *udata;
997 ActionData *adata;
998
999 start_operation ();
1000
1001 udata = g_new0 (UnsetData, 1);
1002 udata->mechanism = g_object_ref (mechanism);
1003 udata->context = context;
1004 udata->includes = g_strdupv ((gchar **)includes);
1005 udata->excludes = g_strdupv ((gchar **)excludes);
1006
1007 adata = g_new0 (ActionData, 1);
1008 adata->mechanism = g_object_ref (mechanism);
1009 adata->context = context;
1010 adata->includes = g_strdupv ((gchar **)includes);
1011 adata->auth_obtained_callback = do_unset_authorized;
1012 adata->data = udata;
1013 adata->destroy = unset_data_free;
1014
1015 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1016 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1017
1018 polkit_authority_enumerate_actions (mechanism->priv->auth,
1019 NULL,
1020 actions_ready_cb,
1021 adata);
1022}
1023
1024static void
1025check_authorization_only_callback (PolkitAuthority *authority,
1026 GAsyncResult *res,
1027 gpointer user_data)
1028{
1029 CheckAuthData *data = user_data;
1030 PolkitAuthorizationResult *result;
1031 GError *error;
1032 gboolean is_authorized;
1033
1034 is_authorized = FALSE;
1035
1036 error = NULL;
1037 result = polkit_authority_check_authorization_finish (authority,
1038 res,
1039 &error);
1040 if (error != NULL) {
1041 g_debug ("error checking action '%s'\n", error->message);
1042 throw_error (data->context,
1043 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1044 "Not Authorized: %s", error->message);
1045 g_error_free (error);
1046 goto out;
1047 }
1048 else {
1049 if (polkit_authorization_result_get_is_authorized (result)) {
1050 g_debug ("result for '%s': authorized\n",
1051 data->actions[data->id]);
1052 is_authorized = TRUE;
1053 }
1054 else if (polkit_authorization_result_get_is_challenge (result)) {
1055 g_debug ("result for '%s': challenge\n",
1056 data->actions[data->id]);
1057 is_authorized = TRUE;
1058 data->challenge = TRUE;
1059 }
1060 else {
1061 g_debug ("result for '%s': not authorized\n",
1062 data->actions[data->id]);
1063 is_authorized = FALSE;
1064 }
1065 }
1066
1067 if (is_authorized) {
1068 data->id++;
1069 if (data->actions[data->id] == NULL) {
1070 gint result;
1071
1072 result = data->challenge ? 1 : 2;
1073 g_debug ("return %d\n", result);
1074 dbus_g_method_return (data->context, result);
1075 }
1076 else {
1077 check_next_action (data);
1078 return; /* continue operation */
1079 }
1080 }
1081 else {
1082 g_debug ("return 0\n");
1083 dbus_g_method_return (data->context, 0);
1084 }
1085
1086out:
1087 check_auth_data_free (data);
1088 g_object_unref (result);
1089 stop_operation ();
1090}
1091
1092static void
1093check_permissions_only (GConfDefaults *mechanism,
1094 DBusGMethodInvocation *context,
1095 gchar **actions,
1096 AuthObtainedCallback auth_obtained_callback,
1097 gpointer user_data,
1098 GDestroyNotify destroy)
1099{
1100 CheckAuthData *data;
1101
1102 data = g_new0 (CheckAuthData, 1);
1103 data->mechanism = g_object_ref (mechanism);
1104 data->context = context;
1105 data->actions = actions;
1106 data->flags = 0;
1107 data->id = 0;
1108 data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback;
1109 data->auth_obtained_callback = NULL;
1110 data->user_data = NULL;
1111 data->destroy = NULL;
1112 data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
1113 data->challenge = FALSE;
1114
1115 check_next_action (data);
1116}
1117
1118static void
1119do_check (GConfDefaults *mechanism,
1120 gboolean mandatory,
1121 const gchar **includes,
1122 DBusGMethodInvocation *context)
1123{
1124 ActionData *adata;
1125
1126 start_operation ();
1127
1128 adata = g_new0 (ActionData, 1);
1129 adata->mechanism = g_object_ref (mechanism);
1130 adata->context = context;
1131 adata->includes = g_strdupv ((gchar **)includes);
1132 adata->actions_ready_callback = check_permissions_only;
1133 adata->auth_obtained_callback = NULL;
1134 adata->data = NULL;
1135 adata->destroy = NULL;
1136
1137 if (mandatory) {
1138 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1139 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1140 }
1141 else {
1142 adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
1143 adata->default_action = "org.gnome.gconf.defaults.set-system";
1144 }
1145
1146 polkit_authority_enumerate_actions (mechanism->priv->auth,
1147 NULL,
1148 actions_ready_cb,
1149 adata);
1150}
1151
1152void
1153gconf_defaults_can_set_system (GConfDefaults *mechanism,
1154 const char **includes,
1155 DBusGMethodInvocation *context)
1156{
1157 do_check (mechanism, FALSE, includes, context);
1158}
1159
1160void
1161gconf_defaults_can_set_mandatory (GConfDefaults *mechanism,
1162 const char **includes,
1163 DBusGMethodInvocation *context)
1164{
1165 do_check (mechanism, TRUE, includes, context);
1166}
1167
1168void
1169gconf_defaults_set_system_value (GConfDefaults *mechanism,
1170 const char *path,
1171 const char *value,
1172 DBusGMethodInvocation *context)
1173{
1174 GConfValue *gvalue;
1175 const char *includes[] = { NULL, NULL };
1176
1177 gvalue = gconf_value_decode (value);
1178 if (gvalue) {
1179 includes[0] = path;
1180 do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL);
1181 }
1182}
1183
1184void
1185gconf_defaults_set_mandatory_value (GConfDefaults *mechanism,
1186 const char *path,
1187 const char *value,
1188 DBusGMethodInvocation *context)
1189{
1190 GConfValue *gvalue;
1191 const char *includes[] = { NULL, NULL };
1192
1193 gvalue = gconf_value_decode (value);
1194 if (gvalue) {
1195 includes[0] = path;
1196 do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL);
1197 }
1198}
1199
01200
=== removed file '.pc/01_defaults_path.patch/defaults/gconf-defaults.c'
--- .pc/01_defaults_path.patch/defaults/gconf-defaults.c 2010-12-06 00:53:14 +0000
+++ .pc/01_defaults_path.patch/defaults/gconf-defaults.c 1970-01-01 00:00:00 +0000
@@ -1,1199 +0,0 @@
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20
21#include <config.h>
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <string.h>
28#include <sys/wait.h>
29#include <errno.h>
30#include <sys/time.h>
31#include <sys/types.h>
32#include <pwd.h>
33
34#include <glib.h>
35#include <glib-object.h>
36
37#include <dbus/dbus-glib.h>
38#include <dbus/dbus-glib-lowlevel.h>
39
40#include <polkit/polkit.h>
41
42#define GCONF_ENABLE_INTERNALS
43#include <gconf/gconf-client.h>
44#include <gconf/gconf-engine.h>
45
46#include "gconf-defaults.h"
47#include "gconf-defaults-glue.h"
48
49static gboolean
50do_exit (gpointer user_data)
51{
52 g_debug ("Exiting due to inactivity");
53 exit (1);
54 return FALSE;
55}
56
57static guint timer_id = 0;
58gboolean disable_killtimer = FALSE;
59
60static void
61stop_killtimer (void)
62{
63 if (disable_killtimer)
64 return;
65
66 if (timer_id > 0) {
67 g_source_remove (timer_id);
68 timer_id = 0;
69 }
70}
71
72static void
73start_killtimer (void)
74{
75 if (disable_killtimer)
76 return;
77
78 if (timer_id == 0) {
79 g_debug ("Setting killtimer to 30 seconds...");
80 timer_id = g_timeout_add_seconds (30, do_exit, NULL);
81 }
82}
83
84static gint operations = 0;
85
86static void
87start_operation (void)
88{
89 if (operations == 0)
90 stop_killtimer ();
91 operations++;
92}
93
94static void
95stop_operation (void)
96{
97 if (operations == 1)
98 start_killtimer ();
99 operations --;
100}
101
102struct GConfDefaultsPrivate
103{
104 DBusGConnection *system_bus_connection;
105 DBusGProxy *system_bus_proxy;
106 PolkitAuthority *auth;
107};
108
109static void gconf_defaults_finalize (GObject *object);
110
111G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
112
113#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
114
115GQuark
116gconf_defaults_error_quark (void)
117{
118 static GQuark ret = 0;
119
120 if (ret == 0) {
121 ret = g_quark_from_static_string ("gconf_defaults_error");
122 }
123
124 return ret;
125}
126
127
128#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
129
130GType
131gconf_defaults_error_get_type (void)
132{
133 static GType etype = 0;
134
135 if (etype == 0)
136 {
137 static const GEnumValue values[] =
138 {
139 ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
140 ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
141 { 0, 0, 0 }
142 };
143
144 g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
145
146 etype = g_enum_register_static ("GConfDefaultsError", values);
147 }
148
149 return etype;
150}
151
152
153static GObject *
154gconf_defaults_constructor (GType type,
155 guint n_construct_properties,
156 GObjectConstructParam *construct_properties)
157{
158 GConfDefaults *mechanism;
159 GConfDefaultsClass *klass;
160
161 klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
162
163 mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
164 type,
165 n_construct_properties,
166 construct_properties));
167
168 return G_OBJECT (mechanism);
169}
170
171enum {
172 SYSTEM_SET,
173 LAST_SIGNAL
174};
175
176static guint signals[LAST_SIGNAL] = { 0 };
177
178static void
179gconf_defaults_class_init (GConfDefaultsClass *klass)
180{
181 GObjectClass *object_class = G_OBJECT_CLASS (klass);
182
183 object_class->constructor = gconf_defaults_constructor;
184 object_class->finalize = gconf_defaults_finalize;
185
186 signals[SYSTEM_SET] = g_signal_new ("system-set",
187 G_OBJECT_CLASS_TYPE (object_class),
188 G_SIGNAL_RUN_FIRST,
189 G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__BOXED,
192 G_TYPE_NONE, 1, G_TYPE_STRV);
193
194 g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
195
196 dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
197
198 dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
199
200}
201
202static void
203gconf_defaults_init (GConfDefaults *mechanism)
204{
205 mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
206}
207
208static void
209gconf_defaults_finalize (GObject *object)
210{
211 GConfDefaults *mechanism;
212
213 g_return_if_fail (object != NULL);
214 g_return_if_fail (GCONF_IS_DEFAULTS (object));
215
216 mechanism = GCONF_DEFAULTS (object);
217
218 g_return_if_fail (mechanism->priv != NULL);
219
220 g_object_unref (mechanism->priv->auth);
221 g_object_unref (mechanism->priv->system_bus_proxy);
222
223 G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
224}
225
226static gboolean
227register_mechanism (GConfDefaults *mechanism)
228{
229 GError *error = NULL;
230
231 mechanism->priv->auth = polkit_authority_get ();
232
233 error = NULL;
234 mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
235 if (mechanism->priv->system_bus_connection == NULL) {
236 if (error != NULL) {
237 g_critical ("error getting system bus: %s", error->message);
238 g_error_free (error);
239 }
240 goto error;
241 }
242
243 dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
244 G_OBJECT (mechanism));
245
246 mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
247 DBUS_SERVICE_DBUS,
248 DBUS_PATH_DBUS,
249 DBUS_INTERFACE_DBUS);
250
251 start_killtimer ();
252
253 return TRUE;
254
255error:
256 return FALSE;
257}
258
259
260GConfDefaults *
261gconf_defaults_new (void)
262{
263 GObject *object;
264 gboolean res;
265
266 object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
267
268 res = register_mechanism (GCONF_DEFAULTS (object));
269 if (! res) {
270 g_object_unref (object);
271 return NULL;
272 }
273
274 return GCONF_DEFAULTS (object);
275}
276
277static const char *
278polkit_action_for_gconf_path (GConfDefaults *mechanism,
279 GList *action_descriptions,
280 const char *annotation_key,
281 const char *path)
282{
283 char *prefix, *p;
284 const char *action;
285 GList *l;
286 PolkitActionDescription *action_description;
287 const gchar *annotation;
288
289 g_debug ("finding action for path '%s'", path);
290 prefix = g_strdup (path);
291 while (1) {
292 for (l = action_descriptions; l; l = l->next) {
293 action_description = l->data;
294
295 annotation = polkit_action_description_get_annotation (action_description, annotation_key);
296 if (g_strcmp0 (prefix, annotation) == 0) {
297 action = polkit_action_description_get_action_id (action_description);
298 g_debug ("action for prefix '%s': '%s'\n", prefix, action);
299 goto found;
300 }
301 }
302
303 p = strrchr (prefix, '/');
304
305 if (p == NULL || p == prefix) {
306 action = NULL;
307 break;
308 }
309
310 *p = 0;
311 }
312
313 found:
314 g_free (prefix);
315
316 return action;
317}
318
319static void
320throw_error (DBusGMethodInvocation *context,
321 gint error_code,
322 const gchar *format,
323 ...)
324{
325 GError *error;
326 va_list args;
327 gchar *message;
328
329 va_start (args, format);
330 message = g_strdup_vprintf (format, args);
331 va_end (args);
332
333 error = g_error_new (GCONF_DEFAULTS_ERROR,
334 error_code,
335 "%s", message);
336 dbus_g_method_return_error (context, error);
337 g_error_free (error);
338 g_free (message);
339}
340
341typedef void (*AuthObtainedCallback) (GConfDefaults *mechanism,
342 DBusGMethodInvocation *context,
343 gpointer user_data);
344
345typedef struct
346{
347 GConfDefaults *mechanism;
348 DBusGMethodInvocation *context;
349 gchar **actions;
350 gint id;
351 gint flags;
352 AuthObtainedCallback auth_obtained_callback;
353 GAsyncReadyCallback check_auth_callback;
354 gpointer user_data;
355 GDestroyNotify destroy;
356 PolkitSubject *subject;
357 gboolean challenge;
358} CheckAuthData;
359
360static void
361check_auth_data_free (CheckAuthData *data)
362{
363 g_object_unref (data->mechanism);
364 g_strfreev (data->actions);
365 if (data->destroy)
366 data->destroy (data->user_data);
367 g_object_unref (data->subject);
368 g_free (data);
369}
370
371static void check_next_action (CheckAuthData *data);
372
373static void
374check_authorization_callback (PolkitAuthority *authority,
375 GAsyncResult *res,
376 gpointer user_data)
377{
378 CheckAuthData *data = user_data;
379 PolkitAuthorizationResult *result;
380 GError *error;
381 gboolean is_authorized;
382
383 is_authorized = FALSE;
384
385 error = NULL;
386 result = polkit_authority_check_authorization_finish (authority,
387 res,
388 &error);
389 if (error != NULL) {
390 g_debug ("error checking action '%s'\n", error->message);
391 throw_error (data->context,
392 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
393 "Not Authorized: %s", error->message);
394 g_error_free (error);
395 }
396 else {
397 if (polkit_authorization_result_get_is_authorized (result)) {
398 g_debug ("result for '%s': authorized\n",
399 data->actions[data->id]);
400 is_authorized = TRUE;
401 }
402 else if (polkit_authorization_result_get_is_challenge (result)) {
403 g_debug ("result for '%s': challenge\n",
404 data->actions[data->id]);
405 throw_error (data->context,
406 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
407 "Authorization is required");
408 }
409 else {
410 g_debug ("result for '%s': not authorized\n",
411 data->actions[data->id]);
412 throw_error (data->context,
413 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
414 "Not Authorized");
415 }
416 }
417
418 if (is_authorized) {
419 data->id++;
420 if (data->actions[data->id] == NULL)
421 data->auth_obtained_callback (data->mechanism,
422 data->context,
423 data->user_data);
424 else {
425 check_next_action (data);
426 return; /* continue operation */
427 }
428 }
429
430 check_auth_data_free (data);
431 g_object_unref (result);
432 stop_operation ();
433}
434
435static void
436check_next_action (CheckAuthData *data)
437{
438 g_debug ("checking action '%s'\n", data->actions[data->id]);
439 polkit_authority_check_authorization (data->mechanism->priv->auth,
440 data->subject,
441 data->actions[data->id],
442 NULL,
443 data->flags,
444 NULL,
445 data->check_auth_callback,
446 data);
447}
448
449static void
450check_polkit_for_actions (GConfDefaults *mechanism,
451 DBusGMethodInvocation *context,
452 gchar **actions,
453 AuthObtainedCallback auth_obtained_callback,
454 gpointer user_data,
455 GDestroyNotify destroy)
456{
457 CheckAuthData *data;
458
459 data = g_new0 (CheckAuthData, 1);
460 data->mechanism = g_object_ref (mechanism);
461 data->context = context;
462 data->actions = actions;
463 data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
464 data->id = 0;
465 data->auth_obtained_callback = auth_obtained_callback;
466 data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback;
467 data->user_data = user_data;
468 data->destroy = destroy;
469 data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
470 data->challenge = FALSE;
471
472 check_next_action (data);
473}
474
475static char *
476gconf_address_for_caller (GConfDefaults *mechanism,
477 DBusGMethodInvocation *context,
478 GError **gerror)
479{
480 char *sender;
481 DBusConnection *conn;
482 uid_t uid;
483 struct passwd *pwd;
484 char *result;
485 DBusError error;
486
487 conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
488 sender = dbus_g_method_get_sender (context);
489
490 dbus_error_init (&error);
491 uid = dbus_bus_get_unix_user (conn, sender, &error);
492 g_free (sender);
493 if (uid == (unsigned)-1) {
494 dbus_set_g_error (gerror, &error);
495 dbus_error_free (&error);
496 return NULL;
497 }
498
499 pwd = getpwuid (uid);
500 if (pwd == NULL) {
501 g_set_error (gerror,
502 0, 0,
503 "Failed to get passwd information for uid %d", uid);
504 return NULL;
505 }
506
507 result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
508 return result;
509}
510
511static gboolean
512path_is_excluded (const char *path,
513 const char **excludes)
514{
515 int i;
516
517 for (i = 0; excludes && excludes[i]; i++) {
518 if (g_str_has_prefix (path, excludes[i]))
519 return TRUE;
520 }
521
522 return FALSE;
523}
524
525static void
526copy_tree (GConfClient *src,
527 const char *path,
528 GConfChangeSet *changes,
529 const char **excludes)
530{
531 GSList *list, *l;
532 GConfEntry *entry;
533
534 if (path_is_excluded (path, excludes))
535 return;
536
537 list = gconf_client_all_entries (src, path, NULL);
538 for (l = list; l; l = l->next) {
539 entry = l->data;
540 if (!path_is_excluded (entry->key, excludes))
541 gconf_change_set_set (changes, entry->key, entry->value);
542 }
543 g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
544 g_slist_free (list);
545
546 list = gconf_client_all_dirs (src, path, NULL);
547 for (l = list; l; l = l->next)
548 copy_tree (src, (const char *)l->data, changes, excludes);
549 g_slist_foreach (list, (GFunc)g_free, NULL);
550 g_slist_free (list);
551}
552
553static void
554copy_entry (GConfClient *src,
555 const char *path,
556 GConfChangeSet *changes,
557 const char **excludes)
558{
559 GConfValue *value;
560
561 if (path_is_excluded (path, excludes))
562 return;
563
564 value = gconf_client_get (src, path, NULL);
565 if (value) {
566 gconf_change_set_set (changes, path, value);
567 gconf_value_free (value);
568 }
569}
570
571typedef void (*ChangeSetCallback) (GConfDefaults *mechanism,
572 GConfChangeSet *changes,
573 gpointer data);
574
575typedef struct
576{
577 GConfDefaults *mechanism;
578 DBusGMethodInvocation *context;
579 const char *dest_address;
580 char **actions;
581 char **includes;
582 char **excludes;
583 GConfValue *value;
584 ChangeSetCallback changeset_callback;
585 gpointer user_data;
586 GDestroyNotify destroy;
587} CopyData;
588
589static void
590copy_data_free (gpointer user_data)
591{
592 CopyData *data = user_data;
593
594 g_object_unref (data->mechanism);
595 g_strfreev (data->includes);
596 g_strfreev (data->excludes);
597 g_strfreev (data->actions);
598 if (data->value)
599 gconf_value_free (data->value);
600 if (data->destroy)
601 data->destroy (data->user_data);
602 g_free (data);
603}
604
605static void
606do_copy_authorized (GConfDefaults *mechanism,
607 DBusGMethodInvocation *context,
608 gpointer user_data)
609{
610 CopyData *data = user_data;
611 GConfClient *source = NULL;
612 GConfClient *dest = NULL;
613 GConfChangeSet *changes = NULL;
614 GConfEngine *engine;
615 char *address = NULL;
616 gint i;
617 GError *error;
618
619 error = NULL;
620 engine = gconf_engine_get_local (data->dest_address, &error);
621 if (error)
622 goto cleanup;
623
624 dest = gconf_client_get_for_engine (engine);
625 gconf_engine_unref (engine);
626
627 /* find the address to from the caller id */
628 address = gconf_address_for_caller (data->mechanism, data->context, &error);
629 if (error)
630 goto cleanup;
631
632 engine = gconf_engine_get_local (address, &error);
633 if (error)
634 goto cleanup;
635
636 source = gconf_client_get_for_engine (engine);
637 gconf_engine_unref (engine);
638
639 changes = gconf_change_set_new ();
640
641 if (data->value) {
642 g_assert (data->includes[1] == NULL);
643 g_assert (data->excludes == NULL);
644
645 gconf_change_set_set (changes, data->includes[0], data->value);
646 }
647 else {
648 /* recursively copy each include, leaving out the excludes */
649 for (i = 0; data->includes[i]; i++) {
650 if (gconf_client_dir_exists (source, data->includes[i], NULL))
651 copy_tree (source, data->includes[i], changes, (const char **)data->excludes);
652 else
653 copy_entry (source, data->includes[i], changes, (const char **)data->excludes);
654 }
655 }
656
657 gconf_client_commit_change_set (dest, changes, FALSE, &error);
658 gconf_client_suggest_sync (dest, NULL);
659
660 if (data->changeset_callback) {
661 data->changeset_callback (data->mechanism, changes, data->user_data);
662 }
663
664cleanup:
665 g_free (address);
666 if (changes)
667 gconf_change_set_unref (changes);
668 if (dest)
669 g_object_unref (dest);
670 if (source)
671 g_object_unref (source);
672
673 if (error) {
674 throw_error (data->context,
675 GCONF_DEFAULTS_ERROR_GENERAL,
676 "%s", error->message);
677 g_error_free (error);
678 }
679 else
680 dbus_g_method_return (data->context);
681}
682
683typedef void (*ActionsReadyCallback) (GConfDefaults *mechanism,
684 DBusGMethodInvocation *context,
685 gchar **actions,
686 AuthObtainedCallback auth_obtained_callback,
687 gpointer data,
688 GDestroyNotify destroy);
689
690typedef struct
691{
692 GConfDefaults *mechanism;
693 DBusGMethodInvocation *context;
694 char **includes;
695 const char *default_action;
696 const char *annotation_key;
697 ActionsReadyCallback actions_ready_callback;
698 AuthObtainedCallback auth_obtained_callback;
699 gpointer data;
700 GDestroyNotify destroy;
701} ActionData;
702
703static void
704action_data_free (ActionData *data)
705{
706 g_object_unref (data->mechanism);
707 g_strfreev (data->includes);
708 if (data->destroy)
709 data->destroy (data->data);
710 g_free (data);
711}
712
713static void
714actions_ready_cb (GObject *source,
715 GAsyncResult *res,
716 gpointer user_data)
717{
718 ActionData *data = user_data;
719 GList *action_descriptions;
720 GError *error = NULL;
721 int i;
722 GHashTable *obtained;
723 GHashTableIter iter;
724 const gchar *action;
725 gchar **actions;
726 gpointer key, value;
727
728 action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error);
729
730 if (error) {
731 throw_error (data->context,
732 GCONF_DEFAULTS_ERROR_GENERAL,
733 "Failed to get action descriptions: %s", error->message);
734 g_error_free (error);
735 action_data_free (data);
736 stop_operation ();
737 return;
738 }
739
740 obtained = g_hash_table_new (g_str_hash, g_str_equal);
741
742 for (i = 0; data->includes[i]; i++) {
743 action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]);
744 if (action == NULL) {
745 g_debug ("using default action '%s' for path '%s'",
746 data->default_action, data->includes[i]);
747 action = data->default_action;
748 }
749
750 g_hash_table_insert (obtained, (gpointer)action, (gpointer)action);
751 }
752 actions = g_new0 (char *, g_hash_table_size (obtained) + 1);
753 g_hash_table_iter_init (&iter, obtained);
754 i = 0;
755 while (g_hash_table_iter_next (&iter, &key, &value)) {
756 actions[i] = g_strdup ((char *)key);
757 i++;
758 }
759 g_hash_table_destroy (obtained);
760 g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL);
761 g_list_free (action_descriptions);
762
763 data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy);
764
765 data->destroy = NULL;
766 action_data_free (data);
767}
768
769static void
770do_copy (GConfDefaults *mechanism,
771 gboolean mandatory,
772 const gchar **includes,
773 const gchar **excludes,
774 GConfValue *value,
775 DBusGMethodInvocation *context,
776 ChangeSetCallback changeset_callback,
777 gpointer user_data,
778 GDestroyNotify destroy)
779{
780 CopyData *cdata;
781 ActionData *adata;
782
783 start_operation ();
784
785 cdata = g_new0 (CopyData, 1);
786 cdata->mechanism = g_object_ref (mechanism);
787 cdata->context = context;
788 cdata->includes = g_strdupv ((gchar **)includes);
789 cdata->excludes = g_strdupv ((gchar **)excludes);
790 cdata->value = value;
791 cdata->actions = NULL;
792 cdata->changeset_callback = changeset_callback;
793 cdata->user_data = user_data;
794 cdata->destroy = destroy;
795
796 adata = g_new0 (ActionData, 1);
797 adata->mechanism = g_object_ref (mechanism);
798 adata->context = context;
799 adata->includes = g_strdupv ((gchar **)includes);
800 adata->actions_ready_callback = check_polkit_for_actions;
801 adata->auth_obtained_callback = do_copy_authorized;
802 adata->data = cdata;
803 adata->destroy = copy_data_free;
804
805 /* check privileges for each include */
806 if (mandatory) {
807 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
808 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
809 cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory";
810 }
811 else {
812 adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
813 adata->default_action = "org.gnome.gconf.defaults.set-system";
814 cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system";
815 }
816
817 polkit_authority_enumerate_actions (mechanism->priv->auth,
818 NULL,
819 actions_ready_cb,
820 adata);
821}
822
823static void
824append_key (GConfChangeSet *cs,
825 const gchar *key,
826 GConfValue *value,
827 gpointer user_data)
828{
829 GPtrArray *keys = (GPtrArray *) user_data;
830
831 g_ptr_array_add (keys, (gpointer) key);
832}
833
834static void
835set_system_changes (GConfDefaults *mechanism,
836 GConfChangeSet *changes,
837 gpointer data)
838{
839 GPtrArray *keys;
840
841 keys = g_ptr_array_new ();
842 gconf_change_set_foreach (changes, append_key, keys);
843 g_ptr_array_add (keys, NULL);
844
845 g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
846
847 g_ptr_array_free (keys, TRUE);
848}
849
850void
851gconf_defaults_set_system (GConfDefaults *mechanism,
852 const char **includes,
853 const char **excludes,
854 DBusGMethodInvocation *context)
855{
856 do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL);
857}
858
859void
860gconf_defaults_set_mandatory (GConfDefaults *mechanism,
861 const char **includes,
862 const char **excludes,
863 DBusGMethodInvocation *context)
864{
865 do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL);
866}
867
868static void
869unset_tree (GConfClient *dest,
870 const char *path,
871 GConfChangeSet *changes,
872 const char **excludes)
873{
874 GSList *list, *l;
875 GConfEntry *entry;
876
877 if (path_is_excluded (path, excludes))
878 return;
879
880 list = gconf_client_all_entries (dest, path, NULL);
881 for (l = list; l; l = l->next) {
882 entry = l->data;
883 if (!path_is_excluded (entry->key, excludes))
884 gconf_change_set_unset (changes, entry->key);
885 }
886 g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
887 g_slist_free (list);
888
889 list = gconf_client_all_dirs (dest, path, NULL);
890 for (l = list; l; l = l->next)
891 unset_tree (dest, (const char *)l->data, changes, excludes);
892 g_slist_foreach (list, (GFunc)g_free, NULL);
893 g_slist_free (list);
894}
895
896static void
897unset_entry (GConfClient *dest,
898 const char *path,
899 GConfChangeSet *changes,
900 const char **excludes)
901{
902 if (path_is_excluded (path, excludes))
903 return;
904
905 gconf_change_set_unset (changes, path);
906}
907
908static void
909unset_in_db (GConfDefaults *mechanism,
910 const gchar *address,
911 const gchar **includes,
912 const gchar **excludes,
913 GError **error)
914{
915 GConfEngine *engine;
916 GConfClient *dest = NULL;
917 GConfChangeSet *changes = NULL;
918 int i;
919
920 engine = gconf_engine_get_local (address, error);
921 if (*error)
922 goto out;
923
924 dest = gconf_client_get_for_engine (engine);
925 gconf_engine_unref (engine);
926
927 changes = gconf_change_set_new ();
928
929 /* recursively copy each include, leaving out the excludes */
930 for (i = 0; includes[i]; i++) {
931 if (gconf_client_dir_exists (dest, includes[i], NULL))
932 unset_tree (dest, includes[i], changes, excludes);
933 else
934 unset_entry (dest, includes[i], changes, excludes);
935 }
936
937 gconf_client_commit_change_set (dest, changes, TRUE, error);
938 gconf_client_suggest_sync (dest, NULL);
939
940out:
941 if (dest)
942 g_object_unref (dest);
943 if (changes)
944 gconf_change_set_unref (changes);
945}
946
947typedef struct
948{
949 GConfDefaults *mechanism;
950 DBusGMethodInvocation *context;
951 char **includes;
952 char **excludes;
953} UnsetData;
954
955static void
956unset_data_free (gpointer user_data)
957{
958 UnsetData *data = user_data;
959
960 g_object_unref (data->mechanism);
961 g_strfreev (data->includes);
962 g_strfreev (data->excludes);
963 g_free (data);
964}
965
966static void
967do_unset_authorized (GConfDefaults *mechanism,
968 DBusGMethodInvocation *context,
969 gpointer user_data)
970{
971 UnsetData *data = user_data;
972 GError *error;
973
974 error = NULL;
975 unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory",
976 (const gchar **)data->includes,
977 (const gchar **)data->excludes, &error);
978
979 if (error) {
980 throw_error (data->context,
981 GCONF_DEFAULTS_ERROR,
982 GCONF_DEFAULTS_ERROR_GENERAL,
983 "%s", error->message);
984 g_error_free (error);
985 }
986 else
987 dbus_g_method_return (data->context);
988}
989
990void
991gconf_defaults_unset_mandatory (GConfDefaults *mechanism,
992 const char **includes,
993 const char **excludes,
994 DBusGMethodInvocation *context)
995{
996 UnsetData *udata;
997 ActionData *adata;
998
999 start_operation ();
1000
1001 udata = g_new0 (UnsetData, 1);
1002 udata->mechanism = g_object_ref (mechanism);
1003 udata->context = context;
1004 udata->includes = g_strdupv ((gchar **)includes);
1005 udata->excludes = g_strdupv ((gchar **)excludes);
1006
1007 adata = g_new0 (ActionData, 1);
1008 adata->mechanism = g_object_ref (mechanism);
1009 adata->context = context;
1010 adata->includes = g_strdupv ((gchar **)includes);
1011 adata->auth_obtained_callback = do_unset_authorized;
1012 adata->data = udata;
1013 adata->destroy = unset_data_free;
1014
1015 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1016 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1017
1018 polkit_authority_enumerate_actions (mechanism->priv->auth,
1019 NULL,
1020 actions_ready_cb,
1021 adata);
1022}
1023
1024static void
1025check_authorization_only_callback (PolkitAuthority *authority,
1026 GAsyncResult *res,
1027 gpointer user_data)
1028{
1029 CheckAuthData *data = user_data;
1030 PolkitAuthorizationResult *result;
1031 GError *error;
1032 gboolean is_authorized;
1033
1034 is_authorized = FALSE;
1035
1036 error = NULL;
1037 result = polkit_authority_check_authorization_finish (authority,
1038 res,
1039 &error);
1040 if (error != NULL) {
1041 g_debug ("error checking action '%s'\n", error->message);
1042 throw_error (data->context,
1043 GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
1044 "Not Authorized: %s", error->message);
1045 g_error_free (error);
1046 goto out;
1047 }
1048 else {
1049 if (polkit_authorization_result_get_is_authorized (result)) {
1050 g_debug ("result for '%s': authorized\n",
1051 data->actions[data->id]);
1052 is_authorized = TRUE;
1053 }
1054 else if (polkit_authorization_result_get_is_challenge (result)) {
1055 g_debug ("result for '%s': challenge\n",
1056 data->actions[data->id]);
1057 is_authorized = TRUE;
1058 data->challenge = TRUE;
1059 }
1060 else {
1061 g_debug ("result for '%s': not authorized\n",
1062 data->actions[data->id]);
1063 is_authorized = FALSE;
1064 }
1065 }
1066
1067 if (is_authorized) {
1068 data->id++;
1069 if (data->actions[data->id] == NULL) {
1070 gint result;
1071
1072 result = data->challenge ? 1 : 2;
1073 g_debug ("return %d\n", result);
1074 dbus_g_method_return (data->context, result);
1075 }
1076 else {
1077 check_next_action (data);
1078 return; /* continue operation */
1079 }
1080 }
1081 else {
1082 g_debug ("return 0\n");
1083 dbus_g_method_return (data->context, 0);
1084 }
1085
1086out:
1087 check_auth_data_free (data);
1088 g_object_unref (result);
1089 stop_operation ();
1090}
1091
1092static void
1093check_permissions_only (GConfDefaults *mechanism,
1094 DBusGMethodInvocation *context,
1095 gchar **actions,
1096 AuthObtainedCallback auth_obtained_callback,
1097 gpointer user_data,
1098 GDestroyNotify destroy)
1099{
1100 CheckAuthData *data;
1101
1102 data = g_new0 (CheckAuthData, 1);
1103 data->mechanism = g_object_ref (mechanism);
1104 data->context = context;
1105 data->actions = actions;
1106 data->flags = 0;
1107 data->id = 0;
1108 data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback;
1109 data->auth_obtained_callback = NULL;
1110 data->user_data = NULL;
1111 data->destroy = NULL;
1112 data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
1113 data->challenge = FALSE;
1114
1115 check_next_action (data);
1116}
1117
1118static void
1119do_check (GConfDefaults *mechanism,
1120 gboolean mandatory,
1121 const gchar **includes,
1122 DBusGMethodInvocation *context)
1123{
1124 ActionData *adata;
1125
1126 start_operation ();
1127
1128 adata = g_new0 (ActionData, 1);
1129 adata->mechanism = g_object_ref (mechanism);
1130 adata->context = context;
1131 adata->includes = g_strdupv ((gchar **)includes);
1132 adata->actions_ready_callback = check_permissions_only;
1133 adata->auth_obtained_callback = NULL;
1134 adata->data = NULL;
1135 adata->destroy = NULL;
1136
1137 if (mandatory) {
1138 adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
1139 adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
1140 }
1141 else {
1142 adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
1143 adata->default_action = "org.gnome.gconf.defaults.set-system";
1144 }
1145
1146 polkit_authority_enumerate_actions (mechanism->priv->auth,
1147 NULL,
1148 actions_ready_cb,
1149 adata);
1150}
1151
1152void
1153gconf_defaults_can_set_system (GConfDefaults *mechanism,
1154 const char **includes,
1155 DBusGMethodInvocation *context)
1156{
1157 do_check (mechanism, FALSE, includes, context);
1158}
1159
1160void
1161gconf_defaults_can_set_mandatory (GConfDefaults *mechanism,
1162 const char **includes,
1163 DBusGMethodInvocation *context)
1164{
1165 do_check (mechanism, TRUE, includes, context);
1166}
1167
1168void
1169gconf_defaults_set_system_value (GConfDefaults *mechanism,
1170 const char *path,
1171 const char *value,
1172 DBusGMethodInvocation *context)
1173{
1174 GConfValue *gvalue;
1175 const char *includes[] = { NULL, NULL };
1176
1177 gvalue = gconf_value_decode (value);
1178 if (gvalue) {
1179 includes[0] = path;
1180 do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL);
1181 }
1182}
1183
1184void
1185gconf_defaults_set_mandatory_value (GConfDefaults *mechanism,
1186 const char *path,
1187 const char *value,
1188 DBusGMethodInvocation *context)
1189{
1190 GConfValue *gvalue;
1191 const char *includes[] = { NULL, NULL };
1192
1193 gvalue = gconf_value_decode (value);
1194 if (gvalue) {
1195 includes[0] = path;
1196 do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL);
1197 }
1198}
1199
12000
=== added directory '.pc/01_defaults_path.patch/gconf'
=== removed directory '.pc/01_defaults_path.patch/gconf'
=== added file '.pc/01_defaults_path.patch/gconf/gconfd.c'
--- .pc/01_defaults_path.patch/gconf/gconfd.c 1970-01-01 00:00:00 +0000
+++ .pc/01_defaults_path.patch/gconf/gconfd.c 2012-03-06 01:10:25 +0000
@@ -0,0 +1,2847 @@
1/* GConf
2 * Copyright (C) 1999, 2000 Red Hat Inc.
3 * Developed by Havoc Pennington, some code in here borrowed from
4 * gnome-name-server and libgnorba (Elliot Lee)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22
23/*
24 * This is the per-user configuration daemon.
25 * (has debug crap in it now)
26 */
27
28#include <config.h>
29
30#include "gconf-internals.h"
31#include "gconf-sources.h"
32#include "gconf-listeners.h"
33#include "gconf-locale.h"
34#include "gconf-schema.h"
35#include "gconf.h"
36#include "gconfd.h"
37#include "gconf-database.h"
38
39#ifdef HAVE_DBUS
40#include "gconf-database-dbus.h"
41#include "gconfd-dbus.h"
42#endif
43
44#ifdef HAVE_CORBA
45#include <orbit/orbit.h>
46
47#include "GConfX.h"
48#endif
49
50#include <sys/types.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <signal.h>
55#include <unistd.h>
56#include <sys/stat.h>
57#include <fcntl.h>
58#include <errno.h>
59#include <ctype.h>
60#include <time.h>
61#ifdef HAVE_SYS_WAIT_H
62#include <sys/wait.h>
63#endif
64#include <locale.h>
65
66#include <dbus/dbus-glib-lowlevel.h>
67
68#ifdef G_OS_WIN32
69#include <io.h>
70#include <conio.h>
71#define _WIN32_WINNT 0x0500
72#include <windows.h>
73
74static int
75fsync (int fd)
76{
77 HANDLE h = (HANDLE) _get_osfhandle (fd);
78 DWORD err;
79
80 if (h == INVALID_HANDLE_VALUE)
81 {
82 errno = EBADF;
83 return -1;
84 }
85
86 if (!FlushFileBuffers (h))
87 {
88 err = GetLastError ();
89 switch (err)
90 {
91 case ERROR_INVALID_HANDLE:
92 errno = EINVAL;
93 break;
94
95 default:
96 errno = EIO;
97 }
98 return -1;
99 }
100
101 return 0;
102}
103#endif
104
105/* This makes hash table safer when debugging */
106#ifndef GCONF_ENABLE_DEBUG
107#define safe_g_hash_table_insert g_hash_table_insert
108#else
109static void
110safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
111{
112 gpointer oldkey = NULL, oldval = NULL;
113
114 if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
115 {
116 gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
117 (gchar*) key);
118 return;
119 }
120 else
121 {
122 g_hash_table_insert(ht, key, value);
123 }
124}
125#endif
126
127/*
128 * Declarations
129 */
130
131static void gconf_main (void);
132static gboolean gconf_main_is_running (void);
133
134#ifdef HAVE_CORBA
135static void logfile_save (void);
136static void logfile_read (void);
137static void log_client_add (const ConfigListener client);
138static void log_client_remove (const ConfigListener client);
139
140static void add_client (const ConfigListener client);
141static void remove_client (const ConfigListener client);
142static GSList *list_clients (void);
143static void log_clients_to_string (GString *str);
144static void drop_old_clients (void);
145static guint client_count (void);
146#endif
147
148static void enter_shutdown (void);
149
150static void init_databases (void);
151static void shutdown_databases (void);
152#ifdef HAVE_DBUS
153static void reload_databases (void);
154#endif
155static void set_default_database (GConfDatabase* db);
156static void register_database (GConfDatabase* db);
157static void unregister_database (GConfDatabase* db);
158static GConfDatabase* lookup_database (GSList *addresses);
159static void drop_old_databases (void);
160static gboolean no_databases_in_use (void);
161
162/*
163 * Flag indicating that we are shutting down, so return errors
164 * on any attempted operation. We do this instead of unregistering with
165 * OAF or deactivating the server object, because we want to avoid
166 * another gconfd starting up before we finish shutting down.
167 */
168
169static gboolean in_shutdown = FALSE;
170
171/*
172 * Flag indicating we received a SIGHUP and we should reaload
173 * all sources during the next periodic_cleanup()
174 */
175static gboolean need_db_reload = FALSE;
176
177#ifdef HAVE_CORBA
178/*
179 * CORBA goo
180 */
181
182static ConfigServer2 server = CORBA_OBJECT_NIL;
183static PortableServer_POA the_poa;
184static GConfLock *daemon_lock = NULL;
185
186static ConfigDatabase
187gconfd_get_default_database(PortableServer_Servant servant,
188 CORBA_Environment* ev);
189
190static ConfigDatabase
191gconfd_get_database(PortableServer_Servant servant,
192 const CORBA_char* address,
193 CORBA_Environment* ev);
194
195static ConfigDatabase
196gconfd_get_database_for_addresses (PortableServer_Servant servant,
197 const ConfigServer2_AddressList *addresses,
198 CORBA_Environment *ev);
199
200static void
201gconfd_add_client (PortableServer_Servant servant,
202 const ConfigListener client,
203 CORBA_Environment *ev);
204
205static void
206gconfd_remove_client (PortableServer_Servant servant,
207 const ConfigListener client,
208 CORBA_Environment *ev);
209
210static CORBA_long
211gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev);
212
213static void
214gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev);
215
216static PortableServer_ServantBase__epv base_epv = {
217 NULL,
218 NULL,
219 NULL
220};
221
222static POA_ConfigServer__epv server_epv = {
223 NULL,
224 gconfd_get_default_database,
225 gconfd_get_database,
226 gconfd_add_client,
227 gconfd_remove_client,
228 gconfd_ping,
229 gconfd_shutdown
230};
231
232static POA_ConfigServer2__epv server2_epv = {
233 NULL,
234 gconfd_get_database_for_addresses
235};
236
237static POA_ConfigServer2__vepv poa_server_vepv = { &base_epv, &server_epv, &server2_epv };
238static POA_ConfigServer2 poa_server_servant = { NULL, &poa_server_vepv };
239
240static ConfigDatabase
241gconfd_get_default_database(PortableServer_Servant servant,
242 CORBA_Environment* ev)
243{
244 GConfDatabase *db;
245
246 if (gconfd_check_in_shutdown (ev))
247 return CORBA_OBJECT_NIL;
248
249 db = lookup_database (NULL);
250
251 if (db)
252 return CORBA_Object_duplicate (db->objref, ev);
253 else
254 return CORBA_OBJECT_NIL;
255}
256
257static ConfigDatabase
258gconfd_get_database(PortableServer_Servant servant,
259 const CORBA_char* address,
260 CORBA_Environment* ev)
261{
262 GConfDatabase *db;
263 GSList *addresses;
264 GError* error = NULL;
265
266 if (gconfd_check_in_shutdown (ev))
267 return CORBA_OBJECT_NIL;
268
269 addresses = g_slist_append (NULL, (char *) address);
270 db = gconfd_obtain_database (addresses, &error);
271 g_slist_free (addresses);
272
273 if (db != NULL)
274 return CORBA_Object_duplicate (db->objref, ev);
275
276 gconf_set_exception (&error, ev);
277
278 return CORBA_OBJECT_NIL;
279}
280
281static ConfigDatabase
282gconfd_get_database_for_addresses (PortableServer_Servant servant,
283 const ConfigServer2_AddressList *seq,
284 CORBA_Environment *ev)
285{
286 GConfDatabase *db;
287 GSList *addresses = NULL;
288 GError *error = NULL;
289 int i;
290
291 if (gconfd_check_in_shutdown (ev))
292 return CORBA_OBJECT_NIL;
293
294 i = 0;
295 while (i < seq->_length)
296 addresses = g_slist_append (addresses, seq->_buffer [i++]);
297
298 db = gconfd_obtain_database (addresses, &error);
299
300 g_slist_free (addresses);
301
302 if (db != NULL)
303 return CORBA_Object_duplicate (db->objref, ev);
304
305 gconf_set_exception (&error, ev);
306
307 return CORBA_OBJECT_NIL;
308}
309
310static void
311gconfd_add_client (PortableServer_Servant servant,
312 const ConfigListener client,
313 CORBA_Environment *ev)
314{
315 if (gconfd_check_in_shutdown (ev))
316 return;
317
318 add_client (client);
319}
320
321static void
322gconfd_remove_client (PortableServer_Servant servant,
323 const ConfigListener client,
324 CORBA_Environment *ev)
325{
326 if (gconfd_check_in_shutdown (ev))
327 return;
328
329 remove_client (client);
330}
331
332static CORBA_long
333gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev)
334{
335 if (gconfd_check_in_shutdown (ev))
336 return 0;
337
338 return getpid();
339}
340
341static void
342gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev)
343{
344 if (gconfd_check_in_shutdown (ev))
345 return;
346
347 gconf_log(GCL_DEBUG, _("Shutdown request received"));
348
349 gconfd_main_quit();
350}
351#endif /* HAVE_CORBA */
352
353/*
354 * Main code
355 */
356
357/* This needs to be called before we register with OAF
358 */
359static GConfSources *
360gconf_server_get_default_sources(void)
361{
362 GSList* addresses;
363 GList* tmp;
364 gboolean have_writable = FALSE;
365 gchar* conffile;
366 GConfSources* sources = NULL;
367 GError* error = NULL;
368
369 conffile = g_strconcat(GCONF_CONFDIR, "/path", NULL);
370
371 addresses = gconf_load_source_path(conffile, NULL);
372
373 g_free(conffile);
374
375#ifdef GCONF_ENABLE_DEBUG
376 /* -- Debug only */
377
378 if (addresses == NULL)
379 {
380 gconf_log(GCL_DEBUG, _("gconfd compiled with debugging; trying to load gconf.path from the source directory"));
381 conffile = g_strconcat(GCONF_SRCDIR, "/gconf/gconf.path", NULL);
382 addresses = gconf_load_source_path(conffile, NULL);
383 g_free(conffile);
384 }
385
386 /* -- End of Debug Only */
387#endif
388
389 if (addresses == NULL)
390 {
391#ifndef G_OS_WIN32
392 const char *home = g_get_home_dir ();
393#else
394 const char *home = _gconf_win32_get_home_dir ();
395#endif
396
397 /* Try using the default address xml:readwrite:$(HOME)/.gconf */
398 addresses = g_slist_append(addresses, g_strconcat("xml:readwrite:", home, "/.gconf", NULL));
399
400 gconf_log(GCL_DEBUG, _("No configuration files found. Trying to use the default configuration source `%s'"), (char *)addresses->data);
401 }
402
403 if (addresses == NULL)
404 {
405 /* We want to stay alive but do nothing, because otherwise every
406 request would result in another failed gconfd being spawned.
407 */
408 gconf_log(GCL_ERR, _("No configuration sources in the source path. Configuration won't be saved; edit %s%s"), GCONF_CONFDIR, "/path");
409 /* don't request error since there aren't any addresses */
410 sources = gconf_sources_new_from_addresses(NULL, NULL);
411
412 return sources;
413 }
414 else
415 {
416 sources = gconf_sources_new_from_addresses(addresses, &error);
417
418 if (error != NULL)
419 {
420 gconf_log(GCL_ERR, _("Error loading some configuration sources: %s"),
421 error->message);
422
423 g_error_free(error);
424 error = NULL;
425 }
426
427 gconf_address_list_free(addresses);
428
429 g_assert(sources != NULL);
430
431 if (sources->sources == NULL)
432 gconf_log(GCL_ERR, _("No configuration source addresses successfully resolved. Can't load or store configuration data"));
433
434 tmp = sources->sources;
435
436 while (tmp != NULL)
437 {
438 if (((GConfSource*)tmp->data)->flags & GCONF_SOURCE_ALL_WRITEABLE)
439 {
440 have_writable = TRUE;
441 break;
442 }
443
444 tmp = g_list_next(tmp);
445 }
446
447 /* In this case, some sources may still return TRUE from their writable() function */
448 if (!have_writable)
449 gconf_log(GCL_WARNING, _("No writable configuration sources successfully resolved. May be unable to save some configuration changes"));
450
451 return sources;
452 }
453}
454
455static void
456gconf_server_load_sources(void)
457{
458 GConfSources* sources;
459
460 sources = gconf_server_get_default_sources();
461
462 /* Install the sources as the default database */
463 set_default_database (gconf_database_new(sources));
464}
465
466/*
467 * Signal handlers should not log debug messages as this code is non-reentrant.
468 * Please avoid calling gconf_log in this function.
469 */
470static void
471signal_handler (int signo)
472{
473 static gint in_fatal = 0;
474
475 /* avoid loops */
476 if (in_fatal > 0)
477 return;
478
479 ++in_fatal;
480
481 switch (signo) {
482 case SIGFPE:
483#ifdef SIGPIPE
484 case SIGPIPE:
485#endif
486 /* Go ahead and try the full cleanup on these,
487 * though it could well not work out very well.
488 */
489 enter_shutdown ();
490
491 /* let the fatal signals interrupt us */
492 --in_fatal;
493
494 if (gconf_main_is_running ())
495 gconfd_main_quit ();
496
497 break;
498
499 case SIGTERM:
500 enter_shutdown ();
501
502 /* let the fatal signals interrupt us */
503 --in_fatal;
504
505 if (gconf_main_is_running ())
506 gconfd_main_quit ();
507 break;
508
509#ifdef SIGHUP
510 case SIGHUP:
511 --in_fatal;
512
513 /* reload sources during next periodic_cleanup() */
514 need_db_reload = TRUE;
515 break;
516#endif
517
518#ifdef SIGUSR1
519 case SIGUSR1:
520 --in_fatal;
521
522 /* it'd be nice to log a message here but it's not very safe, so */
523 gconf_log_debug_messages = !gconf_log_debug_messages;
524 break;
525#endif
526
527 default:
528#ifndef HAVE_SIGACTION
529 signal (signo, signal_handler);
530#endif
531 break;
532 }
533}
534
535#ifdef HAVE_CORBA
536PortableServer_POA
537gconf_get_poa (void)
538{
539 return the_poa;
540}
541#endif
542
543#ifdef HAVE_CORBA
544static const char *
545get_introspection_xml (void)
546{
547 return "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
548 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
549 "<node>\n"
550 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
551 " <method name=\"Introspect\">\n"
552 " <arg name=\"introspection_xml\" direction=\"out\" type=\"s\"/>\n"
553 " </method>\n"
554 " </interface>\n"
555 " <interface name=\"org.gnome.GConf\">\n"
556 " <method name=\"GetIOR\">\n"
557 " <arg name=\"ior\" direction=\"out\" type=\"s\"/>\n"
558 " </method>\n"
559 " </interface>\n"
560 "</node>\n";
561}
562
563static DBusHandlerResult
564bus_message_handler (DBusConnection *connection,
565 DBusMessage *message,
566 void *user_data)
567{
568 DBusMessage *reply;
569
570 reply = NULL;
571
572 if (dbus_message_is_signal (message,
573 DBUS_INTERFACE_LOCAL,
574 "Disconnected"))
575 {
576 gconfd_main_quit ();
577 return DBUS_HANDLER_RESULT_HANDLED;
578 }
579 else if (dbus_message_is_method_call (message,
580 "org.freedesktop.DBus.Introspectable",
581 "Introspect"))
582 {
583 const char *introspection_xml;
584
585 introspection_xml = get_introspection_xml ();
586
587 reply = dbus_message_new_method_return (message);
588 dbus_message_append_args (reply, DBUS_TYPE_STRING, &introspection_xml,
589 DBUS_TYPE_INVALID);
590
591 }
592 else if (dbus_message_is_method_call (message,
593 "org.gnome.GConf",
594 "GetIOR"))
595 {
596 const char *ior;
597
598 ior = gconf_get_daemon_ior ();
599
600 reply = dbus_message_new_method_return (message);
601 dbus_message_append_args (reply, DBUS_TYPE_STRING, &ior, DBUS_TYPE_INVALID);
602 }
603
604 if (reply != NULL)
605 {
606 dbus_connection_send (connection, reply, NULL);
607 dbus_message_unref (reply);
608 return DBUS_HANDLER_RESULT_HANDLED;
609 }
610
611 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
612}
613
614static DBusConnection *
615get_on_d_bus (void)
616{
617 DBusConnection *connection;
618 DBusError bus_error;
619 int result;
620
621 dbus_error_init (&bus_error);
622 connection = dbus_bus_get (DBUS_BUS_SESSION, &bus_error);
623
624 if (dbus_error_is_set (&bus_error))
625 {
626 gconf_log (GCL_ERR, _("Could not connect to session bus: %s"), bus_error.message);
627 dbus_error_free (&bus_error);
628 return NULL;
629 }
630
631 dbus_connection_setup_with_g_main (connection, NULL);
632
633 if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
634 bus_message_handler, NULL, NULL))
635 {
636 dbus_connection_unref (connection);
637 return NULL;
638 }
639
640 dbus_connection_set_exit_on_disconnect (connection, FALSE);
641
642 result = dbus_bus_request_name (connection, "org.gnome.GConf",
643 0, &bus_error);
644
645 if (dbus_error_is_set (&bus_error))
646 {
647 gconf_log (GCL_WARNING,
648 _("Failed to get bus name for daemon, exiting: %s"),
649 bus_error.message);
650 dbus_error_free (&bus_error);
651 }
652
653 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
654 {
655 dbus_connection_unref (connection);
656 return NULL;
657 }
658
659 return connection;
660}
661#endif
662
663#ifdef ENABLE_DEFAULTS_SERVICE
664/* listen on system bus for defaults changes */
665
666static DBusHandlerResult
667system_bus_message_handler (DBusConnection *connection,
668 DBusMessage *message,
669 void *user_data)
670{
671 DBusMessage *reply;
672
673 reply = NULL;
674
675 if (dbus_message_is_signal (message,
676 "org.gnome.GConf.Defaults",
677 "SystemSet"))
678 {
679 DBusError bus_error;
680 char **keys;
681 int n_keys;
682
683 dbus_error_init (&bus_error);
684 if (dbus_message_get_args (message, &bus_error,
685 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys,
686 DBUS_TYPE_INVALID))
687 {
688 char **key;
689 GConfSources *system_sources;
690 GSList addresses;
691
692 gconf_log (GCL_DEBUG, "System defaults changed. Notifying.");
693
694 addresses.data = "xml:merged:" GCONF_ETCDIR "/gconf.xml.system";
695 addresses.next = NULL;
696 system_sources = gconf_sources_new_from_addresses (&addresses, NULL);
697
698 gconfd_clear_cache_for_sources (system_sources);
699
700 for (key = keys; *key; key++)
701 gconfd_notify_other_listeners (NULL, system_sources, *key);
702
703 gconf_sources_free (system_sources);
704
705 dbus_free_string_array (keys);
706 }
707 else
708 {
709 gconf_log (GCL_DEBUG, "SystemSet signal received, but error getting message: %s", bus_error.message);
710 }
711 dbus_error_free (&bus_error);
712
713 return DBUS_HANDLER_RESULT_HANDLED;
714 }
715
716 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
717}
718
719static DBusConnection *
720get_on_system_bus (void)
721{
722 DBusConnection *connection;
723 DBusError bus_error;
724
725 dbus_error_init (&bus_error);
726 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &bus_error);
727
728 if (dbus_error_is_set (&bus_error))
729 {
730 gconf_log (GCL_ERR, _("Could not connect to system bus: %s"), bus_error.message);
731 dbus_error_free (&bus_error);
732 return NULL;
733 }
734
735 dbus_connection_setup_with_g_main (connection, NULL);
736
737 dbus_bus_add_match (connection, "type='signal',interface='org.gnome.GConf.Defaults'", &bus_error);
738 dbus_connection_flush(connection);
739 if (dbus_error_is_set (&bus_error))
740 {
741 gconf_log (GCL_DEBUG, "Failed to add signal match to system bus: %s", bus_error.message);
742 dbus_connection_unref (connection);
743 return NULL;
744 }
745
746 if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
747 system_bus_message_handler, NULL, NULL))
748 {
749 gconf_log (GCL_DEBUG, "Failed to add message filter to system bus.");
750 dbus_connection_unref (connection);
751 return NULL;
752 }
753
754 return connection;
755}
756#endif /* ENABLE_DEFAULTS_SERVICE */
757
758#ifdef G_OS_WIN32
759
760static void
761wait_console_window (void)
762{
763 SetConsoleTitle ("GConf daemon exiting. Type any character to close this window.");
764 printf ("\n"
765 "(GConf daemon exiting. Type any character to close this window)\n");
766 _getch ();
767}
768
769#endif
770
771int
772main(int argc, char** argv)
773{
774#ifdef HAVE_SIGACTION
775 struct sigaction act;
776 sigset_t empty_mask;
777 sigset_t full_mask;
778#endif
779
780#ifdef HAVE_CORBA
781 CORBA_Environment ev;
782 CORBA_ORB orb;
783 gchar* ior;
784 DBusConnection *connection;
785#endif
786
787 int dev_null_fd;
788 int exit_code = 0;
789 int write_byte_fd;
790
791 _gconf_init_i18n ();
792 setlocale (LC_ALL, "");
793 textdomain (GETTEXT_PACKAGE);
794
795 /* Now this is an argument parser */
796 if (argc > 1)
797 write_byte_fd = atoi (argv[1]);
798 else
799 write_byte_fd = -1;
800
801 /* This is so we don't prevent unmounting of devices. We divert
802 * all messages to syslog
803 */
804 if (g_chdir ("/") < 0)
805 {
806 g_printerr ("Could not change to root directory: %s\n",
807 g_strerror (errno));
808 exit (1);
809 }
810
811 if (!g_getenv ("GCONF_DEBUG_OUTPUT"))
812 {
813 dev_null_fd = open (DEV_NULL, O_RDWR);
814 if (dev_null_fd >= 0)
815 {
816 dup2 (dev_null_fd, 0);
817 dup2 (dev_null_fd, 1);
818 dup2 (dev_null_fd, 2);
819 }
820 }
821 else
822 {
823 gconf_log_debug_messages = TRUE;
824#ifdef G_OS_WIN32
825 if (fileno (stdout) != -1 &&
826 _get_osfhandle (fileno (stdout)) != -1)
827 {
828 /* stdout is fine, presumably redirected to a file or pipe */
829 }
830 else
831 {
832 int allocated_new_console = FALSE;
833
834 typedef BOOL (* WINAPI AttachConsole_t) (DWORD);
835
836 AttachConsole_t p_AttachConsole =
837 (AttachConsole_t) GetProcAddress (GetModuleHandle ("kernel32.dll"), "AttachConsole");
838
839 if (p_AttachConsole != NULL)
840 {
841 if (!AttachConsole (ATTACH_PARENT_PROCESS))
842 {
843 if (AllocConsole ())
844 allocated_new_console = TRUE;
845 }
846
847 freopen ("CONOUT$", "w", stdout);
848 dup2 (fileno (stdout), 1);
849 freopen ("CONOUT$", "w", stderr);
850 dup2 (fileno (stderr), 2);
851
852 if (allocated_new_console)
853 {
854 SetConsoleTitle ("GConf daemon debugging output. You can minimize this window, but don't close it.");
855 printf ("You asked for debugging output by setting the GCONF_DEBUG_OUTPUT\n"
856 "environment variable, so here it is.\n"
857 "\n");
858 atexit (wait_console_window);
859 }
860 }
861 }
862#endif
863 }
864
865 umask (022);
866
867 gconf_set_daemon_mode(TRUE);
868
869 gconf_log (GCL_DEBUG, _("starting (version %s), pid %u user '%s'"),
870 VERSION, (guint)getpid(), g_get_user_name());
871
872#ifdef GCONF_ENABLE_DEBUG
873 gconf_log (GCL_DEBUG, "GConf was built with debugging features enabled");
874#endif
875
876 /* Session setup */
877#ifdef HAVE_SIGACTION
878 sigfillset (&full_mask);
879 sigprocmask (SIG_UNBLOCK, &full_mask, NULL);
880
881 sigemptyset (&empty_mask);
882 act.sa_handler = signal_handler;
883 act.sa_mask = empty_mask;
884 act.sa_flags = 0;
885 sigaction (SIGTERM, &act, NULL);
886 sigaction (SIGHUP, &act, NULL);
887 sigaction (SIGUSR1, &act, NULL);
888
889 act.sa_handler = SIG_IGN;
890 sigaction (SIGINT, &act, NULL);
891#else
892 signal (SIGTERM, signal_handler);
893#ifdef SIGHUP
894 signal (SIGHUP, signal_handler);
895#endif
896#ifdef SIGUSR1
897 signal (SIGUSR1, signal_handler);
898#endif
899#endif
900
901#ifdef HAVE_CORBA
902 CORBA_exception_init(&ev);
903#endif
904
905 init_databases ();
906
907#ifdef HAVE_DBUS
908 if (!gconfd_dbus_init ())
909 return 1;
910#endif
911
912#ifdef HAVE_CORBA
913 orb = gconf_orb_get ();
914
915 POA_ConfigServer2__init (&poa_server_servant, &ev);
916
917 the_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
918 PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(the_poa, &ev), &ev);
919
920 server = PortableServer_POA_servant_to_reference(the_poa,
921 &poa_server_servant,
922 &ev);
923 if (CORBA_Object_is_nil(server, &ev))
924 {
925 gconf_log(GCL_ERR, _("Failed to get object reference for ConfigServer"));
926 return 1;
927 }
928
929 /* Needs to be done before loading sources */
930 ior = CORBA_ORB_object_to_string (orb, server, &ev);
931 gconf_set_daemon_ior (ior);
932 CORBA_free (ior);
933
934 connection = get_on_d_bus ();
935
936 if (connection != NULL)
937 {
938 /* This loads backends and so on. It needs to be done before
939 * we can handle any requests, so before we hit the
940 * main loop. if daemon_lock == NULL we won't hit the
941 * main loop.
942 */
943 gconf_server_load_sources ();
944 }
945#endif
946
947#ifdef HAVE_DBUS
948 gconf_server_load_sources ();
949#endif
950
951#ifdef HAVE_CORBA
952 /* notify caller that we're done either getting the lock
953 * or not getting it
954 */
955 if (write_byte_fd >= 0)
956 {
957 char buf[1] = { 'g' };
958 if (write (write_byte_fd, buf, 1) != 1)
959 {
960 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));
961 }
962
963 close (write_byte_fd);
964 }
965
966 if (connection == NULL)
967 {
968 enter_shutdown ();
969 shutdown_databases ();
970
971 return 1;
972 }
973
974 /* Read saved log file, if any */
975 logfile_read ();
976#endif
977
978#ifdef ENABLE_DEFAULTS_SERVICE
979 get_on_system_bus ();
980#endif
981
982 gconf_main ();
983
984 if (in_shutdown)
985 exit_code = 1; /* means someone already called enter_shutdown() */
986
987 /* This starts bouncing all incoming requests (and we aren't running
988 * the main loop anyway, so they won't get processed)
989 */
990 enter_shutdown ();
991
992#ifdef HAVE_CORBA
993 /* Save current state in logfile (may compress the logfile a good
994 * bit)
995 */
996 logfile_save ();
997#endif
998
999 shutdown_databases ();
1000
1001 gconfd_locale_cache_drop ();
1002
1003#ifdef HAVE_CORBA
1004 if (daemon_lock)
1005 {
1006 GError *err;
1007
1008 err = NULL;
1009 gconf_release_lock (daemon_lock, &err);
1010 if (err != NULL)
1011 {
1012 gconf_log (GCL_WARNING, _("Error releasing lockfile: %s"),
1013 err->message);
1014 g_error_free (err);
1015 }
1016 }
1017
1018 daemon_lock = NULL;
1019#endif
1020
1021 gconf_log (GCL_DEBUG, _("Exiting"));
1022
1023 return exit_code;
1024}
1025
1026/*
1027 * Main loop
1028 */
1029
1030static GSList* main_loops = NULL;
1031static guint timeout_id = 0;
1032static gboolean need_log_cleanup = FALSE;
1033
1034static gboolean
1035periodic_cleanup_timeout(gpointer data)
1036{
1037 if (need_db_reload)
1038 {
1039 gconf_log (GCL_INFO, _("SIGHUP received, reloading all databases"));
1040
1041 need_db_reload = FALSE;
1042#ifdef HAVE_CORBA
1043 logfile_save ();
1044 shutdown_databases ();
1045 init_databases ();
1046 gconf_server_load_sources ();
1047 logfile_read ();
1048#endif
1049#ifdef HAVE_DBUS
1050 reload_databases ();
1051#endif
1052 }
1053
1054 gconf_log (GCL_DEBUG, "Performing periodic cleanup, expiring cache cruft");
1055
1056#ifdef HAVE_CORBA
1057 drop_old_clients ();
1058#endif
1059 drop_old_databases ();
1060
1061#ifdef HAVE_DBUS
1062 if (no_databases_in_use () && gconfd_dbus_client_count () == 0)
1063#else
1064 if (no_databases_in_use () && client_count () == 0)
1065#endif
1066 {
1067 gconf_log (GCL_INFO, _("GConf server is not in use, shutting down."));
1068 gconfd_main_quit ();
1069 return FALSE;
1070 }
1071
1072 /* expire old locale cache entries */
1073 gconfd_locale_cache_expire ();
1074
1075#ifdef HAVE_CORBA
1076 if (!need_log_cleanup)
1077 {
1078 gconf_log (GCL_DEBUG, "No log file saving needed in periodic cleanup handler");
1079 return TRUE;
1080 }
1081
1082 /* Compress the running state file */
1083 logfile_save ();
1084#endif
1085
1086 need_log_cleanup = FALSE;
1087
1088 return TRUE;
1089}
1090
1091void
1092gconfd_need_log_cleanup (void)
1093{
1094 need_log_cleanup = TRUE;
1095}
1096
1097static void
1098gconf_main(void)
1099{
1100 GMainLoop* loop;
1101
1102 loop = g_main_loop_new (NULL, TRUE);
1103
1104 if (main_loops == NULL)
1105 {
1106 gulong timeout_len = 60*0.5; /* 60 s/min * .5 min */
1107
1108 g_assert(timeout_id == 0);
1109 timeout_id = g_timeout_add_seconds (timeout_len,
1110 periodic_cleanup_timeout,
1111 NULL);
1112
1113 }
1114
1115 main_loops = g_slist_prepend(main_loops, loop);
1116
1117 g_main_loop_run (loop);
1118
1119 main_loops = g_slist_remove(main_loops, loop);
1120
1121 if (main_loops == NULL)
1122 {
1123 g_assert(timeout_id != 0);
1124 g_source_remove(timeout_id);
1125 timeout_id = 0;
1126 }
1127
1128 g_main_loop_unref (loop);
1129}
1130
1131void
1132gconfd_main_quit(void)
1133{
1134 g_return_if_fail(main_loops != NULL);
1135
1136 g_main_loop_quit (main_loops->data);
1137}
1138
1139static gboolean
1140gconf_main_is_running (void)
1141{
1142 return main_loops != NULL;
1143}
1144
1145/*
1146 * Database storage
1147 */
1148
1149static GList* db_list = NULL;
1150static GHashTable* dbs_by_addresses = NULL;
1151static GConfDatabase *default_db = NULL;
1152
1153static void
1154init_databases (void)
1155{
1156 gconfd_need_log_cleanup ();
1157
1158 g_assert(db_list == NULL);
1159 g_assert(dbs_by_addresses == NULL);
1160
1161 dbs_by_addresses = g_hash_table_new (g_str_hash, g_str_equal);
1162}
1163
1164static void
1165set_default_database (GConfDatabase* db)
1166{
1167 gconfd_need_log_cleanup ();
1168
1169 default_db = db;
1170
1171 register_database (db);
1172}
1173
1174static void
1175register_database (GConfDatabase *db)
1176{
1177 gconfd_need_log_cleanup ();
1178
1179 if (db->sources->sources)
1180 safe_g_hash_table_insert (dbs_by_addresses,
1181 (char *) gconf_database_get_persistent_name (db),
1182 db);
1183
1184 db_list = g_list_prepend (db_list, db);
1185}
1186
1187static void
1188unregister_database (GConfDatabase *db)
1189{
1190 gconfd_need_log_cleanup ();
1191
1192 if (db->sources->sources)
1193 {
1194 g_hash_table_remove (dbs_by_addresses,
1195 gconf_database_get_persistent_name (db));
1196 }
1197
1198 db_list = g_list_remove (db_list, db);
1199
1200 gconf_database_free (db);
1201}
1202
1203static GConfDatabase*
1204lookup_database (GSList *addresses)
1205{
1206 GConfDatabase *retval;
1207 char *key;
1208
1209 if (addresses == NULL)
1210 return default_db;
1211
1212 key = gconf_address_list_get_persistent_name (addresses);
1213
1214 retval = g_hash_table_lookup (dbs_by_addresses, key);
1215
1216 g_free (key);
1217
1218 return retval;
1219}
1220
1221GConfDatabase *
1222gconfd_obtain_database (GSList *addresses,
1223 GError **err)
1224{
1225 GConfSources* sources;
1226 GError* error = NULL;
1227 GConfDatabase *db;
1228
1229 db = lookup_database (addresses);
1230
1231 if (db)
1232 return db;
1233
1234 sources = gconf_sources_new_from_addresses(addresses, &error);
1235
1236 if (error != NULL)
1237 {
1238 if (err)
1239 *err = error;
1240 else
1241 g_error_free (error);
1242
1243 return NULL;
1244 }
1245
1246 if (sources == NULL)
1247 return NULL;
1248
1249 db = gconf_database_new (sources);
1250
1251 register_database (db);
1252
1253 return db;
1254}
1255
1256static void
1257drop_old_databases(void)
1258{
1259 GList *tmp_list;
1260 GList *dead = NULL;
1261 GTime now;
1262
1263 now = time(NULL);
1264
1265 gconf_database_drop_dead_listeners (default_db);
1266
1267 tmp_list = db_list;
1268 while (tmp_list)
1269 {
1270 GConfDatabase* db = tmp_list->data;
1271
1272 if (db == default_db)
1273 {
1274 tmp_list = g_list_next (tmp_list);
1275 continue;
1276 }
1277
1278 /* Drop any listeners whose clients are gone. */
1279 gconf_database_drop_dead_listeners (db);
1280
1281 if (db->listeners && /* not already hibernating */
1282 gconf_listeners_count(db->listeners) == 0 && /* Can hibernate */
1283#ifdef HAVE_DBUS
1284 db->listening_clients &&
1285 g_hash_table_size (db->listening_clients) == 0 &&
1286#endif
1287 (now - db->last_access) > (60*20)) /* 20 minutes without access */
1288 {
1289 dead = g_list_prepend (dead, db);
1290 }
1291
1292 tmp_list = g_list_next (tmp_list);
1293 }
1294
1295 tmp_list = dead;
1296 while (tmp_list)
1297 {
1298 GConfDatabase* db = tmp_list->data;
1299
1300 unregister_database (db);
1301
1302 tmp_list = g_list_next (tmp_list);
1303 }
1304
1305 g_list_free (dead);
1306}
1307
1308static void
1309shutdown_databases (void)
1310{
1311 GList *tmp_list;
1312
1313 /* This may be called before we init fully,
1314 * so check that everything != NULL
1315 */
1316
1317 tmp_list = db_list;
1318
1319 while (tmp_list)
1320 {
1321 GConfDatabase *db = tmp_list->data;
1322
1323 gconf_database_free (db);
1324
1325 tmp_list = g_list_next (tmp_list);
1326 }
1327
1328 g_list_free (db_list);
1329 db_list = NULL;
1330
1331 if (dbs_by_addresses)
1332 g_hash_table_destroy(dbs_by_addresses);
1333
1334 dbs_by_addresses = NULL;
1335 default_db = NULL;
1336}
1337
1338#ifdef HAVE_DBUS
1339static void
1340reload_databases (void)
1341{
1342 GConfSources* sources;
1343 GList *tmp_list;
1344
1345 sources = gconf_server_get_default_sources ();
1346 gconf_database_set_sources (default_db, sources);
1347
1348 tmp_list = db_list;
1349 while (tmp_list)
1350 {
1351 GConfDatabase* db = tmp_list->data;
1352 GList *l;
1353 GConfSource *source;
1354 GSList *addresses = NULL;
1355 GError *error = NULL;
1356
1357 if (db == default_db)
1358 {
1359 tmp_list = g_list_next (tmp_list);
1360 continue;
1361 }
1362
1363 for (l = db->sources->sources; l != NULL; l = l->next)
1364 {
1365 source = l->data;
1366 addresses = g_slist_prepend (addresses, source->address);
1367 }
1368
1369 addresses = g_slist_reverse (addresses);
1370 sources = gconf_sources_new_from_addresses (addresses, &error);
1371
1372 if (error == NULL)
1373 {
1374 gconf_database_set_sources (db, sources);
1375 }
1376 else
1377 {
1378 /* if we got an error, keep our old sources -- that's better than
1379 * nothing */
1380 g_error_free (error);
1381 }
1382
1383 tmp_list = g_list_next (tmp_list);
1384 }
1385}
1386#endif
1387
1388static gboolean
1389no_databases_in_use (void)
1390{
1391 /* Only the default database still open, and
1392 * it has no listeners
1393 */
1394
1395 if (db_list == NULL)
1396 return TRUE;
1397
1398 if (db_list->next == NULL &&
1399 db_list->data == default_db)
1400 return gconf_listeners_count (default_db->listeners) == 0;
1401
1402 return FALSE;
1403}
1404
1405void
1406gconfd_notify_other_listeners (GConfDatabase *modified_db,
1407 GConfSources *modified_sources,
1408 const char *key)
1409{
1410 GList *tmp;
1411
1412 if (!modified_sources)
1413 return;
1414
1415 tmp = db_list;
1416 while (tmp != NULL)
1417 {
1418 GConfDatabase *db = tmp->data;
1419
1420 if (db != modified_db)
1421 {
1422 GList *tmp2;
1423
1424 tmp2 = modified_sources->sources;
1425 while (tmp2)
1426 {
1427 GConfSource *modified_source = tmp2->data;
1428
1429 if (gconf_sources_is_affected (db->sources, modified_source, key))
1430 {
1431 GConfValue *value;
1432#ifdef HAVE_CORBA
1433 ConfigValue *cvalue;
1434#endif
1435 GError *error;
1436 gboolean is_default;
1437 gboolean is_writable;
1438
1439 error = NULL;
1440 value = gconf_database_query_value (db,
1441 key,
1442 NULL,
1443 TRUE,
1444 NULL,
1445 &is_default,
1446 &is_writable,
1447 &error);
1448 if (error != NULL)
1449 {
1450 gconf_log (GCL_WARNING,
1451 _("Error obtaining new value for `%s': %s"),
1452 key, error->message);
1453 g_error_free (error);
1454 return;
1455 }
1456
1457#if HAVE_CORBA
1458 if (value != NULL)
1459 {
1460 cvalue = gconf_corba_value_from_gconf_value (value);
1461 gconf_value_free (value);
1462 }
1463 else
1464 {
1465 cvalue = gconf_invalid_corba_value ();
1466 }
1467
1468 gconf_database_notify_listeners (db,
1469 NULL,
1470 key,
1471 cvalue,
1472 is_default,
1473 is_writable,
1474 FALSE);
1475 CORBA_free (cvalue);
1476#endif
1477#ifdef HAVE_DBUS
1478 gconf_database_dbus_notify_listeners (db,
1479 NULL,
1480 key,
1481 value,
1482 is_default,
1483 is_writable,
1484 FALSE);
1485#endif
1486 }
1487
1488 tmp2 = tmp2->next;
1489 }
1490 }
1491
1492 tmp = tmp->next;
1493 }
1494}
1495
1496void
1497gconfd_clear_cache_for_sources (GConfSources *sources)
1498{
1499 GList *tmp;
1500
1501 tmp = db_list;
1502 while (tmp != NULL)
1503 {
1504 GConfDatabase *db = tmp->data;
1505
1506 gconf_database_clear_cache_for_sources (db, sources, NULL);
1507
1508 tmp = tmp->next;
1509 }
1510}
1511
1512/*
1513 * Cleanup
1514 */
1515
1516static void
1517enter_shutdown(void)
1518{
1519 in_shutdown = TRUE;
1520}
1521
1522
1523#ifdef HAVE_CORBA
1524/* Exceptions */
1525
1526gboolean
1527gconf_set_exception(GError** error,
1528 CORBA_Environment* ev)
1529{
1530 GConfError en;
1531
1532 if (error == NULL)
1533 return FALSE;
1534
1535 if (*error == NULL)
1536 return FALSE;
1537
1538 en = (*error)->code;
1539
1540 /* success is not supposed to get set */
1541 g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);
1542
1543 {
1544 ConfigException* ce;
1545
1546 ce = ConfigException__alloc();
1547 g_assert(error != NULL);
1548 g_assert(*error != NULL);
1549 g_assert((*error)->message != NULL);
1550 ce->message = CORBA_string_dup((gchar*)(*error)->message); /* cast const */
1551
1552 switch (en)
1553 {
1554 case GCONF_ERROR_FAILED:
1555 ce->err_no = ConfigFailed;
1556 break;
1557 case GCONF_ERROR_NO_PERMISSION:
1558 ce->err_no = ConfigNoPermission;
1559 break;
1560 case GCONF_ERROR_BAD_ADDRESS:
1561 ce->err_no = ConfigBadAddress;
1562 break;
1563 case GCONF_ERROR_BAD_KEY:
1564 ce->err_no = ConfigBadKey;
1565 break;
1566 case GCONF_ERROR_PARSE_ERROR:
1567 ce->err_no = ConfigParseError;
1568 break;
1569 case GCONF_ERROR_CORRUPT:
1570 ce->err_no = ConfigCorrupt;
1571 break;
1572 case GCONF_ERROR_TYPE_MISMATCH:
1573 ce->err_no = ConfigTypeMismatch;
1574 break;
1575 case GCONF_ERROR_IS_DIR:
1576 ce->err_no = ConfigIsDir;
1577 break;
1578 case GCONF_ERROR_IS_KEY:
1579 ce->err_no = ConfigIsKey;
1580 break;
1581 case GCONF_ERROR_NO_WRITABLE_DATABASE:
1582 ce->err_no = ConfigNoWritableDatabase;
1583 break;
1584 case GCONF_ERROR_IN_SHUTDOWN:
1585 ce->err_no = ConfigInShutdown;
1586 break;
1587 case GCONF_ERROR_OVERRIDDEN:
1588 ce->err_no = ConfigOverridden;
1589 break;
1590 case GCONF_ERROR_LOCK_FAILED:
1591 ce->err_no = ConfigLockFailed;
1592 break;
1593
1594 case GCONF_ERROR_OAF_ERROR:
1595 case GCONF_ERROR_LOCAL_ENGINE:
1596 case GCONF_ERROR_NO_SERVER:
1597 case GCONF_ERROR_SUCCESS:
1598 default:
1599 gconf_log (GCL_ERR, "Unhandled error code %d", en);
1600 g_assert_not_reached();
1601 break;
1602 }
1603
1604 CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
1605 ex_ConfigException, ce);
1606
1607 gconf_log(GCL_DEBUG, _("Returning exception: %s"), (*error)->message);
1608
1609 g_error_free(*error);
1610 *error = NULL;
1611
1612 return TRUE;
1613 }
1614}
1615
1616gboolean
1617gconfd_check_in_shutdown (CORBA_Environment *ev)
1618{
1619 if (in_shutdown)
1620 {
1621 ConfigException* ce;
1622
1623 ce = ConfigException__alloc();
1624 ce->message = CORBA_string_dup("Configuration server is currently shutting down");
1625 ce->err_no = ConfigInShutdown;
1626
1627 CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
1628 ex_ConfigException, ce);
1629
1630 return TRUE;
1631 }
1632 else
1633 return FALSE;
1634}
1635
1636/*
1637 * Logging
1638 */
1639
1640/*
1641 The log file records the current listeners we have registered,
1642 so we can restore them if we exit and restart.
1643
1644 Basically:
1645
1646 1) On startup, we parse any logfile and try to restore the
1647 listeners contained therein. As we restore each listener (give
1648 clients a new listener ID) we append a removal of the previous
1649 daemon's listener and the addition of our own listener to the
1650 logfile; this means that if we crash and have to restore a
1651 client's listener a second time, we'll have the client's current
1652 listener ID. If all goes well we then atomically rewrite the
1653 parsed logfile with the resulting current state, to keep the logfile
1654 compact.
1655
1656 2) While running, we keep a FILE* open and whenever we add/remove
1657 a listener we write a line to the logfile recording it,
1658 to keep the logfile always up-to-date.
1659
1660 3) On normal exit, and also periodically (every hour or so, say) we
1661 atomically write over the running log with our complete current
1662 state, to keep the running log from growing without bound.
1663*/
1664
1665static void
1666get_log_names (gchar **logdir, gchar **logfile)
1667{
1668#ifndef G_OS_WIN32
1669 const char *home = g_get_home_dir ();
1670#else
1671 const char *home = _gconf_win32_get_home_dir ();
1672#endif
1673
1674 *logdir = g_build_filename (home, ".gconfd", NULL);
1675 *logfile = g_build_filename (*logdir, "saved_state", NULL);
1676}
1677
1678static void close_append_handle (void);
1679
1680static FILE* append_handle = NULL;
1681static guint append_handle_timeout = 0;
1682
1683static gboolean
1684close_append_handle_timeout(gpointer data)
1685{
1686 close_append_handle ();
1687
1688 /* uninstall the timeout */
1689 append_handle_timeout = 0;
1690 return FALSE;
1691}
1692
1693static gboolean
1694open_append_handle (GError **err)
1695{
1696 if (append_handle == NULL)
1697 {
1698 gchar *logdir;
1699 gchar *logfile;
1700
1701 get_log_names (&logdir, &logfile);
1702
1703 g_mkdir (logdir, 0700); /* ignore failure, we'll catch failures
1704 * that matter on open()
1705 */
1706
1707 append_handle = g_fopen (logfile, "a");
1708
1709 if (append_handle == NULL)
1710 {
1711 gconf_set_error (err,
1712 GCONF_ERROR_FAILED,
1713 _("Failed to open gconfd logfile; won't be able to restore listeners after gconfd shutdown (%s)"),
1714 g_strerror (errno));
1715
1716 g_free (logdir);
1717 g_free (logfile);
1718
1719 return FALSE;
1720 }
1721
1722 g_free (logdir);
1723 g_free (logfile);
1724
1725
1726 {
1727 const gulong timeout_len = 60*0.5; /* 60 s/min * 0.5 min */
1728
1729 if (append_handle_timeout != 0)
1730 g_source_remove (append_handle_timeout);
1731
1732 append_handle_timeout = g_timeout_add_seconds (timeout_len,
1733 close_append_handle_timeout,
1734 NULL);
1735 }
1736 }
1737
1738 return TRUE;
1739}
1740
1741static void
1742close_append_handle (void)
1743{
1744 if (append_handle)
1745 {
1746 if (fclose (append_handle) < 0)
1747 gconf_log (GCL_WARNING,
1748 _("Failed to close gconfd logfile; data may not have been properly saved (%s)"),
1749 g_strerror (errno));
1750
1751 append_handle = NULL;
1752
1753 if (append_handle_timeout != 0)
1754 {
1755 g_source_remove (append_handle_timeout);
1756 append_handle_timeout = 0;
1757 }
1758 }
1759}
1760
1761/* Atomically save our current state, if possible; otherwise
1762 * leave the running log in place.
1763 */
1764static void
1765logfile_save (void)
1766{
1767 GList *tmp_list;
1768 gchar *logdir = NULL;
1769 gchar *logfile = NULL;
1770 gchar *tmpfile = NULL;
1771 gchar *tmpfile2 = NULL;
1772 GString *saveme = NULL;
1773 gint fd = -1;
1774
1775 /* Close the running log */
1776 close_append_handle ();
1777
1778 get_log_names (&logdir, &logfile);
1779
1780 g_mkdir (logdir, 0700); /* ignore failure, we'll catch failures
1781 * that matter on open()
1782 */
1783
1784 saveme = g_string_new (NULL);
1785
1786 /* Clients */
1787 log_clients_to_string (saveme);
1788
1789 /* Databases */
1790 tmp_list = db_list;
1791 while (tmp_list)
1792 {
1793 GConfDatabase *db = tmp_list->data;
1794
1795 gconf_database_log_listeners_to_string (db,
1796 db == default_db ? TRUE : FALSE,
1797 saveme);
1798
1799 tmp_list = g_list_next (tmp_list);
1800 }
1801
1802 /* Now try saving the string to a temporary file */
1803 tmpfile = g_strconcat (logfile, ".tmp", NULL);
1804
1805 fd = g_open (tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
1806
1807 if (fd < 0)
1808 {
1809 gconf_log (GCL_WARNING,
1810 _("Could not open saved state file '%s' for writing: %s"),
1811 tmpfile, g_strerror (errno));
1812
1813 goto out;
1814 }
1815
1816 again:
1817
1818 if (write (fd, saveme->str, saveme->len) < 0)
1819 {
1820 if (errno == EINTR)
1821 goto again;
1822
1823 gconf_log (GCL_WARNING,
1824 _("Could not write saved state file '%s' fd: %d: %s"),
1825 tmpfile, fd, g_strerror (errno));
1826
1827 goto out;
1828 }
1829
1830 if (fsync (fd) < 0)
1831 {
1832 gconf_log (GCL_WARNING,
1833 _("Could not flush saved state file '%s' to disk: %s"),
1834 tmpfile, g_strerror (errno));
1835 }
1836
1837 if (close (fd) < 0)
1838 {
1839 gconf_log (GCL_WARNING,
1840 _("Failed to close new saved state file '%s': %s"),
1841 tmpfile, g_strerror (errno));
1842 goto out;
1843 }
1844
1845 fd = -1;
1846
1847 /* Move the main saved state file aside, if it exists */
1848 if (g_file_test(logfile, G_FILE_TEST_EXISTS))
1849 {
1850 tmpfile2 = g_strconcat (logfile, ".orig", NULL);
1851 if (g_rename (logfile, tmpfile2) < 0)
1852 {
1853 gconf_log (GCL_WARNING,
1854 _("Could not move aside old saved state file '%s': %s"),
1855 logfile, g_strerror (errno));
1856 goto out;
1857 }
1858 }
1859
1860 /* Move the new saved state file into place */
1861 if (g_rename (tmpfile, logfile) < 0)
1862 {
1863 gconf_log (GCL_WARNING,
1864 _("Failed to move new saved state file into place: %s"),
1865 g_strerror (errno));
1866
1867 /* Try to restore old file */
1868 if (tmpfile2)
1869 {
1870 if (g_rename (tmpfile2, logfile) < 0)
1871 {
1872 gconf_log (GCL_WARNING,
1873 _("Failed to restore original saved state file that had been moved to '%s': %s"),
1874 tmpfile2, g_strerror (errno));
1875
1876 }
1877 }
1878
1879 goto out;
1880 }
1881
1882 /* Get rid of original saved state file if everything succeeded */
1883 if (tmpfile2)
1884 g_unlink (tmpfile2);
1885
1886 out:
1887 if (saveme)
1888 g_string_free (saveme, TRUE);
1889 g_free (logdir);
1890 g_free (logfile);
1891 g_free (tmpfile);
1892 g_free (tmpfile2);
1893
1894 if (fd >= 0)
1895 close (fd);
1896}
1897
1898typedef struct _ListenerLogEntry ListenerLogEntry;
1899
1900struct _ListenerLogEntry
1901{
1902 guint connection_id;
1903 gchar *ior;
1904 gchar *address;
1905 gchar *location;
1906};
1907
1908static guint
1909listener_logentry_hash (gconstpointer v)
1910{
1911 const ListenerLogEntry *lle = v;
1912
1913 return
1914 (lle->connection_id & 0xff000000) |
1915 (g_str_hash (lle->ior) & 0x00ff0000) |
1916 (g_str_hash (lle->address) & 0x0000ff00) |
1917 (g_str_hash (lle->location) & 0x000000ff);
1918}
1919
1920static gboolean
1921listener_logentry_equal (gconstpointer ap, gconstpointer bp)
1922{
1923 const ListenerLogEntry *a = ap;
1924 const ListenerLogEntry *b = bp;
1925
1926 return
1927 a->connection_id == b->connection_id &&
1928 strcmp (a->location, b->location) == 0 &&
1929 strcmp (a->ior, b->ior) == 0 &&
1930 strcmp (a->address, b->address) == 0;
1931}
1932
1933/* Return value indicates whether we "handled" this line of text */
1934static gboolean
1935parse_listener_entry (GHashTable *entries,
1936 gchar *text)
1937{
1938 gboolean add;
1939 gchar *p;
1940 gchar *ior;
1941 gchar *address;
1942 gchar *location;
1943 gchar *end;
1944 guint connection_id;
1945 GError *err;
1946 ListenerLogEntry *lle;
1947 ListenerLogEntry *old;
1948
1949 if (strncmp (text, "ADD", 3) == 0)
1950 {
1951 add = TRUE;
1952 p = text + 3;
1953 }
1954 else if (strncmp (text, "REMOVE", 6) == 0)
1955 {
1956 add = FALSE;
1957 p = text + 6;
1958 }
1959 else
1960 {
1961 return FALSE;
1962 }
1963
1964 while (*p && g_ascii_isspace (*p))
1965 ++p;
1966
1967 errno = 0;
1968 end = NULL;
1969 connection_id = strtoul (p, &end, 10);
1970 if (end == p || errno != 0)
1971 {
1972 gconf_log (GCL_DEBUG,
1973 "Failed to parse connection ID in saved state file");
1974
1975 return TRUE;
1976 }
1977
1978 if (connection_id == 0)
1979 {
1980 gconf_log (GCL_DEBUG,
1981 "Connection ID 0 in saved state file is not valid");
1982 return TRUE;
1983 }
1984
1985 p = end;
1986
1987 while (*p && g_ascii_isspace (*p))
1988 ++p;
1989
1990 err = NULL;
1991 end = NULL;
1992 gconf_unquote_string_inplace (p, &end, &err);
1993 if (err != NULL)
1994 {
1995 gconf_log (GCL_DEBUG,
1996 "Failed to unquote configuration source address from saved state file: %s",
1997 err->message);
1998
1999 g_error_free (err);
2000
2001 return TRUE;
2002 }
2003
2004 address = p;
2005 p = end;
2006
2007 while (*p && g_ascii_isspace (*p))
2008 ++p;
2009
2010 err = NULL;
2011 end = NULL;
2012 gconf_unquote_string_inplace (p, &end, &err);
2013 if (err != NULL)
2014 {
2015 gconf_log (GCL_DEBUG,
2016 "Failed to unquote listener location from saved state file: %s",
2017 err->message);
2018
2019 g_error_free (err);
2020
2021 return TRUE;
2022 }
2023
2024 location = p;
2025 p = end;
2026
2027 while (*p && g_ascii_isspace (*p))
2028 ++p;
2029
2030 err = NULL;
2031 end = NULL;
2032 gconf_unquote_string_inplace (p, &end, &err);
2033 if (err != NULL)
2034 {
2035 gconf_log (GCL_DEBUG,
2036 "Failed to unquote IOR from saved state file: %s",
2037 err->message);
2038
2039 g_error_free (err);
2040
2041 return TRUE;
2042 }
2043
2044 ior = p;
2045 p = end;
2046
2047 lle = g_new (ListenerLogEntry, 1);
2048 lle->connection_id = connection_id;
2049 lle->address = address;
2050 lle->ior = ior;
2051 lle->location = location;
2052
2053 if (*(lle->address) == '\0' ||
2054 *(lle->ior) == '\0' ||
2055 *(lle->location) == '\0')
2056 {
2057 gconf_log (GCL_DEBUG,
2058 "Saved state file listener entry didn't contain all the fields; ignoring.");
2059
2060 g_free (lle);
2061
2062 return TRUE;
2063 }
2064
2065 old = g_hash_table_lookup (entries, lle);
2066
2067 if (old)
2068 {
2069 if (add)
2070 {
2071 gconf_log (GCL_DEBUG,
2072 "Saved state file records the same listener added twice; ignoring the second instance");
2073 goto quit;
2074 }
2075 else
2076 {
2077 /* This entry was added, then removed. */
2078 g_hash_table_remove (entries, lle);
2079 goto quit;
2080 }
2081 }
2082 else
2083 {
2084 if (add)
2085 {
2086 g_hash_table_insert (entries, lle, lle);
2087
2088 return TRUE;
2089 }
2090 else
2091 {
2092 gconf_log (GCL_DEBUG,
2093 "Saved state file had a removal of a listener that wasn't added; ignoring the removal.");
2094 goto quit;
2095 }
2096 }
2097
2098 quit:
2099 g_free (lle);
2100
2101 return TRUE;
2102}
2103
2104/* Return value indicates whether we "handled" this line of text */
2105static gboolean
2106parse_client_entry (GHashTable *clients,
2107 gchar *text)
2108{
2109 gboolean add;
2110 gchar *ior;
2111 GError *err;
2112 gchar *old;
2113 gchar *p;
2114 gchar *end;
2115
2116 if (strncmp (text, "CLIENTADD", 9) == 0)
2117 {
2118 add = TRUE;
2119 p = text + 9;
2120 }
2121 else if (strncmp (text, "CLIENTREMOVE", 12) == 0)
2122 {
2123 add = FALSE;
2124 p = text + 12;
2125 }
2126 else
2127 {
2128 return FALSE;
2129 }
2130
2131 while (*p && g_ascii_isspace (*p))
2132 ++p;
2133
2134 err = NULL;
2135 end = NULL;
2136 gconf_unquote_string_inplace (p, &end, &err);
2137 if (err != NULL)
2138 {
2139 gconf_log (GCL_DEBUG,
2140 "Failed to unquote IOR from saved state file: %s",
2141 err->message);
2142
2143 g_error_free (err);
2144
2145 return TRUE;
2146 }
2147
2148 ior = p;
2149 p = end;
2150
2151 old = g_hash_table_lookup (clients, ior);
2152
2153 if (old)
2154 {
2155 if (add)
2156 {
2157 gconf_log (GCL_DEBUG,
2158 "Saved state file records the same client added twice; ignoring the second instance");
2159 goto quit;
2160 }
2161 else
2162 {
2163 /* This entry was added, then removed. */
2164 g_hash_table_remove (clients, ior);
2165 goto quit;
2166 }
2167 }
2168 else
2169 {
2170 if (add)
2171 {
2172 g_hash_table_insert (clients, ior, ior);
2173
2174 return TRUE;
2175 }
2176 else
2177 {
2178 gconf_log (GCL_DEBUG,
2179 "Saved state file had a removal of a client that wasn't added; ignoring the removal.");
2180 goto quit;
2181 }
2182 }
2183
2184 quit:
2185
2186 return TRUE;
2187}
2188
2189static void
2190restore_client (const gchar *ior)
2191{
2192 ConfigListener cl;
2193 CORBA_Environment ev;
2194
2195 CORBA_exception_init (&ev);
2196
2197 cl = CORBA_ORB_string_to_object (gconf_orb_get (), (gchar*)ior, &ev);
2198
2199 CORBA_exception_free (&ev);
2200
2201 if (CORBA_Object_is_nil (cl, &ev))
2202 {
2203 CORBA_exception_free (&ev);
2204
2205 gconf_log (GCL_DEBUG,
2206 "Client in saved state file no longer exists, not restoring it as a client");
2207
2208 return;
2209 }
2210
2211 ConfigListener_drop_all_caches (cl, &ev);
2212
2213 if (ev._major != CORBA_NO_EXCEPTION)
2214 {
2215 gconf_log (GCL_DEBUG, "Failed to update client in saved state file, the client probably no longer exists");
2216
2217 goto finished;
2218 }
2219
2220 /* Add the client, since it still exists. Note that the client still
2221 * has the wrong server object reference, so next time it tries to
2222 * contact the server it will re-add itself; we just live with that,
2223 * it's not a problem.
2224 */
2225 add_client (cl);
2226
2227 finished:
2228 CORBA_Object_release (cl, &ev);
2229
2230 CORBA_exception_free (&ev);
2231}
2232
2233static void
2234restore_listener (GConfDatabase* db,
2235 ListenerLogEntry *lle)
2236{
2237 ConfigListener cl;
2238 CORBA_Environment ev;
2239 guint new_cnxn;
2240 GError *err;
2241
2242 CORBA_exception_init (&ev);
2243
2244 cl = CORBA_ORB_string_to_object (gconf_orb_get (), lle->ior, &ev);
2245
2246 CORBA_exception_free (&ev);
2247
2248 if (CORBA_Object_is_nil (cl, &ev))
2249 {
2250 CORBA_exception_free (&ev);
2251
2252 gconf_log (GCL_DEBUG,
2253 "Client in saved state file no longer exists, not updating its listener connections");
2254
2255 return;
2256 }
2257
2258 /* "Cancel" the addition of the listener in the saved state file,
2259 * so that if we reload the saved state file a second time
2260 * for some reason, we don't try to add this listener that time.
2261 */
2262
2263 err = NULL;
2264 if (!gconfd_logfile_change_listener (db,
2265 FALSE, /* remove */
2266 lle->connection_id,
2267 cl,
2268 lle->location,
2269 &err))
2270 {
2271 gconf_log (GCL_DEBUG,
2272 "Failed to cancel previous daemon's listener in saved state file: %s",
2273 err->message);
2274 g_error_free (err);
2275 }
2276
2277 new_cnxn = gconf_database_readd_listener (db, cl, "from-saved-state", lle->location);
2278
2279 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);
2280
2281 ConfigListener_update_listener (cl,
2282 db->objref,
2283 lle->address,
2284 lle->connection_id,
2285 lle->location,
2286 new_cnxn,
2287 &ev);
2288
2289 if (ev._major != CORBA_NO_EXCEPTION)
2290 {
2291 gconf_log (GCL_DEBUG, "Failed to update listener in saved state file, probably the client no longer exists");
2292
2293 /* listener will get removed next time we try to notify -
2294 * we already appended a cancel of the listener to the
2295 * saved state file.
2296 */
2297 goto finished;
2298 }
2299
2300 /* Successfully notified client of new connection ID, so put that
2301 * connection ID in the saved state file.
2302 */
2303 err = NULL;
2304 if (!gconfd_logfile_change_listener (db,
2305 TRUE, /* add */
2306 new_cnxn,
2307 cl,
2308 lle->location,
2309 &err))
2310 {
2311 gconf_log (GCL_DEBUG,
2312 "Failed to re-add this daemon's listener ID in saved state file: %s",
2313 err->message);
2314 g_error_free (err);
2315 }
2316
2317 /* We updated the listener, and logged that to the saved state
2318 * file. Yay!
2319 */
2320
2321 finished:
2322
2323 CORBA_Object_release (cl, &ev);
2324
2325 CORBA_exception_free (&ev);
2326}
2327
2328static void
2329listener_logentry_restore_and_destroy_foreach (gpointer key,
2330 gpointer value,
2331 gpointer data)
2332{
2333 ListenerLogEntry *lle = key;
2334 GConfDatabase *db = NULL;
2335
2336 if (strcmp (lle->address, "def") == 0)
2337 db = default_db;
2338 else
2339 {
2340 GSList *addresses;
2341
2342 addresses = gconf_persistent_name_get_address_list (lle->address);
2343
2344 db = gconfd_obtain_database (addresses, NULL);
2345
2346 gconf_address_list_free (addresses);
2347 }
2348
2349 if (db == NULL)
2350 {
2351 gconf_log (GCL_WARNING,
2352 _("Unable to restore a listener on address '%s', couldn't resolve the database"),
2353 lle->address);
2354 return;
2355 }
2356
2357 restore_listener (db, lle);
2358
2359 /* We don't need it anymore */
2360 g_free (lle);
2361}
2362
2363static void
2364restore_client_foreach (gpointer key,
2365 gpointer value,
2366 gpointer data)
2367{
2368 restore_client (key);
2369}
2370
2371
2372static gchar*
2373read_line (FILE *f)
2374{
2375#define BUF_SIZE 2048
2376
2377 char buf[BUF_SIZE] = { '\0' };
2378 char *retval = NULL;
2379 int len = 0;
2380
2381 do
2382 {
2383 if (fgets (buf, BUF_SIZE, f) == NULL)
2384 {
2385 if (ferror (f))
2386 {
2387 gconf_log (GCL_ERR,
2388 _("Error reading saved state file: %s"),
2389 g_strerror (errno));
2390 }
2391 break;
2392 }
2393
2394 len = strlen (buf);
2395 if (len > 0 && buf[len - 1] == '\n')
2396 buf[--len] = '\0';
2397
2398 if (retval == NULL)
2399 {
2400 retval = g_strndup (buf, len);
2401 }
2402 else
2403 {
2404 char *freeme = retval;
2405
2406 retval = g_strconcat (retval, buf, NULL);
2407 g_free (freeme);
2408 }
2409 }
2410 while (len == BUF_SIZE - 1);
2411
2412 return retval;
2413
2414#undef BUF_SIZE
2415}
2416
2417static void
2418logfile_read (void)
2419{
2420 gchar *logfile;
2421 gchar *logdir;
2422 GHashTable *entries;
2423 GHashTable *clients;
2424 FILE *f;
2425 gchar *line;
2426 GSList *lines = NULL;
2427
2428 /* Just for good form */
2429 close_append_handle ();
2430
2431 get_log_names (&logdir, &logfile);
2432
2433 f = g_fopen (logfile, "r");
2434
2435 if (f == NULL)
2436 {
2437 if (errno != ENOENT)
2438 gconf_log (GCL_ERR, _("Unable to open saved state file '%s': %s"),
2439 logfile, g_strerror (errno));
2440
2441 goto finished;
2442 }
2443
2444 entries = g_hash_table_new (listener_logentry_hash, listener_logentry_equal);
2445 clients = g_hash_table_new (g_str_hash, g_str_equal);
2446
2447 line = read_line (f);
2448 while (line)
2449 {
2450 if (!parse_listener_entry (entries, line))
2451 {
2452 if (!parse_client_entry (clients, line))
2453 {
2454 gconf_log (GCL_DEBUG,
2455 "Didn't understand line in saved state file: '%s'",
2456 line);
2457 g_free (line);
2458 line = NULL;
2459 }
2460 }
2461
2462 if (line)
2463 lines = g_slist_prepend (lines, line);
2464
2465 line = read_line (f);
2466 }
2467
2468 /* Restore clients first */
2469 g_hash_table_foreach (clients,
2470 restore_client_foreach,
2471 NULL);
2472
2473 /* Entries that still remain in the listener hash table were added
2474 * but not removed, so add them in this daemon instantiation and
2475 * update their listeners with the new connection ID etc.
2476 */
2477 g_hash_table_foreach (entries,
2478 listener_logentry_restore_and_destroy_foreach,
2479 NULL);
2480
2481 g_hash_table_destroy (entries);
2482 g_hash_table_destroy (clients);
2483
2484 /* Note that we need the strings to remain valid until we are totally
2485 * finished, because we store pointers to them in the log entry
2486 * hash.
2487 */
2488 g_slist_foreach (lines, (GFunc)g_free, NULL);
2489 g_slist_free (lines);
2490
2491 finished:
2492 if (f != NULL)
2493 fclose (f);
2494
2495 g_free (logfile);
2496 g_free (logdir);
2497}
2498
2499gboolean
2500gconfd_logfile_change_listener (GConfDatabase *db,
2501 gboolean add,
2502 guint connection_id,
2503 ConfigListener listener,
2504 const gchar *where,
2505 GError **err)
2506{
2507 gchar *ior = NULL;
2508 gchar *quoted_db_name;
2509 gchar *quoted_where;
2510 gchar *quoted_ior;
2511
2512 if (!open_append_handle (err))
2513 return FALSE;
2514
2515 ior = gconf_object_to_string (listener, err);
2516
2517 if (ior == NULL)
2518 return FALSE;
2519
2520 quoted_ior = gconf_quote_string (ior);
2521 g_free (ior);
2522 ior = NULL;
2523
2524 if (db == default_db)
2525 quoted_db_name = gconf_quote_string ("def");
2526 else
2527 {
2528 const gchar *db_name;
2529
2530 db_name = gconf_database_get_persistent_name (db);
2531
2532 quoted_db_name = gconf_quote_string (db_name);
2533 }
2534
2535 quoted_where = gconf_quote_string (where);
2536
2537 /* KEEP IN SYNC with gconf-database.c log to string function */
2538 if (fprintf (append_handle, "%s %u %s %s %s\n",
2539 add ? "ADD" : "REMOVE", connection_id,
2540 quoted_db_name, quoted_where, quoted_ior) < 0)
2541 goto error;
2542
2543 if (fflush (append_handle) < 0)
2544 goto error;
2545
2546 g_free (quoted_db_name);
2547 g_free (quoted_ior);
2548 g_free (quoted_where);
2549
2550 return TRUE;
2551
2552 error:
2553
2554 if (add)
2555 gconf_set_error (err,
2556 GCONF_ERROR_FAILED,
2557 _("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)"),
2558 g_strerror (errno));
2559 else
2560 gconf_set_error (err,
2561 GCONF_ERROR_FAILED,
2562 _("Failed to log removal of listener to gconfd logfile; might erroneously re-add the listener if gconfd exits or shuts down (%s)"),
2563 g_strerror (errno));
2564
2565 g_free (quoted_db_name);
2566 g_free (quoted_ior);
2567 g_free (quoted_where);
2568
2569 return FALSE;
2570}
2571
2572static void
2573log_client_change (const ConfigListener client,
2574 gboolean add)
2575{
2576 gchar *ior = NULL;
2577 gchar *quoted_ior = NULL;
2578 GError *err;
2579
2580 err = NULL;
2581 ior = gconf_object_to_string (client, &err);
2582
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: