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)
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.
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.
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., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
24
* This is the per-user configuration daemon.
25
* (has debug crap in it now)
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-glib-private.h"
38
#include "gconf-database.h"
39
#include <orb/orbit.h>
43
#include <sys/types.h>
56
/* This makes hash table safer when debugging */
57
#ifndef GCONF_ENABLE_DEBUG
58
#define safe_g_hash_table_insert g_hash_table_insert
61
safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
63
gpointer oldkey = NULL, oldval = NULL;
65
if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
67
gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
73
g_hash_table_insert(ht, key, value);
82
static void gconf_main (void);
83
static void gconf_main_quit (void);
84
static gboolean gconf_main_is_running (void);
86
static void logfile_save (void);
87
static void logfile_read (void);
88
static void log_client_add (const ConfigListener client);
89
static void log_client_remove (const ConfigListener client);
91
static void add_client (const ConfigListener client);
92
static void remove_client (const ConfigListener client);
93
static GSList *list_clients (void);
94
static void log_clients_to_string (GString *str);
95
static void drop_old_clients (void);
96
static guint client_count (void);
98
static void enter_shutdown (void);
100
static void init_databases (void);
101
static void shutdown_databases (void);
102
static void set_default_database (GConfDatabase* db);
103
static void register_database (GConfDatabase* db);
104
static void unregister_database (GConfDatabase* db);
105
static GConfDatabase* lookup_database (const gchar *address);
106
static GConfDatabase* obtain_database (const gchar *address,
108
static void drop_old_databases (void);
109
static gboolean no_databases_in_use (void);
112
* Flag indicating that we are shutting down, so return errors
113
* on any attempted operation. We do this instead of unregistering with
114
* OAF or deactivating the server object, because we want to avoid
115
* another gconfd starting up before we finish shutting down.
118
static gboolean in_shutdown = FALSE;
124
static ConfigServer server = CORBA_OBJECT_NIL;
125
static PortableServer_POA the_poa;
126
static GConfLock *daemon_lock = NULL;
128
static ConfigDatabase
129
gconfd_get_default_database(PortableServer_Servant servant,
130
CORBA_Environment* ev);
132
static ConfigDatabase
133
gconfd_get_database(PortableServer_Servant servant,
134
const CORBA_char* address,
135
CORBA_Environment* ev);
138
gconfd_add_client (PortableServer_Servant servant,
139
const ConfigListener client,
140
CORBA_Environment *ev);
143
gconfd_remove_client (PortableServer_Servant servant,
144
const ConfigListener client,
145
CORBA_Environment *ev);
148
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev);
151
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev);
153
static PortableServer_ServantBase__epv base_epv = {
159
static POA_ConfigServer__epv server_epv = {
161
gconfd_get_default_database,
164
gconfd_remove_client,
169
static POA_ConfigServer__vepv poa_server_vepv = { &base_epv, &server_epv };
170
static POA_ConfigServer poa_server_servant = { NULL, &poa_server_vepv };
172
static ConfigDatabase
173
gconfd_get_default_database(PortableServer_Servant servant,
174
CORBA_Environment* ev)
178
if (gconfd_check_in_shutdown (ev))
179
return CORBA_OBJECT_NIL;
181
db = lookup_database (NULL);
184
return CORBA_Object_duplicate (db->objref, ev);
186
return CORBA_OBJECT_NIL;
189
static ConfigDatabase
190
gconfd_get_database(PortableServer_Servant servant,
191
const CORBA_char* address,
192
CORBA_Environment* ev)
195
GError* error = NULL;
197
if (gconfd_check_in_shutdown (ev))
198
return CORBA_OBJECT_NIL;
200
db = obtain_database (address, &error);
203
return CORBA_Object_duplicate (db->objref, ev);
204
else if (gconf_set_exception(&error, ev))
205
return CORBA_OBJECT_NIL;
207
return CORBA_OBJECT_NIL;
211
gconfd_add_client (PortableServer_Servant servant,
212
const ConfigListener client,
213
CORBA_Environment *ev)
215
if (gconfd_check_in_shutdown (ev))
222
gconfd_remove_client (PortableServer_Servant servant,
223
const ConfigListener client,
224
CORBA_Environment *ev)
226
if (gconfd_check_in_shutdown (ev))
229
remove_client (client);
233
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev)
235
if (gconfd_check_in_shutdown (ev))
242
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev)
244
if (gconfd_check_in_shutdown (ev))
247
gconf_log(GCL_DEBUG, _("Shutdown request received"));
256
/* This needs to be called before we register with OAF
259
gconf_server_load_sources(void)
263
gboolean have_writable = FALSE;
265
GConfSources* sources = NULL;
266
GError* error = NULL;
268
conffile = g_strconcat(GCONF_CONFDIR, "/path", NULL);
270
addresses = gconf_load_source_path(conffile, NULL);
274
#ifdef GCONF_ENABLE_DEBUG
277
if (addresses == NULL)
279
gconf_log(GCL_DEBUG, _("gconfd compiled with debugging; trying to load gconf.path from the source directory"));
280
conffile = g_strconcat(GCONF_SRCDIR, "/gconf/gconf.path", NULL);
281
addresses = gconf_load_source_path(conffile, NULL);
285
/* -- End of Debug Only */
288
if (addresses == NULL)
290
/* Try using the default address xml:readwrite:$(HOME)/.gconf */
291
addresses = g_new0(gchar*, 2);
293
addresses[0] = g_strconcat("xml:readwrite:", g_get_home_dir(), "/.gconf", NULL);
297
gconf_log(GCL_DEBUG, _("No configuration files found, trying to use the default config source `%s'"), addresses[0]);
300
if (addresses == NULL)
302
/* We want to stay alive but do nothing, because otherwise every
303
request would result in another failed gconfd being spawned.
305
const gchar* empty_addr[] = { NULL };
306
gconf_log(GCL_ERR, _("No configuration sources in the source path, configuration won't be saved; edit "GCONF_CONFDIR"/path"));
307
/* don't request error since there aren't any addresses */
308
sources = gconf_sources_new_from_addresses(empty_addr, NULL);
310
/* Install the sources as the default database */
311
set_default_database (gconf_database_new(sources));
315
sources = gconf_sources_new_from_addresses((const gchar**)addresses,
320
gconf_log(GCL_ERR, _("Error loading some config sources: %s"),
329
g_assert(sources != NULL);
331
if (sources->sources == NULL)
332
gconf_log(GCL_ERR, _("No config source addresses successfully resolved, can't load or store config data"));
334
tmp = sources->sources;
338
if (((GConfSource*)tmp->data)->flags & GCONF_SOURCE_ALL_WRITEABLE)
340
have_writable = TRUE;
344
tmp = g_list_next(tmp);
347
/* In this case, some sources may still return TRUE from their writable() function */
349
gconf_log(GCL_WARNING, _("No writable config sources successfully resolved, may not be able to save some configuration changes"));
352
/* Install the sources as the default database */
353
set_default_database (gconf_database_new(sources));
358
signal_handler (int signo)
360
static gint in_fatal = 0;
369
/* Fast cleanup only */
375
_("Received signal %d, dumping core. Please report a GConf bug."),
382
/* Go ahead and try the full cleanup on these,
383
* though it could well not work out very well.
387
/* let the fatal signals interrupt us */
391
_("Received signal %d, shutting down abnormally. Please file a GConf bug report."),
395
if (gconf_main_is_running ())
404
/* let the fatal signals interrupt us */
408
_("Received signal %d, shutting down cleanly"), signo);
410
if (gconf_main_is_running ())
415
/* it'd be nice to log a message here but it's not very safe, so */
416
gconf_log_debug_messages = !gconf_log_debug_messages;
431
log_handler (const gchar *log_domain,
432
GLogLevelFlags log_level,
433
const gchar *message,
436
GConfLogPriority pri = GCL_WARNING;
440
case G_LOG_LEVEL_ERROR:
441
case G_LOG_LEVEL_CRITICAL:
445
case G_LOG_LEVEL_WARNING:
449
case G_LOG_LEVEL_MESSAGE:
450
case G_LOG_LEVEL_INFO:
454
case G_LOG_LEVEL_DEBUG:
462
gconf_log (pri, "%s", message);
466
main(int argc, char** argv)
468
struct sigaction act;
470
/* PortableServer_ObjectId objid = {0, sizeof("ConfigServer"), "ConfigServer"}; */
471
PortableServer_ObjectId* objid;
472
CORBA_Environment ev;
475
const gchar* username;
485
/* Now this is an argument parser */
487
write_byte_fd = atoi (argv[1]);
493
/* This is so we don't prevent unmounting of devices. We divert
494
* all messages to syslog
497
if (!g_getenv ("GCONF_DEBUG_OUTPUT"))
499
dev_null_fd = open ("/dev/null", O_RDWR);
500
if (dev_null_fd >= 0)
502
dup2 (dev_null_fd, 0);
503
dup2 (dev_null_fd, 1);
504
dup2 (dev_null_fd, 2);
510
gconf_set_daemon_mode(TRUE);
513
username = g_get_user_name();
514
len = strlen(username) + strlen("gconfd") + 15;
515
logname = g_malloc(len);
516
g_snprintf(logname, len, "gconfd (%s-%u)", username, (guint)getpid());
518
openlog (logname, LOG_NDELAY, LOG_USER);
520
g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
523
/* openlog() does not copy logname - what total brokenness.
524
So we free it at the end of main() */
526
gconf_log (GCL_INFO, _("starting (version %s), pid %u user '%s'"),
527
VERSION, (guint)getpid(), g_get_user_name());
529
#ifdef GCONF_ENABLE_DEBUG
530
gconf_log (GCL_DEBUG, "GConf was built with debugging features enabled");
534
sigemptyset (&empty_mask);
535
act.sa_handler = signal_handler;
536
act.sa_mask = empty_mask;
538
sigaction (SIGTERM, &act, 0);
539
sigaction (SIGILL, &act, 0);
540
sigaction (SIGBUS, &act, 0);
541
sigaction (SIGFPE, &act, 0);
542
sigaction (SIGHUP, &act, 0);
543
sigaction (SIGSEGV, &act, 0);
544
sigaction (SIGABRT, &act, 0);
546
act.sa_handler = SIG_IGN;
547
sigaction (SIGINT, &act, 0);
549
CORBA_exception_init(&ev);
553
orb = gconf_orb_get();
555
POA_ConfigServer__init(&poa_server_servant, &ev);
557
the_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
558
PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(the_poa, &ev), &ev);
560
objid = PortableServer_POA_activate_object(the_poa, &poa_server_servant, &ev);
562
server = PortableServer_POA_servant_to_reference(the_poa,
565
if (CORBA_Object_is_nil(server, &ev))
567
gconf_log(GCL_ERR, _("Failed to get object reference for ConfigServer"));
571
/* Needs to be done before loading sources */
572
ior = CORBA_ORB_object_to_string (orb, server, &ev);
573
gconf_set_daemon_ior (ior);
576
gconfd_dir = gconf_get_daemon_dir ();
577
lock_dir = gconf_get_lock_dir ();
579
if (mkdir (gconfd_dir, 0700) < 0 && errno != EEXIST)
580
gconf_log (GCL_WARNING, _("Failed to create %s: %s"),
581
gconfd_dir, g_strerror (errno));
585
daemon_lock = gconf_get_lock (lock_dir, &err);
587
if (daemon_lock != NULL)
589
/* This loads backends and so on. It needs to be done before
590
* we can handle any requests, so before we hit the
591
* main loop. if daemon_lock == NULL we won't hit the
594
gconf_server_load_sources ();
597
/* notify caller that we're done either getting the lock
600
if (write_byte_fd >= 0)
602
char buf[1] = { 'g' };
603
if (write (write_byte_fd, buf, 1) != 1)
605
gconf_log (GCL_ERR, _("Failed to write byte to pipe fd %d so client program may hang: %s"), write_byte_fd, g_strerror (errno));
608
close (write_byte_fd);
611
if (daemon_lock == NULL)
615
gconf_log (GCL_WARNING, _("Failed to get lock for daemon, exiting: %s"),
620
shutdown_databases ();
625
/* Read saved log file, if any */
631
exit_code = 1; /* means someone already called enter_shutdown() */
633
/* This starts bouncing all incoming requests (and we aren't running
634
* the main loop anyway, so they won't get processed)
638
/* Save current state in logfile (may compress the logfile a good
643
shutdown_databases ();
645
gconfd_locale_cache_drop ();
647
/* Now we can release the lock */
649
server = CORBA_OBJECT_NIL;
654
gconf_release_lock (daemon_lock, &err);
657
gconf_log (GCL_WARNING, _("Error releasing lockfile: %s"),
665
gconf_log (GCL_INFO, _("Exiting"));
676
static GSList* main_loops = NULL;
677
static guint timeout_id = 0;
678
static gboolean need_log_cleanup = FALSE;
681
periodic_cleanup_timeout(gpointer data)
683
gconf_log (GCL_DEBUG, "Performing periodic cleanup, expiring cache cruft");
686
drop_old_databases ();
688
if (no_databases_in_use () && client_count () == 0)
690
gconf_log (GCL_INFO, _("GConf server is not in use, shutting down."));
695
/* expire old locale cache entries */
696
gconfd_locale_cache_expire ();
698
if (!need_log_cleanup)
700
gconf_log (GCL_DEBUG, "No log file saving needed in periodic cleanup handler");
704
/* Compress the running state file */
707
need_log_cleanup = FALSE;
713
gconfd_need_log_cleanup (void)
715
need_log_cleanup = TRUE;
723
loop = g_main_new(TRUE);
725
if (main_loops == NULL)
727
#ifdef GCONF_ENABLE_DEBUG
728
gulong timeout_len = 1000*60*1; /* 1 sec * 60 s/min * 1 min */
730
gulong timeout_len = 1000*60*15; /* 1 sec * 60 s/min * 2 min */
733
g_assert(timeout_id == 0);
734
timeout_id = g_timeout_add (timeout_len,
735
periodic_cleanup_timeout,
740
main_loops = g_slist_prepend(main_loops, loop);
744
main_loops = g_slist_remove(main_loops, loop);
746
if (main_loops == NULL)
748
g_assert(timeout_id != 0);
749
g_source_remove(timeout_id);
753
g_main_destroy(loop);
757
gconf_main_quit(void)
759
g_return_if_fail(main_loops != NULL);
761
g_main_quit(main_loops->data);
765
gconf_main_is_running (void)
767
return main_loops != NULL;
774
static GList* db_list = NULL;
775
static GHashTable* dbs_by_address = NULL;
776
static GConfDatabase *default_db = NULL;
779
init_databases (void)
781
gconfd_need_log_cleanup ();
783
g_assert(db_list == NULL);
784
g_assert(dbs_by_address == NULL);
786
dbs_by_address = g_hash_table_new (g_str_hash, g_str_equal);
788
/* Default database isn't in the address hash since it has
789
multiple addresses in a stack
794
set_default_database (GConfDatabase* db)
796
gconfd_need_log_cleanup ();
800
/* Default database isn't in the address hash since it has
801
multiple addresses in a stack
806
register_database (GConfDatabase *db)
808
gconfd_need_log_cleanup ();
810
if (db->sources->sources)
811
safe_g_hash_table_insert(dbs_by_address,
812
((GConfSource*)db->sources->sources->data)->address,
815
db_list = g_list_prepend (db_list, db);
819
unregister_database (GConfDatabase *db)
821
gconfd_need_log_cleanup ();
823
if (db->sources->sources)
824
g_hash_table_remove(dbs_by_address,
825
((GConfSource*)(db->sources->sources->data))->address);
827
db_list = g_list_remove (db_list, db);
829
gconf_database_free (db);
832
static GConfDatabase*
833
lookup_database (const gchar *address)
838
return g_hash_table_lookup (dbs_by_address, address);
841
static GConfDatabase*
842
obtain_database (const gchar *address,
846
GConfSources* sources;
847
const gchar* addresses[] = { NULL, NULL };
848
GError* error = NULL;
851
addresses[0] = address;
852
db = lookup_database (address);
857
sources = gconf_sources_new_from_addresses(addresses, &error);
864
g_error_free (error);
872
db = gconf_database_new (sources);
874
register_database (db);
880
drop_old_databases(void)
888
gconf_database_drop_dead_listeners (default_db);
893
GConfDatabase* db = tmp_list->data;
895
/* Drop any listeners whose clients are gone. */
896
gconf_database_drop_dead_listeners (db);
898
if (db->listeners && /* not already hibernating */
899
gconf_listeners_count(db->listeners) == 0 && /* Can hibernate */
900
(now - db->last_access) > (60*20)) /* 20 minutes without access */
902
dead = g_list_prepend (dead, db);
905
tmp_list = g_list_next (tmp_list);
911
GConfDatabase* db = tmp_list->data;
913
unregister_database (db);
915
tmp_list = g_list_next (tmp_list);
922
shutdown_databases (void)
926
/* This may be called before we init fully,
927
* so check that everything != NULL
934
GConfDatabase *db = tmp_list->data;
936
gconf_database_free (db);
938
tmp_list = g_list_next (tmp_list);
941
g_list_free (db_list);
945
g_hash_table_destroy(dbs_by_address);
947
dbs_by_address = NULL;
950
gconf_database_free (default_db);
956
no_databases_in_use (void)
958
/* Only the default database still open, and
959
* it has no listeners
961
return db_list == NULL &&
962
gconf_listeners_count (default_db->listeners) == 0;
979
gconf_set_exception(GError** error,
980
CORBA_Environment* ev)
992
/* success is not supposed to get set */
993
g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);
998
ce = ConfigException__alloc();
999
g_assert(error != NULL);
1000
g_assert(*error != NULL);
1001
g_assert((*error)->message != NULL);
1002
ce->message = CORBA_string_dup((gchar*)(*error)->message); /* cast const */
1006
case GCONF_ERROR_FAILED:
1007
ce->err_no = ConfigFailed;
1009
case GCONF_ERROR_NO_PERMISSION:
1010
ce->err_no = ConfigNoPermission;
1012
case GCONF_ERROR_BAD_ADDRESS:
1013
ce->err_no = ConfigBadAddress;
1015
case GCONF_ERROR_BAD_KEY:
1016
ce->err_no = ConfigBadKey;
1018
case GCONF_ERROR_PARSE_ERROR:
1019
ce->err_no = ConfigParseError;
1021
case GCONF_ERROR_CORRUPT:
1022
ce->err_no = ConfigCorrupt;
1024
case GCONF_ERROR_TYPE_MISMATCH:
1025
ce->err_no = ConfigTypeMismatch;
1027
case GCONF_ERROR_IS_DIR:
1028
ce->err_no = ConfigIsDir;
1030
case GCONF_ERROR_IS_KEY:
1031
ce->err_no = ConfigIsKey;
1033
case GCONF_ERROR_NO_WRITABLE_DATABASE:
1034
ce->err_no = ConfigNoWritableDatabase;
1036
case GCONF_ERROR_IN_SHUTDOWN:
1037
ce->err_no = ConfigInShutdown;
1039
case GCONF_ERROR_OVERRIDDEN:
1040
ce->err_no = ConfigOverridden;
1042
case GCONF_ERROR_LOCK_FAILED:
1043
ce->err_no = ConfigLockFailed;
1046
case GCONF_ERROR_OAF_ERROR:
1047
case GCONF_ERROR_LOCAL_ENGINE:
1048
case GCONF_ERROR_NO_SERVER:
1049
case GCONF_ERROR_SUCCESS:
1051
gconf_log (GCL_ERR, "Unhandled error code %d", en);
1052
g_assert_not_reached();
1056
CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
1057
ex_ConfigException, ce);
1059
gconf_log(GCL_ERR, _("Returning exception: %s"), (*error)->message);
1061
g_error_free(*error);
1069
gconfd_check_in_shutdown (CORBA_Environment *ev)
1073
ConfigException* ce;
1075
ce = ConfigException__alloc();
1076
ce->message = CORBA_string_dup("config server is currently shutting down");
1077
ce->err_no = ConfigInShutdown;
1079
CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
1080
ex_ConfigException, ce);
1093
The log file records the current listeners we have registered,
1094
so we can restore them if we exit and restart.
1098
1) On startup, we parse any logfile and try to restore the
1099
listeners contained therein. As we restore each listener (give
1100
clients a new listener ID) we append a removal of the previous
1101
daemon's listener and the addition of our own listener to the
1102
logfile; this means that if we crash and have to restore a
1103
client's listener a second time, we'll have the client's current
1104
listener ID. If all goes well we then atomically rewrite the
1105
parsed logfile with the resulting current state, to keep the logfile
1108
2) While running, we keep a FILE* open and whenever we add/remove
1109
a listener we write a line to the logfile recording it,
1110
to keep the logfile always up-to-date.
1112
3) On normal exit, and also periodically (every hour or so, say) we
1113
atomically write over the running log with our complete current
1114
state, to keep the running log from growing without bound.
1118
get_log_names (gchar **logdir, gchar **logfile)
1120
*logdir = gconf_concat_dir_and_key (g_get_home_dir (), ".gconfd");
1121
*logfile = gconf_concat_dir_and_key (*logdir, "saved_state");
1124
static void close_append_handle (void);
1126
static FILE* append_handle = NULL;
1127
static guint append_handle_timeout = 0;
1130
close_append_handle_timeout(gpointer data)
1132
close_append_handle ();
1134
/* uninstall the timeout */
1135
append_handle_timeout = 0;
1140
open_append_handle (GError **err)
1142
if (append_handle == NULL)
1147
get_log_names (&logdir, &logfile);
1149
mkdir (logdir, 0700); /* ignore failure, we'll catch failures
1150
* that matter on open()
1153
append_handle = fopen (logfile, "a");
1155
if (append_handle == NULL)
1157
gconf_set_error (err,
1159
_("Failed to open gconfd logfile; won't be able to restore listeners after gconfd shutdown (%s)"),
1173
const gulong timeout_len = 1000*60*0.5; /* 1 sec * 60 s/min * 0.5 min */
1175
if (append_handle_timeout != 0)
1176
g_source_remove (append_handle_timeout);
1178
append_handle_timeout = g_timeout_add (timeout_len,
1179
close_append_handle_timeout,
1188
close_append_handle (void)
1192
if (fclose (append_handle) < 0)
1193
gconf_log (GCL_WARNING,
1194
_("Failed to close gconfd logfile; data may not have been properly saved (%s)"),
1197
append_handle = NULL;
1199
if (append_handle_timeout != 0)
1201
g_source_remove (append_handle_timeout);
1202
append_handle_timeout = 0;
1207
/* Atomically save our current state, if possible; otherwise
1208
* leave the running log in place.
1214
gchar *logdir = NULL;
1215
gchar *logfile = NULL;
1216
gchar *tmpfile = NULL;
1217
gchar *tmpfile2 = NULL;
1218
GString *saveme = NULL;
1221
/* Close the running log */
1222
close_append_handle ();
1224
get_log_names (&logdir, &logfile);
1226
mkdir (logdir, 0700); /* ignore failure, we'll catch failures
1227
* that matter on open()
1230
saveme = g_string_new ("");
1233
log_clients_to_string (saveme);
1235
/* Default database */
1236
gconf_database_log_listeners_to_string (default_db,
1240
/* Other databases */
1246
GConfDatabase *db = tmp_list->data;
1248
gconf_database_log_listeners_to_string (db,
1252
tmp_list = g_list_next (tmp_list);
1255
/* Now try saving the string to a temporary file */
1256
tmpfile = g_strconcat (logfile, ".tmp", NULL);
1258
fd = open (tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
1262
gconf_log (GCL_WARNING,
1263
_("Could not open saved state file '%s' for writing: %s"),
1264
tmpfile, strerror (errno));
1271
if (write (fd, saveme->str, saveme->len) < 0)
1276
gconf_log (GCL_WARNING,
1277
_("Could not write saved state file '%s' fd: %d: %s"),
1278
tmpfile, fd, strerror (errno));
1285
gconf_log (GCL_WARNING,
1286
_("Failed to close new saved state file '%s': %s"),
1287
tmpfile, strerror (errno));
1293
/* Move the main saved state file aside, if it exists */
1294
if (gconf_file_exists (logfile))
1296
tmpfile2 = g_strconcat (logfile, ".orig", NULL);
1297
if (rename (logfile, tmpfile2) < 0)
1299
gconf_log (GCL_WARNING,
1300
_("Could not move aside old saved state file '%s': %s"),
1301
logfile, strerror (errno));
1306
/* Move the new saved state file into place */
1307
if (rename (tmpfile, logfile) < 0)
1309
gconf_log (GCL_WARNING,
1310
_("Failed to move new save state file into place: %s"),
1313
/* Try to restore old file */
1316
if (rename (tmpfile2, logfile) < 0)
1318
gconf_log (GCL_WARNING,
1319
_("Failed to restore original saved state file that had been moved to '%s': %s"),
1320
tmpfile2, strerror (errno));
1328
/* Get rid of original saved state file if everything succeeded */
1334
g_string_free (saveme, TRUE);
1344
typedef struct _ListenerLogEntry ListenerLogEntry;
1346
struct _ListenerLogEntry
1348
guint connection_id;
1355
listener_logentry_hash (gconstpointer v)
1357
const ListenerLogEntry *lle = v;
1360
(lle->connection_id & 0xff000000) |
1361
(g_str_hash (lle->ior) & 0x00ff0000) |
1362
(g_str_hash (lle->address) & 0x0000ff00) |
1363
(g_str_hash (lle->location) & 0x000000ff);
1367
listener_logentry_equal (gconstpointer ap, gconstpointer bp)
1369
const ListenerLogEntry *a = ap;
1370
const ListenerLogEntry *b = bp;
1373
a->connection_id == b->connection_id &&
1374
strcmp (a->location, b->location) == 0 &&
1375
strcmp (a->ior, b->ior) == 0 &&
1376
strcmp (a->address, b->address) == 0;
1379
/* Return value indicates whether we "handled" this line of text */
1381
parse_listener_entry (GHashTable *entries,
1390
guint connection_id;
1392
ListenerLogEntry *lle;
1393
ListenerLogEntry *old;
1395
if (strncmp (text, "ADD", 3) == 0)
1400
else if (strncmp (text, "REMOVE", 6) == 0)
1410
while (*p && isspace (*p))
1415
connection_id = strtoul (p, &end, 10);
1416
if (end == p || errno != 0)
1418
gconf_log (GCL_DEBUG,
1419
"Failed to parse connection ID in saved state file");
1424
if (connection_id == 0)
1426
gconf_log (GCL_DEBUG,
1427
"Connection ID 0 in saved state file is not valid");
1433
while (*p && isspace (*p))
1438
gconf_unquote_string_inplace (p, &end, &err);
1441
gconf_log (GCL_DEBUG,
1442
"Failed to unquote config source address from saved state file: %s",
1453
while (*p && isspace (*p))
1458
gconf_unquote_string_inplace (p, &end, &err);
1461
gconf_log (GCL_DEBUG,
1462
"Failed to unquote listener location from saved state file: %s",
1473
while (*p && isspace (*p))
1478
gconf_unquote_string_inplace (p, &end, &err);
1481
gconf_log (GCL_DEBUG,
1482
"Failed to unquote IOR from saved state file: %s",
1493
lle = g_new (ListenerLogEntry, 1);
1494
lle->connection_id = connection_id;
1495
lle->address = address;
1497
lle->location = location;
1499
if (*(lle->address) == '\0' ||
1500
*(lle->ior) == '\0' ||
1501
*(lle->location) == '\0')
1503
gconf_log (GCL_DEBUG,
1504
"Saved state file listener entry didn't contain all the fields; ignoring.");
1511
old = g_hash_table_lookup (entries, lle);
1517
gconf_log (GCL_DEBUG,
1518
"Saved state file records the same listener added twice; ignoring the second instance");
1523
/* This entry was added, then removed. */
1524
g_hash_table_remove (entries, lle);
1532
g_hash_table_insert (entries, lle, lle);
1538
gconf_log (GCL_DEBUG,
1539
"Saved state file had a removal of a listener that wasn't added; ignoring the removal.");
1550
/* Return value indicates whether we "handled" this line of text */
1552
parse_client_entry (GHashTable *clients,
1562
if (strncmp (text, "CLIENTADD", 9) == 0)
1567
else if (strncmp (text, "CLIENTREMOVE", 12) == 0)
1577
while (*p && isspace (*p))
1582
gconf_unquote_string_inplace (p, &end, &err);
1585
gconf_log (GCL_DEBUG,
1586
"Failed to unquote IOR from saved state file: %s",
1597
old = g_hash_table_lookup (clients, ior);
1603
gconf_log (GCL_DEBUG,
1604
"Saved state file records the same client added twice; ignoring the second instance");
1609
/* This entry was added, then removed. */
1610
g_hash_table_remove (clients, ior);
1618
g_hash_table_insert (clients, ior, ior);
1624
gconf_log (GCL_DEBUG,
1625
"Saved state file had a removal of a client that wasn't added; ignoring the removal.");
1636
restore_client (const gchar *ior)
1639
CORBA_Environment ev;
1641
CORBA_exception_init (&ev);
1643
cl = CORBA_ORB_string_to_object (gconf_orb_get (),
1647
CORBA_exception_free (&ev);
1649
if (CORBA_Object_is_nil (cl, &ev))
1651
CORBA_exception_free (&ev);
1653
gconf_log (GCL_DEBUG,
1654
"Client in saved state file no longer exists, not restoring it as a client");
1659
ConfigListener_drop_all_caches (cl, &ev);
1661
if (ev._major != CORBA_NO_EXCEPTION)
1663
gconf_log (GCL_DEBUG, "Failed to update client in saved state file, probably the client no longer exists");
1668
/* Add the client, since it still exists. Note that the client still
1669
* has the wrong server object reference, so next time it tries to
1670
* contact the server it will re-add itself; we just live with that,
1671
* it's not a problem.
1676
CORBA_Object_release (cl, &ev);
1678
CORBA_exception_free (&ev);
1682
restore_listener (GConfDatabase* db,
1683
ListenerLogEntry *lle)
1686
CORBA_Environment ev;
1690
CORBA_exception_init (&ev);
1692
cl = CORBA_ORB_string_to_object (gconf_orb_get (),
1696
CORBA_exception_free (&ev);
1698
if (CORBA_Object_is_nil (cl, &ev))
1700
CORBA_exception_free (&ev);
1702
gconf_log (GCL_DEBUG,
1703
"Client in saved state file no longer exists, not updating its listener connections");
1708
/* "Cancel" the addition of the listener in the saved state file,
1709
* so that if we reload the saved state file a second time
1710
* for some reason, we don't try to add this listener that time.
1714
if (!gconfd_logfile_change_listener (db,
1721
gconf_log (GCL_DEBUG,
1722
"Failed to cancel previous daemon's listener in saved state file: %s",
1727
new_cnxn = gconf_database_readd_listener (db, cl, lle->location);
1729
gconf_log (GCL_DEBUG, "Attempting to update listener from saved state file, old connection %u, new connectin %u", (guint) lle->connection_id, (guint) new_cnxn);
1731
ConfigListener_update_listener (cl,
1739
if (ev._major != CORBA_NO_EXCEPTION)
1741
gconf_log (GCL_DEBUG, "Failed to update listener in saved state file, probably the client no longer exists");
1743
/* listener will get removed next time we try to notify -
1744
* we already appended a cancel of the listener to the
1750
/* Successfully notified client of new connection ID, so put that
1751
* connection ID in the saved state file.
1754
if (!gconfd_logfile_change_listener (db,
1761
gconf_log (GCL_DEBUG,
1762
"Failed to re-add this daemon's listener ID in saved state file: %s",
1767
/* We updated the listener, and logged that to the saved state
1773
CORBA_Object_release (cl, &ev);
1775
CORBA_exception_free (&ev);
1779
listener_logentry_restore_and_destroy_foreach (gpointer key,
1783
ListenerLogEntry *lle = key;
1786
if (strcmp (lle->address, "def") == 0)
1789
db = obtain_database (lle->address, NULL);
1793
gconf_log (GCL_WARNING,
1794
_("Unable to restore a listener on address '%s', couldn't resolve the database"),
1799
restore_listener (db, lle);
1801
/* We don't need it anymore */
1806
restore_client_foreach (gpointer key,
1810
restore_client (key);
1814
#ifndef HAVE_FLOCKFILE
1815
# define flockfile(f) (void)1
1816
# define funlockfile(f) (void)1
1817
# define getc_unlocked(f) getc(f)
1818
#endif /* !HAVE_FLOCKFILE */
1826
str = g_string_new ("");
1832
c = getc_unlocked (f);
1840
_("Error reading saved state file: %s"),
1841
g_strerror (errno));
1850
g_string_append_c (str, c);
1860
g_string_free (str, TRUE);
1868
g_string_free (str, FALSE);
1878
GHashTable *entries;
1879
GHashTable *clients;
1882
GSList *lines = NULL;
1884
/* Just for good form */
1885
close_append_handle ();
1887
get_log_names (&logdir, &logfile);
1889
f = fopen (logfile, "r");
1893
gconf_log (GCL_ERR, _("Unable to open saved state file '%s': %s"),
1894
logfile, g_strerror (errno));
1899
entries = g_hash_table_new (listener_logentry_hash, listener_logentry_equal);
1900
clients = g_hash_table_new (g_str_hash, g_str_equal);
1902
line = read_line (f);
1905
if (!parse_listener_entry (entries, line))
1907
if (!parse_client_entry (clients, line))
1909
gconf_log (GCL_DEBUG,
1910
"Didn't understand line in saved state file: '%s'",
1918
lines = g_slist_prepend (lines, line);
1920
line = read_line (f);
1923
/* Restore clients first */
1924
g_hash_table_foreach (clients,
1925
restore_client_foreach,
1928
/* Entries that still remain in the listener hash table were added
1929
* but not removed, so add them in this daemon instantiation and
1930
* update their listeners with the new connection ID etc.
1932
g_hash_table_foreach (entries,
1933
listener_logentry_restore_and_destroy_foreach,
1936
g_hash_table_destroy (entries);
1937
g_hash_table_destroy (clients);
1939
/* Note that we need the strings to remain valid until we are totally
1940
* finished, because we store pointers to them in the log entry
1943
g_slist_foreach (lines, (GFunc)g_free, NULL);
1944
g_slist_free (lines);
1953
gconfd_logfile_change_listener (GConfDatabase *db,
1955
guint connection_id,
1956
ConfigListener listener,
1961
gchar *quoted_db_name;
1962
gchar *quoted_where;
1965
if (!open_append_handle (err))
1968
ior = gconf_object_to_string (listener, err);
1973
quoted_ior = gconf_quote_string (ior);
1977
if (db == default_db)
1978
quoted_db_name = gconf_quote_string ("def");
1981
const gchar *db_name;
1983
db_name = gconf_database_get_persistent_name (db);
1985
quoted_db_name = gconf_quote_string (db_name);
1988
quoted_where = gconf_quote_string (where);
1990
/* KEEP IN SYNC with gconf-database.c log to string function */
1991
if (fprintf (append_handle, "%s %u %s %s %s\n",
1992
add ? "ADD" : "REMOVE", connection_id,
1993
quoted_db_name, quoted_where, quoted_ior) < 0)
1996
if (fflush (append_handle) < 0)
1999
g_free (quoted_db_name);
2000
g_free (quoted_ior);
2001
g_free (quoted_where);
2008
gconf_set_error (err,
2010
_("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)"),
2011
g_strerror (errno));
2013
gconf_set_error (err,
2015
_("Failed to log removal of listener to gconfd logfile; might erroneously re-add the listener if gconfd exits or shuts down (%s)"),
2016
g_strerror (errno));
2018
g_free (quoted_db_name);
2019
g_free (quoted_ior);
2020
g_free (quoted_where);
2026
log_client_change (const ConfigListener client,
2030
gchar *quoted_ior = NULL;
2034
ior = gconf_object_to_string (client, &err);
2038
gconf_log (GCL_WARNING, _("Failed to get IOR for client: %s"),
2047
quoted_ior = gconf_quote_string (ior);
2051
if (!open_append_handle (&err))
2053
gconf_log (GCL_WARNING, _("Failed to open saved state file: %s"),
2061
/* KEEP IN SYNC with log to string function */
2062
if (fprintf (append_handle, "%s %s\n",
2063
add ? "CLIENTADD" : "CLIENTREMOVE", quoted_ior) < 0)
2065
gconf_log (GCL_WARNING,
2066
_("Failed to write client add to saved state file: %s"),
2071
if (fflush (append_handle) < 0)
2073
gconf_log (GCL_WARNING,
2074
_("Failed to flush client add to saved state file: %s"),
2081
g_free (quoted_ior);
2085
log_client_add (const ConfigListener client)
2087
log_client_change (client, TRUE);
2091
log_client_remove (const ConfigListener client)
2093
log_client_change (client, FALSE);
2100
static GHashTable *client_table = NULL;
2103
add_client (const ConfigListener client)
2105
gconfd_need_log_cleanup ();
2107
if (client_table == NULL)
2108
client_table = g_hash_table_new ((GHashFunc) g_CORBA_Object_hash,
2109
(GCompareFunc) g_CORBA_Object_equal);
2111
if (g_hash_table_lookup (client_table, client))
2113
/* Ignore this case; it happens normally when we added a client
2114
* from the logfile, and the client also adds itself
2115
* when it gets a new server objref.
2121
CORBA_Environment ev;
2122
ConfigListener copy;
2124
CORBA_exception_init (&ev);
2125
copy = CORBA_Object_duplicate (client, &ev);
2126
g_hash_table_insert (client_table, copy, copy);
2127
CORBA_exception_free (&ev);
2129
log_client_add (client);
2131
gconf_log (GCL_DEBUG, "Added a new client");
2136
remove_client (const ConfigListener client)
2138
ConfigListener old_client;
2139
CORBA_Environment ev;
2141
gconfd_need_log_cleanup ();
2143
if (client_table == NULL)
2146
old_client = g_hash_table_lookup (client_table,
2149
if (old_client == NULL)
2152
g_hash_table_remove (client_table,
2155
log_client_remove (old_client);
2157
CORBA_exception_init (&ev);
2158
CORBA_Object_release (old_client, &ev);
2159
CORBA_exception_free (&ev);
2164
gconf_log (GCL_WARNING, _("Some client removed itself from the GConf server when it hadn't been added."));
2168
hash_listify_func(gpointer key, gpointer value, gpointer user_data)
2170
GSList** list_p = user_data;
2172
*list_p = g_slist_prepend(*list_p, value);
2178
GSList *clients = NULL;
2180
if (client_table == NULL)
2183
g_hash_table_foreach (client_table, hash_listify_func, &clients);
2189
log_clients_foreach (gpointer key, gpointer value, gpointer data)
2191
ConfigListener client;
2193
gchar *quoted_ior = NULL;
2199
ior = gconf_object_to_string (client, &err);
2203
gconf_log (GCL_WARNING, _("Failed to get IOR for client: %s"),
2212
quoted_ior = gconf_quote_string (ior);
2216
g_string_append (data, "CLIENTADD ");
2217
g_string_append (data, quoted_ior);
2218
g_string_append_c (data, '\n');
2219
g_free (quoted_ior);
2223
log_clients_to_string (GString *str)
2225
if (client_table == NULL)
2228
g_hash_table_foreach (client_table, log_clients_foreach, str);
2232
drop_old_clients (void)
2237
clients = list_clients ();
2241
CORBA_Environment ev;
2243
CORBA_exception_init (&ev);
2248
ConfigListener cl = tmp->data;
2250
ConfigListener_ping (cl, &ev);
2252
if (ev._major != CORBA_NO_EXCEPTION)
2254
gconf_log (GCL_DEBUG, "Removing stale client");
2258
CORBA_exception_free (&ev);
2261
tmp = g_slist_next (tmp);
2264
g_slist_free (clients);
2271
if (client_table == NULL)
2274
return g_hash_table_size (client_table);