~ubuntu-branches/ubuntu/hoary/gconf/hoary

« back to all changes in this revision

Viewing changes to gconf/gconfd.c

  • Committer: Bazaar Package Importer
  • Author(s): Takuo KITAME
  • Date: 2002-03-17 01:51:39 UTC
  • Revision ID: james.westby@ubuntu.com-20020317015139-z4f8fdg1hoe049g0
Tags: upstream-1.0.9
ImportĀ upstreamĀ versionĀ 1.0.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, 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-glib-private.h"
 
36
#include "gconf.h"
 
37
#include "gconfd.h"
 
38
#include "gconf-database.h"
 
39
#include <orb/orbit.h>
 
40
 
 
41
#include "GConf.h"
 
42
 
 
43
#include <sys/types.h>
 
44
#include <stdio.h>
 
45
#include <stdlib.h>
 
46
#include <string.h>
 
47
#include <signal.h>
 
48
#include <unistd.h>
 
49
#include <sys/stat.h>
 
50
#include <fcntl.h>
 
51
#include <errno.h>
 
52
#include <ctype.h>
 
53
#include <syslog.h>
 
54
#include <time.h>
 
55
 
 
56
/* This makes hash table safer when debugging */
 
57
#ifndef GCONF_ENABLE_DEBUG
 
58
#define safe_g_hash_table_insert g_hash_table_insert
 
59
#else
 
60
static void
 
61
safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
 
62
{
 
63
  gpointer oldkey = NULL, oldval = NULL;
 
64
 
 
65
  if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
 
66
    {
 
67
      gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
 
68
                (gchar*) key);
 
69
      return;
 
70
    }
 
71
  else
 
72
    {
 
73
      g_hash_table_insert(ht, key, value);
 
74
    }
 
75
}
 
76
#endif
 
77
 
 
78
/*
 
79
 * Declarations
 
80
 */
 
81
 
 
82
static void     gconf_main            (void);
 
83
static void     gconf_main_quit       (void);
 
84
static gboolean gconf_main_is_running (void);
 
85
 
 
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);
 
90
 
 
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);
 
97
 
 
98
static void    enter_shutdown          (void);
 
99
 
 
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,
 
107
                                             GError **err);
 
108
static void                 drop_old_databases (void);
 
109
static gboolean             no_databases_in_use (void);
 
110
 
 
111
/*
 
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.
 
116
 */
 
117
 
 
118
static gboolean in_shutdown = FALSE;
 
119
 
 
120
/* 
 
121
 * CORBA goo
 
122
 */
 
123
 
 
124
static ConfigServer server = CORBA_OBJECT_NIL;
 
125
static PortableServer_POA the_poa;
 
126
static GConfLock *daemon_lock = NULL;
 
127
 
 
128
static ConfigDatabase
 
129
gconfd_get_default_database(PortableServer_Servant servant,
 
130
                            CORBA_Environment* ev);
 
131
 
 
132
static ConfigDatabase
 
133
gconfd_get_database(PortableServer_Servant servant,
 
134
                    const CORBA_char* address,
 
135
                    CORBA_Environment* ev);
 
136
 
 
137
static void
 
138
gconfd_add_client (PortableServer_Servant servant,
 
139
                   const ConfigListener client,
 
140
                   CORBA_Environment *ev);
 
141
 
 
142
static void
 
143
gconfd_remove_client (PortableServer_Servant servant,
 
144
                      const ConfigListener client,
 
145
                      CORBA_Environment *ev);
 
146
 
 
147
static CORBA_long
 
148
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev);
 
149
 
 
150
static void
 
151
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev);
 
152
 
 
153
static PortableServer_ServantBase__epv base_epv = {
 
154
  NULL,
 
155
  NULL,
 
156
  NULL
 
157
};
 
158
 
 
159
static POA_ConfigServer__epv server_epv = { 
 
160
  NULL,
 
161
  gconfd_get_default_database,
 
162
  gconfd_get_database,
 
163
  gconfd_add_client,
 
164
  gconfd_remove_client,
 
165
  gconfd_ping,
 
166
  gconfd_shutdown
 
167
};
 
168
 
 
169
static POA_ConfigServer__vepv poa_server_vepv = { &base_epv, &server_epv };
 
170
static POA_ConfigServer poa_server_servant = { NULL, &poa_server_vepv };
 
171
 
 
172
static ConfigDatabase
 
173
gconfd_get_default_database(PortableServer_Servant servant,
 
174
                            CORBA_Environment* ev)
 
175
{
 
176
  GConfDatabase *db;
 
177
 
 
178
  if (gconfd_check_in_shutdown (ev))
 
179
    return CORBA_OBJECT_NIL;
 
180
  
 
181
  db = lookup_database (NULL);
 
182
 
 
183
  if (db)
 
184
    return CORBA_Object_duplicate (db->objref, ev);
 
185
  else
 
186
    return CORBA_OBJECT_NIL;
 
187
}
 
188
 
 
189
static ConfigDatabase
 
190
gconfd_get_database(PortableServer_Servant servant,
 
191
                    const CORBA_char* address,
 
192
                    CORBA_Environment* ev)
 
193
{
 
194
  GConfDatabase *db;
 
195
  GError* error = NULL;  
 
196
 
 
197
  if (gconfd_check_in_shutdown (ev))
 
198
    return CORBA_OBJECT_NIL;
 
199
  
 
200
  db = obtain_database (address, &error);
 
201
 
 
202
  if (db != NULL)
 
203
    return CORBA_Object_duplicate (db->objref, ev);
 
204
  else if (gconf_set_exception(&error, ev))
 
205
    return CORBA_OBJECT_NIL;
 
206
  else
 
207
    return CORBA_OBJECT_NIL;
 
208
}
 
209
 
 
210
static void
 
211
gconfd_add_client (PortableServer_Servant servant,
 
212
                   const ConfigListener client,
 
213
                   CORBA_Environment *ev)
 
214
{
 
215
  if (gconfd_check_in_shutdown (ev))
 
216
    return;
 
217
  
 
218
  add_client (client);
 
219
}
 
220
 
 
221
static void
 
222
gconfd_remove_client (PortableServer_Servant servant,
 
223
                      const ConfigListener client,
 
224
                      CORBA_Environment *ev)
 
225
{
 
226
  if (gconfd_check_in_shutdown (ev))
 
227
    return;
 
228
  
 
229
  remove_client (client);
 
230
}
 
231
 
 
232
static CORBA_long
 
233
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev)
 
234
{
 
235
  if (gconfd_check_in_shutdown (ev))
 
236
    return 0;
 
237
  
 
238
  return getpid();
 
239
}
 
240
 
 
241
static void
 
242
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev)
 
243
{
 
244
  if (gconfd_check_in_shutdown (ev))
 
245
    return;
 
246
  
 
247
  gconf_log(GCL_DEBUG, _("Shutdown request received"));
 
248
 
 
249
  gconf_main_quit();
 
250
}
 
251
 
 
252
/*
 
253
 * Main code
 
254
 */
 
255
 
 
256
/* This needs to be called before we register with OAF
 
257
 */
 
258
static void
 
259
gconf_server_load_sources(void)
 
260
{
 
261
  gchar** addresses;
 
262
  GList* tmp;
 
263
  gboolean have_writable = FALSE;
 
264
  gchar* conffile;
 
265
  GConfSources* sources = NULL;
 
266
  GError* error = NULL;
 
267
  
 
268
  conffile = g_strconcat(GCONF_CONFDIR, "/path", NULL);
 
269
 
 
270
  addresses = gconf_load_source_path(conffile, NULL);
 
271
 
 
272
  g_free(conffile);
 
273
 
 
274
#ifdef GCONF_ENABLE_DEBUG
 
275
  /* -- Debug only */
 
276
  
 
277
  if (addresses == NULL)
 
278
    {
 
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);
 
282
      g_free(conffile);
 
283
    }
 
284
 
 
285
  /* -- End of Debug Only */
 
286
#endif
 
287
 
 
288
  if (addresses == NULL)
 
289
    {      
 
290
      /* Try using the default address xml:readwrite:$(HOME)/.gconf */
 
291
      addresses = g_new0(gchar*, 2);
 
292
 
 
293
      addresses[0] = g_strconcat("xml:readwrite:", g_get_home_dir(), "/.gconf", NULL);
 
294
 
 
295
      addresses[1] = NULL;
 
296
      
 
297
      gconf_log(GCL_DEBUG, _("No configuration files found, trying to use the default config source `%s'"), addresses[0]);
 
298
    }
 
299
  
 
300
  if (addresses == NULL)
 
301
    {
 
302
      /* We want to stay alive but do nothing, because otherwise every
 
303
         request would result in another failed gconfd being spawned.  
 
304
      */
 
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);
 
309
 
 
310
      /* Install the sources as the default database */
 
311
      set_default_database (gconf_database_new(sources));
 
312
    }
 
313
  else
 
314
    {
 
315
      sources = gconf_sources_new_from_addresses((const gchar**)addresses,
 
316
                                                 &error);
 
317
 
 
318
      if (error != NULL)
 
319
        {
 
320
          gconf_log(GCL_ERR, _("Error loading some config sources: %s"),
 
321
                    error->message);
 
322
 
 
323
          g_error_free(error);
 
324
          error = NULL;
 
325
        }
 
326
      
 
327
      g_free(addresses);
 
328
 
 
329
      g_assert(sources != NULL);
 
330
 
 
331
      if (sources->sources == NULL)
 
332
        gconf_log(GCL_ERR, _("No config source addresses successfully resolved, can't load or store config data"));
 
333
    
 
334
      tmp = sources->sources;
 
335
 
 
336
      while (tmp != NULL)
 
337
        {
 
338
          if (((GConfSource*)tmp->data)->flags & GCONF_SOURCE_ALL_WRITEABLE)
 
339
            {
 
340
              have_writable = TRUE;
 
341
              break;
 
342
            }
 
343
 
 
344
          tmp = g_list_next(tmp);
 
345
        }
 
346
 
 
347
      /* In this case, some sources may still return TRUE from their writable() function */
 
348
      if (!have_writable)
 
349
        gconf_log(GCL_WARNING, _("No writable config sources successfully resolved, may not be able to save some configuration changes"));
 
350
 
 
351
        
 
352
      /* Install the sources as the default database */
 
353
      set_default_database (gconf_database_new(sources));
 
354
    }
 
355
}
 
356
 
 
357
static void
 
358
signal_handler (int signo)
 
359
{
 
360
  static gint in_fatal = 0;
 
361
 
 
362
  /* avoid loops */
 
363
  if (in_fatal > 0)
 
364
    return;
 
365
  
 
366
  ++in_fatal;
 
367
  
 
368
  switch(signo) {
 
369
    /* Fast cleanup only */
 
370
  case SIGSEGV:
 
371
  case SIGBUS:
 
372
  case SIGILL:
 
373
    enter_shutdown ();
 
374
    gconf_log(GCL_ERR,
 
375
              _("Received signal %d, dumping core. Please report a GConf bug."),
 
376
              signo);
 
377
    abort ();
 
378
    break;
 
379
 
 
380
  case SIGFPE:
 
381
  case SIGPIPE:
 
382
    /* Go ahead and try the full cleanup on these,
 
383
     * though it could well not work out very well.
 
384
     */
 
385
    enter_shutdown ();
 
386
 
 
387
    /* let the fatal signals interrupt us */
 
388
    --in_fatal;
 
389
    
 
390
    gconf_log (GCL_ERR,
 
391
               _("Received signal %d, shutting down abnormally. Please file a GConf bug report."),
 
392
               signo);
 
393
 
 
394
 
 
395
    if (gconf_main_is_running ())
 
396
      gconf_main_quit ();
 
397
    
 
398
    break;
 
399
 
 
400
  case SIGTERM:
 
401
  case SIGHUP:
 
402
    enter_shutdown ();
 
403
 
 
404
    /* let the fatal signals interrupt us */
 
405
    --in_fatal;
 
406
    
 
407
    gconf_log (GCL_INFO,
 
408
               _("Received signal %d, shutting down cleanly"), signo);
 
409
 
 
410
    if (gconf_main_is_running ())
 
411
      gconf_main_quit ();
 
412
    break;
 
413
 
 
414
  case SIGUSR1:
 
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;
 
417
    break;
 
418
    
 
419
  default:
 
420
    break;
 
421
  }
 
422
}
 
423
 
 
424
PortableServer_POA
 
425
gconf_get_poa ()
 
426
{
 
427
  return the_poa;
 
428
}
 
429
 
 
430
static void
 
431
log_handler (const gchar   *log_domain,
 
432
             GLogLevelFlags log_level,
 
433
             const gchar   *message,
 
434
             gpointer       user_data)
 
435
{
 
436
  GConfLogPriority pri = GCL_WARNING;
 
437
  
 
438
  switch (log_level)
 
439
    {
 
440
    case G_LOG_LEVEL_ERROR:
 
441
    case G_LOG_LEVEL_CRITICAL:
 
442
      pri = GCL_ERR;
 
443
      break;
 
444
 
 
445
    case G_LOG_LEVEL_WARNING:
 
446
      pri = GCL_WARNING;
 
447
      break;
 
448
 
 
449
    case G_LOG_LEVEL_MESSAGE:
 
450
    case G_LOG_LEVEL_INFO:
 
451
      pri = GCL_INFO;
 
452
      break;
 
453
 
 
454
    case G_LOG_LEVEL_DEBUG:
 
455
      pri = GCL_DEBUG;
 
456
      break;
 
457
 
 
458
    default:
 
459
      break;
 
460
    }
 
461
 
 
462
  gconf_log (pri, "%s", message);
 
463
}
 
464
 
 
465
int 
 
466
main(int argc, char** argv)
 
467
{
 
468
  struct sigaction act;
 
469
  sigset_t empty_mask;
 
470
  /*   PortableServer_ObjectId objid = {0, sizeof("ConfigServer"), "ConfigServer"}; */
 
471
  PortableServer_ObjectId* objid;
 
472
  CORBA_Environment ev;
 
473
  CORBA_ORB orb;
 
474
  gchar* logname;
 
475
  const gchar* username;
 
476
  guint len;
 
477
  gchar* ior;
 
478
  int exit_code = 0;
 
479
  GError *err;
 
480
  char *lock_dir;
 
481
  char *gconfd_dir;
 
482
  int dev_null_fd;
 
483
  int write_byte_fd;
 
484
  
 
485
  /* Now this is an argument parser */
 
486
  if (argc > 1)
 
487
    write_byte_fd = atoi (argv[1]);
 
488
  else
 
489
    write_byte_fd = -1;
 
490
  
 
491
  chdir ("/");
 
492
 
 
493
  /* This is so we don't prevent unmounting of devices. We divert
 
494
   * all messages to syslog
 
495
   */
 
496
 
 
497
  if (!g_getenv ("GCONF_DEBUG_OUTPUT"))
 
498
    {
 
499
      dev_null_fd = open ("/dev/null", O_RDWR);
 
500
      if (dev_null_fd >= 0)
 
501
        {
 
502
          dup2 (dev_null_fd, 0);
 
503
          dup2 (dev_null_fd, 1);
 
504
          dup2 (dev_null_fd, 2);
 
505
        }
 
506
    }
 
507
  
 
508
  umask (022);
 
509
  
 
510
  gconf_set_daemon_mode(TRUE);
 
511
  
 
512
  /* Logs */
 
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());
 
517
 
 
518
  openlog (logname, LOG_NDELAY, LOG_USER);
 
519
 
 
520
  g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
 
521
                     log_handler, NULL);
 
522
  
 
523
  /* openlog() does not copy logname - what total brokenness.
 
524
     So we free it at the end of main() */
 
525
  
 
526
  gconf_log (GCL_INFO, _("starting (version %s), pid %u user '%s'"), 
 
527
             VERSION, (guint)getpid(), g_get_user_name());
 
528
 
 
529
#ifdef GCONF_ENABLE_DEBUG
 
530
  gconf_log (GCL_DEBUG, "GConf was built with debugging features enabled");
 
531
#endif
 
532
  
 
533
  /* Session setup */
 
534
  sigemptyset (&empty_mask);
 
535
  act.sa_handler = signal_handler;
 
536
  act.sa_mask    = empty_mask;
 
537
  act.sa_flags   = 0;
 
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);
 
545
 
 
546
  act.sa_handler = SIG_IGN;
 
547
  sigaction (SIGINT, &act, 0);
 
548
 
 
549
  CORBA_exception_init(&ev);
 
550
 
 
551
  init_databases ();
 
552
 
 
553
  orb = gconf_orb_get();
 
554
  
 
555
  POA_ConfigServer__init(&poa_server_servant, &ev);
 
556
  
 
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);
 
559
 
 
560
  objid = PortableServer_POA_activate_object(the_poa, &poa_server_servant, &ev);
 
561
  
 
562
  server = PortableServer_POA_servant_to_reference(the_poa,
 
563
                                                   &poa_server_servant,
 
564
                                                   &ev);
 
565
  if (CORBA_Object_is_nil(server, &ev)) 
 
566
    {
 
567
      gconf_log(GCL_ERR, _("Failed to get object reference for ConfigServer"));
 
568
      return 1;
 
569
    }
 
570
 
 
571
  /* Needs to be done before loading sources */
 
572
  ior = CORBA_ORB_object_to_string (orb, server, &ev);
 
573
  gconf_set_daemon_ior (ior);
 
574
  CORBA_free (ior);
 
575
 
 
576
  gconfd_dir = gconf_get_daemon_dir ();
 
577
  lock_dir = gconf_get_lock_dir ();
 
578
 
 
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));
 
582
  
 
583
  
 
584
  err = NULL;
 
585
  daemon_lock = gconf_get_lock (lock_dir, &err);
 
586
 
 
587
  if (daemon_lock != NULL)
 
588
    {
 
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
 
592
       * main loop.
 
593
       */
 
594
      gconf_server_load_sources ();
 
595
    }
 
596
  
 
597
  /* notify caller that we're done either getting the lock
 
598
   * or not getting it
 
599
   */
 
600
  if (write_byte_fd >= 0)
 
601
    {
 
602
      char buf[1] = { 'g' };
 
603
      if (write (write_byte_fd, buf, 1) != 1)
 
604
        {
 
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));
 
606
        }
 
607
 
 
608
      close (write_byte_fd);
 
609
    }
 
610
  
 
611
  if (daemon_lock == NULL)
 
612
    {
 
613
      g_assert (err);
 
614
 
 
615
      gconf_log (GCL_WARNING, _("Failed to get lock for daemon, exiting: %s"),
 
616
                 err->message);
 
617
      g_error_free (err);
 
618
 
 
619
      enter_shutdown ();
 
620
      shutdown_databases ();
 
621
      
 
622
      return 1;
 
623
    }
 
624
 
 
625
  /* Read saved log file, if any */
 
626
  logfile_read ();
 
627
  
 
628
  gconf_main ();
 
629
 
 
630
  if (in_shutdown)
 
631
    exit_code = 1; /* means someone already called enter_shutdown() */
 
632
  
 
633
  /* This starts bouncing all incoming requests (and we aren't running
 
634
   * the main loop anyway, so they won't get processed)
 
635
   */
 
636
  enter_shutdown ();
 
637
 
 
638
  /* Save current state in logfile (may compress the logfile a good
 
639
   * bit)
 
640
   */
 
641
  logfile_save ();
 
642
  
 
643
  shutdown_databases ();
 
644
 
 
645
  gconfd_locale_cache_drop ();
 
646
 
 
647
  /* Now we can release the lock */
 
648
 
 
649
  server = CORBA_OBJECT_NIL;
 
650
 
 
651
  if (daemon_lock)
 
652
    {
 
653
      err = NULL;
 
654
      gconf_release_lock (daemon_lock, &err);
 
655
      if (err != NULL)
 
656
        {
 
657
          gconf_log (GCL_WARNING, _("Error releasing lockfile: %s"),
 
658
                     err->message);
 
659
          g_error_free (err);
 
660
        }
 
661
    }
 
662
 
 
663
  daemon_lock = NULL;
 
664
  
 
665
  gconf_log (GCL_INFO, _("Exiting"));
 
666
  
 
667
  g_free (logname);
 
668
  
 
669
  return exit_code;
 
670
}
 
671
 
 
672
/*
 
673
 * Main loop
 
674
 */
 
675
 
 
676
static GSList* main_loops = NULL;
 
677
static guint timeout_id = 0;
 
678
static gboolean need_log_cleanup = FALSE;
 
679
 
 
680
static gboolean
 
681
periodic_cleanup_timeout(gpointer data)
 
682
{  
 
683
  gconf_log (GCL_DEBUG, "Performing periodic cleanup, expiring cache cruft");
 
684
  
 
685
  drop_old_clients ();
 
686
  drop_old_databases ();
 
687
 
 
688
  if (no_databases_in_use () && client_count () == 0)
 
689
    {
 
690
      gconf_log (GCL_INFO, _("GConf server is not in use, shutting down."));
 
691
      gconf_main_quit ();
 
692
      return FALSE;
 
693
    }
 
694
  
 
695
  /* expire old locale cache entries */
 
696
  gconfd_locale_cache_expire ();
 
697
 
 
698
  if (!need_log_cleanup)
 
699
    {
 
700
      gconf_log (GCL_DEBUG, "No log file saving needed in periodic cleanup handler");
 
701
      return TRUE;
 
702
    }
 
703
  
 
704
  /* Compress the running state file */
 
705
  logfile_save ();
 
706
 
 
707
  need_log_cleanup = FALSE;
 
708
  
 
709
  return TRUE;
 
710
}
 
711
 
 
712
void
 
713
gconfd_need_log_cleanup (void)
 
714
{
 
715
  need_log_cleanup = TRUE;
 
716
}
 
717
 
 
718
static void
 
719
gconf_main(void)
 
720
{
 
721
  GMainLoop* loop;
 
722
 
 
723
  loop = g_main_new(TRUE);
 
724
 
 
725
  if (main_loops == NULL)
 
726
    {
 
727
#ifdef GCONF_ENABLE_DEBUG
 
728
      gulong timeout_len = 1000*60*1; /* 1 sec * 60 s/min * 1 min */
 
729
#else
 
730
      gulong timeout_len = 1000*60*15; /* 1 sec * 60 s/min * 2 min */
 
731
#endif
 
732
      
 
733
      g_assert(timeout_id == 0);
 
734
      timeout_id = g_timeout_add (timeout_len,
 
735
                                  periodic_cleanup_timeout,
 
736
                                  NULL);
 
737
 
 
738
    }
 
739
  
 
740
  main_loops = g_slist_prepend(main_loops, loop);
 
741
 
 
742
  g_main_run(loop);
 
743
 
 
744
  main_loops = g_slist_remove(main_loops, loop);
 
745
 
 
746
  if (main_loops == NULL)
 
747
    {
 
748
      g_assert(timeout_id != 0);
 
749
      g_source_remove(timeout_id);
 
750
      timeout_id = 0;
 
751
    }
 
752
  
 
753
  g_main_destroy(loop);
 
754
}
 
755
 
 
756
static void 
 
757
gconf_main_quit(void)
 
758
{
 
759
  g_return_if_fail(main_loops != NULL);
 
760
 
 
761
  g_main_quit(main_loops->data);
 
762
}
 
763
 
 
764
static gboolean
 
765
gconf_main_is_running (void)
 
766
{
 
767
  return main_loops != NULL;
 
768
}
 
769
 
 
770
/*
 
771
 * Database storage
 
772
 */
 
773
 
 
774
static GList* db_list = NULL;
 
775
static GHashTable* dbs_by_address = NULL;
 
776
static GConfDatabase *default_db = NULL;
 
777
 
 
778
static void
 
779
init_databases (void)
 
780
{
 
781
  gconfd_need_log_cleanup ();
 
782
  
 
783
  g_assert(db_list == NULL);
 
784
  g_assert(dbs_by_address == NULL);
 
785
  
 
786
  dbs_by_address = g_hash_table_new (g_str_hash, g_str_equal);
 
787
 
 
788
  /* Default database isn't in the address hash since it has
 
789
     multiple addresses in a stack
 
790
  */
 
791
}
 
792
 
 
793
static void
 
794
set_default_database (GConfDatabase* db)
 
795
{
 
796
  gconfd_need_log_cleanup ();
 
797
  
 
798
  default_db = db;
 
799
  
 
800
  /* Default database isn't in the address hash since it has
 
801
     multiple addresses in a stack
 
802
  */
 
803
}
 
804
 
 
805
static void
 
806
register_database (GConfDatabase *db)
 
807
{
 
808
  gconfd_need_log_cleanup ();
 
809
  
 
810
  if (db->sources->sources)
 
811
    safe_g_hash_table_insert(dbs_by_address,
 
812
                             ((GConfSource*)db->sources->sources->data)->address,
 
813
                             db);
 
814
  
 
815
  db_list = g_list_prepend (db_list, db);
 
816
}
 
817
 
 
818
static void
 
819
unregister_database (GConfDatabase *db)
 
820
{
 
821
  gconfd_need_log_cleanup ();
 
822
  
 
823
  if (db->sources->sources)
 
824
    g_hash_table_remove(dbs_by_address,
 
825
                        ((GConfSource*)(db->sources->sources->data))->address);
 
826
 
 
827
  db_list = g_list_remove (db_list, db);
 
828
 
 
829
  gconf_database_free (db);
 
830
}
 
831
 
 
832
static GConfDatabase*
 
833
lookup_database (const gchar *address)
 
834
{
 
835
  if (address == NULL)
 
836
    return default_db;
 
837
  else
 
838
    return g_hash_table_lookup (dbs_by_address, address);
 
839
}
 
840
 
 
841
static GConfDatabase*
 
842
obtain_database (const gchar *address,
 
843
                 GError **err)
 
844
{
 
845
  
 
846
  GConfSources* sources;
 
847
  const gchar* addresses[] = { NULL, NULL };
 
848
  GError* error = NULL;
 
849
  GConfDatabase *db;
 
850
 
 
851
  addresses[0] = address;
 
852
  db = lookup_database (address);
 
853
 
 
854
  if (db)
 
855
    return db;
 
856
  
 
857
  sources = gconf_sources_new_from_addresses(addresses, &error);
 
858
 
 
859
  if (error != NULL)
 
860
    {
 
861
      if (err)
 
862
        *err = error;
 
863
      else
 
864
        g_error_free (error);
 
865
 
 
866
      return NULL;
 
867
    }
 
868
  
 
869
  if (sources == NULL)
 
870
    return NULL;
 
871
 
 
872
  db = gconf_database_new (sources);
 
873
 
 
874
  register_database (db);
 
875
 
 
876
  return db;
 
877
}
 
878
 
 
879
static void
 
880
drop_old_databases(void)
 
881
{
 
882
  GList *tmp_list;
 
883
  GList *dead = NULL;
 
884
  GTime now;
 
885
  
 
886
  now = time(NULL);
 
887
 
 
888
  gconf_database_drop_dead_listeners (default_db);
 
889
  
 
890
  tmp_list = db_list;
 
891
  while (tmp_list)
 
892
    {
 
893
      GConfDatabase* db = tmp_list->data;
 
894
 
 
895
      /* Drop any listeners whose clients are gone. */
 
896
      gconf_database_drop_dead_listeners (db);
 
897
      
 
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 */
 
901
        {
 
902
          dead = g_list_prepend (dead, db);
 
903
        }
 
904
      
 
905
      tmp_list = g_list_next (tmp_list);
 
906
    }
 
907
 
 
908
  tmp_list = dead;
 
909
  while (tmp_list)
 
910
    {
 
911
      GConfDatabase* db = tmp_list->data;
 
912
 
 
913
      unregister_database (db);
 
914
            
 
915
      tmp_list = g_list_next (tmp_list);
 
916
    }
 
917
 
 
918
  g_list_free (dead);
 
919
}
 
920
 
 
921
static void
 
922
shutdown_databases (void)
 
923
{
 
924
  GList *tmp_list;  
 
925
 
 
926
  /* This may be called before we init fully,
 
927
   * so check that everything != NULL
 
928
   */
 
929
  
 
930
  tmp_list = db_list;
 
931
 
 
932
  while (tmp_list)
 
933
    {
 
934
      GConfDatabase *db = tmp_list->data;
 
935
 
 
936
      gconf_database_free (db);
 
937
      
 
938
      tmp_list = g_list_next (tmp_list);
 
939
    }
 
940
 
 
941
  g_list_free (db_list);
 
942
  db_list = NULL;
 
943
 
 
944
  if (dbs_by_address)
 
945
    g_hash_table_destroy(dbs_by_address);
 
946
 
 
947
  dbs_by_address = NULL;
 
948
 
 
949
  if (default_db)
 
950
    gconf_database_free (default_db);
 
951
 
 
952
  default_db = NULL;
 
953
}
 
954
 
 
955
static gboolean
 
956
no_databases_in_use (void)
 
957
{
 
958
  /* Only the default database still open, and
 
959
   * it has no listeners
 
960
   */
 
961
  return db_list == NULL &&
 
962
    gconf_listeners_count (default_db->listeners) == 0;
 
963
}
 
964
 
 
965
/*
 
966
 * Cleanup
 
967
 */
 
968
 
 
969
static void 
 
970
enter_shutdown(void)
 
971
{
 
972
  in_shutdown = TRUE;
 
973
}
 
974
 
 
975
 
 
976
/* Exceptions */
 
977
 
 
978
gboolean
 
979
gconf_set_exception(GError** error,
 
980
                    CORBA_Environment* ev)
 
981
{
 
982
  GConfError en;
 
983
 
 
984
  if (error == NULL)
 
985
    return FALSE;
 
986
 
 
987
  if (*error == NULL)
 
988
    return FALSE;
 
989
  
 
990
  en = (*error)->code;
 
991
 
 
992
  /* success is not supposed to get set */
 
993
  g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);
 
994
  
 
995
  {
 
996
    ConfigException* ce;
 
997
 
 
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 */
 
1003
      
 
1004
    switch (en)
 
1005
      {
 
1006
      case GCONF_ERROR_FAILED:
 
1007
        ce->err_no = ConfigFailed;
 
1008
        break;
 
1009
      case GCONF_ERROR_NO_PERMISSION:
 
1010
        ce->err_no = ConfigNoPermission;
 
1011
        break;
 
1012
      case GCONF_ERROR_BAD_ADDRESS:
 
1013
        ce->err_no = ConfigBadAddress;
 
1014
        break;
 
1015
      case GCONF_ERROR_BAD_KEY:
 
1016
        ce->err_no = ConfigBadKey;
 
1017
        break;
 
1018
      case GCONF_ERROR_PARSE_ERROR:
 
1019
        ce->err_no = ConfigParseError;
 
1020
        break;
 
1021
      case GCONF_ERROR_CORRUPT:
 
1022
        ce->err_no = ConfigCorrupt;
 
1023
        break;
 
1024
      case GCONF_ERROR_TYPE_MISMATCH:
 
1025
        ce->err_no = ConfigTypeMismatch;
 
1026
        break;
 
1027
      case GCONF_ERROR_IS_DIR:
 
1028
        ce->err_no = ConfigIsDir;
 
1029
        break;
 
1030
      case GCONF_ERROR_IS_KEY:
 
1031
        ce->err_no = ConfigIsKey;
 
1032
        break;
 
1033
      case GCONF_ERROR_NO_WRITABLE_DATABASE:
 
1034
        ce->err_no = ConfigNoWritableDatabase;        
 
1035
        break;
 
1036
      case GCONF_ERROR_IN_SHUTDOWN:
 
1037
        ce->err_no = ConfigInShutdown;
 
1038
        break;
 
1039
      case GCONF_ERROR_OVERRIDDEN:
 
1040
        ce->err_no = ConfigOverridden;
 
1041
        break;
 
1042
      case GCONF_ERROR_LOCK_FAILED:
 
1043
        ce->err_no = ConfigLockFailed;
 
1044
        break;
 
1045
 
 
1046
      case GCONF_ERROR_OAF_ERROR:
 
1047
      case GCONF_ERROR_LOCAL_ENGINE:
 
1048
      case GCONF_ERROR_NO_SERVER:
 
1049
      case GCONF_ERROR_SUCCESS:
 
1050
      default:
 
1051
        gconf_log (GCL_ERR, "Unhandled error code %d", en);
 
1052
        g_assert_not_reached();
 
1053
        break;
 
1054
      }
 
1055
 
 
1056
    CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
 
1057
                        ex_ConfigException, ce);
 
1058
 
 
1059
    gconf_log(GCL_ERR, _("Returning exception: %s"), (*error)->message);
 
1060
      
 
1061
    g_error_free(*error);
 
1062
    *error = NULL;
 
1063
      
 
1064
    return TRUE;
 
1065
  }
 
1066
}
 
1067
 
 
1068
gboolean
 
1069
gconfd_check_in_shutdown (CORBA_Environment *ev)
 
1070
{
 
1071
  if (in_shutdown)
 
1072
    {
 
1073
      ConfigException* ce;
 
1074
      
 
1075
      ce = ConfigException__alloc();
 
1076
      ce->message = CORBA_string_dup("config server is currently shutting down");
 
1077
      ce->err_no = ConfigInShutdown;
 
1078
 
 
1079
      CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
 
1080
                          ex_ConfigException, ce);
 
1081
 
 
1082
      return TRUE;
 
1083
    }
 
1084
  else
 
1085
    return FALSE;
 
1086
}
 
1087
 
 
1088
/*
 
1089
 * Logging
 
1090
 */
 
1091
 
 
1092
/*
 
1093
   The log file records the current listeners we have registered,
 
1094
   so we can restore them if we exit and restart.
 
1095
 
 
1096
   Basically:
 
1097
 
 
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
 
1106
      compact.
 
1107
 
 
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.
 
1111
 
 
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.
 
1115
*/
 
1116
 
 
1117
static void
 
1118
get_log_names (gchar **logdir, gchar **logfile)
 
1119
{
 
1120
  *logdir = gconf_concat_dir_and_key (g_get_home_dir (), ".gconfd");
 
1121
  *logfile = gconf_concat_dir_and_key (*logdir, "saved_state");
 
1122
}
 
1123
 
 
1124
static void close_append_handle (void);
 
1125
 
 
1126
static FILE* append_handle = NULL;
 
1127
static guint append_handle_timeout = 0;
 
1128
 
 
1129
static gboolean
 
1130
close_append_handle_timeout(gpointer data)
 
1131
{
 
1132
  close_append_handle ();
 
1133
 
 
1134
  /* uninstall the timeout */
 
1135
  append_handle_timeout = 0;
 
1136
  return FALSE;
 
1137
}
 
1138
 
 
1139
static gboolean
 
1140
open_append_handle (GError **err)
 
1141
{
 
1142
  if (append_handle == NULL)
 
1143
    {
 
1144
      gchar *logdir;
 
1145
      gchar *logfile;
 
1146
 
 
1147
      get_log_names (&logdir, &logfile);
 
1148
      
 
1149
      mkdir (logdir, 0700); /* ignore failure, we'll catch failures
 
1150
                             * that matter on open()
 
1151
                             */
 
1152
      
 
1153
      append_handle = fopen (logfile, "a");
 
1154
 
 
1155
      if (append_handle == NULL)
 
1156
        {
 
1157
          gconf_set_error (err,
 
1158
                           GCONF_ERROR_FAILED,
 
1159
                           _("Failed to open gconfd logfile; won't be able to restore listeners after gconfd shutdown (%s)"),
 
1160
                           strerror (errno));
 
1161
          
 
1162
          g_free (logdir);
 
1163
          g_free (logfile);
 
1164
 
 
1165
          return FALSE;
 
1166
        }
 
1167
      
 
1168
      g_free (logdir);
 
1169
      g_free (logfile);
 
1170
 
 
1171
 
 
1172
      {
 
1173
        const gulong timeout_len = 1000*60*0.5; /* 1 sec * 60 s/min * 0.5 min */
 
1174
 
 
1175
        if (append_handle_timeout != 0)
 
1176
          g_source_remove (append_handle_timeout);
 
1177
        
 
1178
        append_handle_timeout = g_timeout_add (timeout_len,
 
1179
                                               close_append_handle_timeout,
 
1180
                                               NULL);
 
1181
      }
 
1182
    }
 
1183
 
 
1184
  return TRUE;
 
1185
}
 
1186
 
 
1187
static void
 
1188
close_append_handle (void)
 
1189
{
 
1190
  if (append_handle)
 
1191
    {
 
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)"),
 
1195
                   strerror (errno));
 
1196
 
 
1197
      append_handle = NULL;
 
1198
 
 
1199
      if (append_handle_timeout != 0)
 
1200
        {
 
1201
          g_source_remove (append_handle_timeout);
 
1202
          append_handle_timeout = 0;
 
1203
        }
 
1204
    }
 
1205
}
 
1206
 
 
1207
/* Atomically save our current state, if possible; otherwise
 
1208
 * leave the running log in place.
 
1209
 */
 
1210
static void
 
1211
logfile_save (void)
 
1212
{
 
1213
  GList *tmp_list;
 
1214
  gchar *logdir = NULL;
 
1215
  gchar *logfile = NULL;
 
1216
  gchar *tmpfile = NULL;
 
1217
  gchar *tmpfile2 = NULL;
 
1218
  GString *saveme = NULL;
 
1219
  gint fd = -1;
 
1220
  
 
1221
  /* Close the running log */
 
1222
  close_append_handle ();
 
1223
  
 
1224
  get_log_names (&logdir, &logfile);
 
1225
 
 
1226
  mkdir (logdir, 0700); /* ignore failure, we'll catch failures
 
1227
                         * that matter on open()
 
1228
                         */
 
1229
 
 
1230
  saveme = g_string_new ("");
 
1231
 
 
1232
  /* Clients */
 
1233
  log_clients_to_string (saveme);
 
1234
  
 
1235
  /* Default database */
 
1236
  gconf_database_log_listeners_to_string (default_db,
 
1237
                                          TRUE,
 
1238
                                          saveme);
 
1239
 
 
1240
  /* Other databases */
 
1241
  
 
1242
  tmp_list = db_list;
 
1243
 
 
1244
  while (tmp_list)
 
1245
    {
 
1246
      GConfDatabase *db = tmp_list->data;
 
1247
 
 
1248
      gconf_database_log_listeners_to_string (db,
 
1249
                                              FALSE,
 
1250
                                              saveme);
 
1251
      
 
1252
      tmp_list = g_list_next (tmp_list);
 
1253
    }
 
1254
  
 
1255
  /* Now try saving the string to a temporary file */
 
1256
  tmpfile = g_strconcat (logfile, ".tmp", NULL);
 
1257
  
 
1258
  fd = open (tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
 
1259
 
 
1260
  if (fd < 0)
 
1261
    {
 
1262
      gconf_log (GCL_WARNING,
 
1263
                 _("Could not open saved state file '%s' for writing: %s"),
 
1264
                 tmpfile, strerror (errno));
 
1265
      
 
1266
      goto out;
 
1267
    }
 
1268
 
 
1269
 again:
 
1270
  
 
1271
  if (write (fd, saveme->str, saveme->len) < 0)
 
1272
    {
 
1273
      if (errno == EINTR)
 
1274
        goto again;
 
1275
      
 
1276
      gconf_log (GCL_WARNING,
 
1277
                 _("Could not write saved state file '%s' fd: %d: %s"),
 
1278
                 tmpfile, fd, strerror (errno));
 
1279
 
 
1280
      goto out;
 
1281
    }
 
1282
 
 
1283
  if (close (fd) < 0)
 
1284
    {
 
1285
      gconf_log (GCL_WARNING,
 
1286
                 _("Failed to close new saved state file '%s': %s"),
 
1287
                 tmpfile, strerror (errno));
 
1288
      goto out;
 
1289
    }
 
1290
 
 
1291
  fd = -1;
 
1292
  
 
1293
  /* Move the main saved state file aside, if it exists */
 
1294
  if (gconf_file_exists (logfile))
 
1295
    {
 
1296
      tmpfile2 = g_strconcat (logfile, ".orig", NULL);
 
1297
      if (rename (logfile, tmpfile2) < 0)
 
1298
        {
 
1299
          gconf_log (GCL_WARNING,
 
1300
                     _("Could not move aside old saved state file '%s': %s"),
 
1301
                     logfile, strerror (errno));
 
1302
          goto out;
 
1303
        }
 
1304
    }
 
1305
 
 
1306
  /* Move the new saved state file into place */
 
1307
  if (rename (tmpfile, logfile) < 0)
 
1308
    {
 
1309
      gconf_log (GCL_WARNING,
 
1310
                 _("Failed to move new save state file into place: %s"),
 
1311
                 strerror (errno));
 
1312
 
 
1313
      /* Try to restore old file */
 
1314
      if (tmpfile2)
 
1315
        {
 
1316
          if (rename (tmpfile2, logfile) < 0)
 
1317
            {
 
1318
              gconf_log (GCL_WARNING,
 
1319
                         _("Failed to restore original saved state file that had been moved to '%s': %s"),
 
1320
                         tmpfile2, strerror (errno));
 
1321
 
 
1322
            }
 
1323
        }
 
1324
      
 
1325
      goto out;
 
1326
    }
 
1327
 
 
1328
  /* Get rid of original saved state file if everything succeeded */
 
1329
  if (tmpfile2)
 
1330
    unlink (tmpfile2);
 
1331
  
 
1332
 out:
 
1333
  if (saveme)
 
1334
    g_string_free (saveme, TRUE);
 
1335
  g_free (logdir);
 
1336
  g_free (logfile);
 
1337
  g_free (tmpfile);
 
1338
  g_free (tmpfile2);
 
1339
 
 
1340
  if (fd >= 0)
 
1341
    close (fd);
 
1342
}
 
1343
 
 
1344
typedef struct _ListenerLogEntry ListenerLogEntry;
 
1345
 
 
1346
struct _ListenerLogEntry
 
1347
{
 
1348
  guint connection_id;
 
1349
  gchar *ior;
 
1350
  gchar *address;
 
1351
  gchar *location;
 
1352
};
 
1353
 
 
1354
static guint
 
1355
listener_logentry_hash (gconstpointer v)
 
1356
{
 
1357
  const ListenerLogEntry *lle = v;
 
1358
 
 
1359
  return
 
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);
 
1364
}
 
1365
 
 
1366
static gboolean
 
1367
listener_logentry_equal (gconstpointer ap, gconstpointer bp)
 
1368
{
 
1369
  const ListenerLogEntry *a = ap;
 
1370
  const ListenerLogEntry *b = bp;
 
1371
 
 
1372
  return
 
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;
 
1377
}
 
1378
 
 
1379
/* Return value indicates whether we "handled" this line of text */
 
1380
static gboolean
 
1381
parse_listener_entry (GHashTable *entries,
 
1382
                      gchar      *text)
 
1383
{
 
1384
  gboolean add;
 
1385
  gchar *p;
 
1386
  gchar *ior;
 
1387
  gchar *address;
 
1388
  gchar *location;
 
1389
  gchar *end;
 
1390
  guint connection_id;
 
1391
  GError *err;
 
1392
  ListenerLogEntry *lle;
 
1393
  ListenerLogEntry *old;
 
1394
  
 
1395
  if (strncmp (text, "ADD", 3) == 0)
 
1396
    {
 
1397
      add = TRUE;
 
1398
      p = text + 3;
 
1399
    }
 
1400
  else if (strncmp (text, "REMOVE", 6) == 0)
 
1401
    {
 
1402
      add = FALSE;
 
1403
      p = text + 6;
 
1404
    }
 
1405
  else
 
1406
    {
 
1407
      return FALSE;
 
1408
    }
 
1409
  
 
1410
  while (*p && isspace (*p))
 
1411
    ++p;
 
1412
 
 
1413
  errno = 0;
 
1414
  end = NULL;
 
1415
  connection_id = strtoul (p, &end, 10);
 
1416
  if (end == p || errno != 0)
 
1417
    {
 
1418
      gconf_log (GCL_DEBUG,
 
1419
                 "Failed to parse connection ID in saved state file");
 
1420
      
 
1421
      return TRUE;
 
1422
    }
 
1423
 
 
1424
  if (connection_id == 0)
 
1425
    {
 
1426
      gconf_log (GCL_DEBUG,
 
1427
                 "Connection ID 0 in saved state file is not valid");
 
1428
      return TRUE;
 
1429
    }
 
1430
  
 
1431
  p = end;
 
1432
 
 
1433
  while (*p && isspace (*p))
 
1434
    ++p;
 
1435
 
 
1436
  err = NULL;
 
1437
  end = NULL;
 
1438
  gconf_unquote_string_inplace (p, &end, &err);
 
1439
  if (err != NULL)
 
1440
    {
 
1441
      gconf_log (GCL_DEBUG,
 
1442
                 "Failed to unquote config source address from saved state file: %s",
 
1443
                 err->message);
 
1444
 
 
1445
      g_error_free (err);
 
1446
      
 
1447
      return TRUE;
 
1448
    }
 
1449
 
 
1450
  address = p;
 
1451
  p = end;
 
1452
 
 
1453
  while (*p && isspace (*p))
 
1454
    ++p;
 
1455
  
 
1456
  err = NULL;
 
1457
  end = NULL;
 
1458
  gconf_unquote_string_inplace (p, &end, &err);
 
1459
  if (err != NULL)
 
1460
    {
 
1461
      gconf_log (GCL_DEBUG,
 
1462
                 "Failed to unquote listener location from saved state file: %s",
 
1463
                 err->message);
 
1464
 
 
1465
      g_error_free (err);
 
1466
      
 
1467
      return TRUE;
 
1468
    }
 
1469
 
 
1470
  location = p;
 
1471
  p = end;
 
1472
 
 
1473
  while (*p && isspace (*p))
 
1474
    ++p;
 
1475
  
 
1476
  err = NULL;
 
1477
  end = NULL;
 
1478
  gconf_unquote_string_inplace (p, &end, &err);
 
1479
  if (err != NULL)
 
1480
    {
 
1481
      gconf_log (GCL_DEBUG,
 
1482
                 "Failed to unquote IOR from saved state file: %s",
 
1483
                 err->message);
 
1484
      
 
1485
      g_error_free (err);
 
1486
      
 
1487
      return TRUE;
 
1488
    }
 
1489
  
 
1490
  ior = p;
 
1491
  p = end;    
 
1492
 
 
1493
  lle = g_new (ListenerLogEntry, 1);
 
1494
  lle->connection_id = connection_id;
 
1495
  lle->address = address;
 
1496
  lle->ior = ior;
 
1497
  lle->location = location;
 
1498
 
 
1499
  if (*(lle->address) == '\0' ||
 
1500
      *(lle->ior) == '\0' ||
 
1501
      *(lle->location) == '\0')
 
1502
    {
 
1503
      gconf_log (GCL_DEBUG,
 
1504
                 "Saved state file listener entry didn't contain all the fields; ignoring.");
 
1505
 
 
1506
      g_free (lle);
 
1507
 
 
1508
      return TRUE;
 
1509
    }
 
1510
  
 
1511
  old = g_hash_table_lookup (entries, lle);
 
1512
 
 
1513
  if (old)
 
1514
    {
 
1515
      if (add)
 
1516
        {
 
1517
          gconf_log (GCL_DEBUG,
 
1518
                     "Saved state file records the same listener added twice; ignoring the second instance");
 
1519
          goto quit;
 
1520
        }
 
1521
      else
 
1522
        {
 
1523
          /* This entry was added, then removed. */
 
1524
          g_hash_table_remove (entries, lle);
 
1525
          goto quit;
 
1526
        }
 
1527
    }
 
1528
  else
 
1529
    {
 
1530
      if (add)
 
1531
        {
 
1532
          g_hash_table_insert (entries, lle, lle);
 
1533
          
 
1534
          return TRUE;
 
1535
        }
 
1536
      else
 
1537
        {
 
1538
          gconf_log (GCL_DEBUG,
 
1539
                     "Saved state file had a removal of a listener that wasn't added; ignoring the removal.");
 
1540
          goto quit;
 
1541
        }
 
1542
    }
 
1543
  
 
1544
 quit:
 
1545
  g_free (lle);
 
1546
 
 
1547
  return TRUE;
 
1548
}                
 
1549
 
 
1550
/* Return value indicates whether we "handled" this line of text */
 
1551
static gboolean
 
1552
parse_client_entry (GHashTable *clients,
 
1553
                    gchar      *text)
 
1554
{
 
1555
  gboolean add;
 
1556
  gchar *ior;
 
1557
  GError *err;
 
1558
  gchar *old;
 
1559
  gchar *p;
 
1560
  gchar *end;
 
1561
  
 
1562
  if (strncmp (text, "CLIENTADD", 9) == 0)
 
1563
    {
 
1564
      add = TRUE;
 
1565
      p = text + 9;
 
1566
    }
 
1567
  else if (strncmp (text, "CLIENTREMOVE", 12) == 0)
 
1568
    {
 
1569
      add = FALSE;
 
1570
      p = text + 12;
 
1571
    }
 
1572
  else
 
1573
    {
 
1574
      return FALSE;
 
1575
    }
 
1576
  
 
1577
  while (*p && isspace (*p))
 
1578
    ++p;
 
1579
  
 
1580
  err = NULL;
 
1581
  end = NULL;
 
1582
  gconf_unquote_string_inplace (p, &end, &err);
 
1583
  if (err != NULL)
 
1584
    {
 
1585
      gconf_log (GCL_DEBUG,
 
1586
                 "Failed to unquote IOR from saved state file: %s",
 
1587
                 err->message);
 
1588
      
 
1589
      g_error_free (err);
 
1590
      
 
1591
      return TRUE;
 
1592
    }
 
1593
  
 
1594
  ior = p;
 
1595
  p = end;    
 
1596
  
 
1597
  old = g_hash_table_lookup (clients, ior);
 
1598
 
 
1599
  if (old)
 
1600
    {
 
1601
      if (add)
 
1602
        {
 
1603
          gconf_log (GCL_DEBUG,
 
1604
                     "Saved state file records the same client added twice; ignoring the second instance");
 
1605
          goto quit;
 
1606
        }
 
1607
      else
 
1608
        {
 
1609
          /* This entry was added, then removed. */
 
1610
          g_hash_table_remove (clients, ior);
 
1611
          goto quit;
 
1612
        }
 
1613
    }
 
1614
  else
 
1615
    {
 
1616
      if (add)
 
1617
        {
 
1618
          g_hash_table_insert (clients, ior, ior);
 
1619
          
 
1620
          return TRUE;
 
1621
        }
 
1622
      else
 
1623
        {
 
1624
          gconf_log (GCL_DEBUG,
 
1625
                     "Saved state file had a removal of a client that wasn't added; ignoring the removal.");
 
1626
          goto quit;
 
1627
        }
 
1628
    }
 
1629
  
 
1630
 quit:
 
1631
 
 
1632
  return TRUE;
 
1633
}
 
1634
 
 
1635
static void
 
1636
restore_client (const gchar *ior)
 
1637
{
 
1638
  ConfigListener cl;
 
1639
  CORBA_Environment ev;
 
1640
  
 
1641
  CORBA_exception_init (&ev);
 
1642
  
 
1643
  cl = CORBA_ORB_string_to_object (gconf_orb_get (),
 
1644
                                   (gchar*)ior,
 
1645
                                   &ev);
 
1646
 
 
1647
  CORBA_exception_free (&ev);
 
1648
  
 
1649
  if (CORBA_Object_is_nil (cl, &ev))
 
1650
    {
 
1651
      CORBA_exception_free (&ev);
 
1652
 
 
1653
      gconf_log (GCL_DEBUG,
 
1654
                 "Client in saved state file no longer exists, not restoring it as a client");
 
1655
      
 
1656
      return;
 
1657
    }
 
1658
 
 
1659
  ConfigListener_drop_all_caches (cl, &ev);
 
1660
  
 
1661
  if (ev._major != CORBA_NO_EXCEPTION)
 
1662
    {
 
1663
      gconf_log (GCL_DEBUG, "Failed to update client in saved state file, probably the client no longer exists");
 
1664
 
 
1665
      goto finished;
 
1666
    }
 
1667
 
 
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.
 
1672
   */
 
1673
  add_client (cl);
 
1674
  
 
1675
 finished:
 
1676
  CORBA_Object_release (cl, &ev);
 
1677
 
 
1678
  CORBA_exception_free (&ev);
 
1679
}
 
1680
 
 
1681
static void
 
1682
restore_listener (GConfDatabase* db,
 
1683
                  ListenerLogEntry *lle)
 
1684
{
 
1685
  ConfigListener cl;
 
1686
  CORBA_Environment ev;
 
1687
  guint new_cnxn;
 
1688
  GError *err;
 
1689
  
 
1690
  CORBA_exception_init (&ev);
 
1691
  
 
1692
  cl = CORBA_ORB_string_to_object (gconf_orb_get (),
 
1693
                                   lle->ior,
 
1694
                                   &ev);
 
1695
 
 
1696
  CORBA_exception_free (&ev);
 
1697
  
 
1698
  if (CORBA_Object_is_nil (cl, &ev))
 
1699
    {
 
1700
      CORBA_exception_free (&ev);
 
1701
 
 
1702
      gconf_log (GCL_DEBUG,
 
1703
                 "Client in saved state file no longer exists, not updating its listener connections");
 
1704
      
 
1705
      return;
 
1706
    }
 
1707
 
 
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.
 
1711
   */
 
1712
 
 
1713
  err = NULL;  
 
1714
  if (!gconfd_logfile_change_listener (db,
 
1715
                                       FALSE, /* remove */
 
1716
                                       lle->connection_id,
 
1717
                                       cl,
 
1718
                                       lle->location,
 
1719
                                       &err))
 
1720
    {
 
1721
      gconf_log (GCL_DEBUG,
 
1722
                 "Failed to cancel previous daemon's listener in saved state file: %s",
 
1723
                 err->message);
 
1724
      g_error_free (err);
 
1725
    }  
 
1726
 
 
1727
  new_cnxn = gconf_database_readd_listener (db, cl, lle->location);
 
1728
 
 
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);
 
1730
  
 
1731
  ConfigListener_update_listener (cl,
 
1732
                                  db->objref,
 
1733
                                  lle->address,
 
1734
                                  lle->connection_id,
 
1735
                                  lle->location,
 
1736
                                  new_cnxn,
 
1737
                                  &ev);
 
1738
  
 
1739
  if (ev._major != CORBA_NO_EXCEPTION)
 
1740
    {
 
1741
      gconf_log (GCL_DEBUG, "Failed to update listener in saved state file, probably the client no longer exists");
 
1742
 
 
1743
      /* listener will get removed next time we try to notify -
 
1744
       * we already appended a cancel of the listener to the
 
1745
       * saved state file.
 
1746
       */
 
1747
      goto finished;
 
1748
    }
 
1749
 
 
1750
  /* Successfully notified client of new connection ID, so put that
 
1751
   * connection ID in the saved state file.
 
1752
   */
 
1753
  err = NULL;  
 
1754
  if (!gconfd_logfile_change_listener (db,
 
1755
                                       TRUE, /* add */
 
1756
                                       new_cnxn,
 
1757
                                       cl,
 
1758
                                       lle->location,
 
1759
                                       &err))
 
1760
    {
 
1761
      gconf_log (GCL_DEBUG,
 
1762
                 "Failed to re-add this daemon's listener ID in saved state file: %s",
 
1763
                 err->message);
 
1764
      g_error_free (err);
 
1765
    }
 
1766
 
 
1767
  /* We updated the listener, and logged that to the saved state
 
1768
   * file. Yay!
 
1769
   */
 
1770
  
 
1771
 finished:
 
1772
  
 
1773
  CORBA_Object_release (cl, &ev);
 
1774
 
 
1775
  CORBA_exception_free (&ev);
 
1776
}
 
1777
 
 
1778
static void
 
1779
listener_logentry_restore_and_destroy_foreach (gpointer key,
 
1780
                                               gpointer value,
 
1781
                                               gpointer data)
 
1782
{
 
1783
  ListenerLogEntry *lle = key;
 
1784
  GConfDatabase *db;
 
1785
  
 
1786
  if (strcmp (lle->address, "def") == 0)
 
1787
    db = default_db;
 
1788
  else
 
1789
    db = obtain_database (lle->address, NULL);
 
1790
  
 
1791
  if (db == NULL)
 
1792
    {
 
1793
      gconf_log (GCL_WARNING,
 
1794
                 _("Unable to restore a listener on address '%s', couldn't resolve the database"),
 
1795
                 lle->address);
 
1796
      return;
 
1797
    }
 
1798
 
 
1799
  restore_listener (db, lle);
 
1800
 
 
1801
  /* We don't need it anymore */
 
1802
  g_free (lle);
 
1803
}
 
1804
 
 
1805
static void
 
1806
restore_client_foreach (gpointer key,
 
1807
                        gpointer value,
 
1808
                        gpointer data)
 
1809
{
 
1810
  restore_client (key);
 
1811
}
 
1812
 
 
1813
 
 
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 */
 
1819
 
 
1820
static gchar*
 
1821
read_line (FILE *f)
 
1822
{
 
1823
  int c;
 
1824
  GString *str;
 
1825
  
 
1826
  str = g_string_new ("");
 
1827
  
 
1828
  flockfile (f);
 
1829
 
 
1830
  while (TRUE)
 
1831
    {
 
1832
      c = getc_unlocked (f);
 
1833
 
 
1834
      switch (c)
 
1835
        {
 
1836
        case EOF:
 
1837
          if (ferror (f))
 
1838
            {
 
1839
              gconf_log (GCL_ERR,
 
1840
                         _("Error reading saved state file: %s"),
 
1841
                         g_strerror (errno));
 
1842
            }
 
1843
 
 
1844
          /* FALL THRU */
 
1845
        case '\n':
 
1846
          goto done;
 
1847
          break;
 
1848
 
 
1849
        default:
 
1850
          g_string_append_c (str, c);
 
1851
          break;
 
1852
        }
 
1853
    }
 
1854
 
 
1855
 done:
 
1856
  funlockfile (f);
 
1857
 
 
1858
  if (str->len == 0)
 
1859
    {
 
1860
      g_string_free (str, TRUE);
 
1861
      return NULL;
 
1862
    }
 
1863
  else
 
1864
    {
 
1865
      gchar *ret;
 
1866
      
 
1867
      ret = str->str;
 
1868
      g_string_free (str, FALSE);
 
1869
      return ret;
 
1870
    }
 
1871
}
 
1872
 
 
1873
static void
 
1874
logfile_read (void)
 
1875
{
 
1876
  gchar *logfile;
 
1877
  gchar *logdir;
 
1878
  GHashTable *entries;
 
1879
  GHashTable *clients;
 
1880
  FILE *f;
 
1881
  gchar *line;
 
1882
  GSList *lines = NULL;
 
1883
  
 
1884
  /* Just for good form */
 
1885
  close_append_handle ();
 
1886
  
 
1887
  get_log_names (&logdir, &logfile);
 
1888
 
 
1889
  f = fopen (logfile, "r");
 
1890
  
 
1891
  if (f == NULL)
 
1892
    {
 
1893
      gconf_log (GCL_ERR, _("Unable to open saved state file '%s': %s"),
 
1894
                 logfile, g_strerror (errno));
 
1895
 
 
1896
      goto finished;
 
1897
    }
 
1898
 
 
1899
  entries = g_hash_table_new (listener_logentry_hash, listener_logentry_equal);
 
1900
  clients = g_hash_table_new (g_str_hash, g_str_equal);
 
1901
 
 
1902
  line = read_line (f);
 
1903
  while (line)
 
1904
    {
 
1905
      if (!parse_listener_entry (entries, line))
 
1906
        {
 
1907
          if (!parse_client_entry (clients, line))
 
1908
            {
 
1909
              gconf_log (GCL_DEBUG,
 
1910
                         "Didn't understand line in saved state file: '%s'", 
 
1911
                         line);
 
1912
              g_free (line);
 
1913
              line = NULL;
 
1914
            }
 
1915
        }
 
1916
 
 
1917
      if (line)
 
1918
        lines = g_slist_prepend (lines, line);
 
1919
      
 
1920
      line = read_line (f);
 
1921
    }
 
1922
  
 
1923
  /* Restore clients first */
 
1924
  g_hash_table_foreach (clients,
 
1925
                        restore_client_foreach,
 
1926
                        NULL);
 
1927
  
 
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.
 
1931
   */
 
1932
  g_hash_table_foreach (entries, 
 
1933
                        listener_logentry_restore_and_destroy_foreach,
 
1934
                        NULL);
 
1935
 
 
1936
  g_hash_table_destroy (entries);
 
1937
  g_hash_table_destroy (clients);
 
1938
 
 
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
 
1941
   * hash.
 
1942
   */
 
1943
  g_slist_foreach (lines, (GFunc)g_free, NULL);
 
1944
  g_slist_free (lines);
 
1945
  
 
1946
 finished:
 
1947
  
 
1948
  g_free (logfile);
 
1949
  g_free (logdir);
 
1950
}
 
1951
 
 
1952
gboolean
 
1953
gconfd_logfile_change_listener (GConfDatabase *db,
 
1954
                                gboolean add,
 
1955
                                guint connection_id,
 
1956
                                ConfigListener listener,
 
1957
                                const gchar *where,
 
1958
                                GError **err)
 
1959
{
 
1960
  gchar *ior = NULL;
 
1961
  gchar *quoted_db_name;
 
1962
  gchar *quoted_where;
 
1963
  gchar *quoted_ior;
 
1964
  
 
1965
  if (!open_append_handle (err))
 
1966
    return FALSE;
 
1967
  
 
1968
  ior = gconf_object_to_string (listener, err);
 
1969
  
 
1970
  if (ior == NULL)
 
1971
    return FALSE;
 
1972
 
 
1973
  quoted_ior = gconf_quote_string (ior);
 
1974
  g_free (ior);
 
1975
  ior = NULL;
 
1976
  
 
1977
  if (db == default_db)
 
1978
    quoted_db_name = gconf_quote_string ("def");
 
1979
  else
 
1980
    {
 
1981
      const gchar *db_name;
 
1982
      
 
1983
      db_name = gconf_database_get_persistent_name (db);
 
1984
      
 
1985
      quoted_db_name = gconf_quote_string (db_name);
 
1986
    }
 
1987
 
 
1988
  quoted_where = gconf_quote_string (where);
 
1989
 
 
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)
 
1994
    goto error;
 
1995
 
 
1996
  if (fflush (append_handle) < 0)
 
1997
    goto error;
 
1998
 
 
1999
  g_free (quoted_db_name);
 
2000
  g_free (quoted_ior);
 
2001
  g_free (quoted_where);
 
2002
  
 
2003
  return TRUE;
 
2004
 
 
2005
 error:
 
2006
 
 
2007
  if (add)
 
2008
    gconf_set_error (err,
 
2009
                     GCONF_ERROR_FAILED,
 
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));
 
2012
  else
 
2013
    gconf_set_error (err,
 
2014
                     GCONF_ERROR_FAILED,
 
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));
 
2017
 
 
2018
  g_free (quoted_db_name);
 
2019
  g_free (quoted_ior);
 
2020
  g_free (quoted_where);
 
2021
 
 
2022
  return FALSE;
 
2023
}
 
2024
 
 
2025
static void
 
2026
log_client_change (const ConfigListener client,
 
2027
                   gboolean add)
 
2028
{
 
2029
  gchar *ior = NULL;
 
2030
  gchar *quoted_ior = NULL;
 
2031
  GError *err;
 
2032
  
 
2033
  err = NULL;
 
2034
  ior = gconf_object_to_string (client, &err);
 
2035
 
 
2036
  if (err != NULL)
 
2037
    {
 
2038
      gconf_log (GCL_WARNING, _("Failed to get IOR for client: %s"),
 
2039
                 err->message);
 
2040
      g_error_free (err);
 
2041
      return;
 
2042
    }
 
2043
      
 
2044
  if (ior == NULL)
 
2045
    return;
 
2046
 
 
2047
  quoted_ior = gconf_quote_string (ior);
 
2048
  g_free (ior);
 
2049
  ior = NULL;
 
2050
  
 
2051
  if (!open_append_handle (&err))
 
2052
    {
 
2053
      gconf_log (GCL_WARNING, _("Failed to open saved state file: %s"),
 
2054
                 err->message);
 
2055
 
 
2056
      g_error_free (err);
 
2057
      
 
2058
      goto error;
 
2059
    }
 
2060
 
 
2061
  /* KEEP IN SYNC with log to string function */
 
2062
  if (fprintf (append_handle, "%s %s\n",
 
2063
               add ? "CLIENTADD" : "CLIENTREMOVE", quoted_ior) < 0)
 
2064
    {
 
2065
      gconf_log (GCL_WARNING,
 
2066
                 _("Failed to write client add to saved state file: %s"),
 
2067
                 strerror (errno));
 
2068
      goto error;
 
2069
    }
 
2070
 
 
2071
  if (fflush (append_handle) < 0)
 
2072
    {
 
2073
      gconf_log (GCL_WARNING,
 
2074
                 _("Failed to flush client add to saved state file: %s"),
 
2075
                 strerror (errno));
 
2076
      goto error;
 
2077
    }
 
2078
 
 
2079
 error:
 
2080
  g_free (ior);
 
2081
  g_free (quoted_ior);
 
2082
}
 
2083
 
 
2084
static void
 
2085
log_client_add (const ConfigListener client)
 
2086
{
 
2087
  log_client_change (client, TRUE);
 
2088
}
 
2089
 
 
2090
static void
 
2091
log_client_remove (const ConfigListener client)
 
2092
{
 
2093
  log_client_change (client, FALSE);
 
2094
}
 
2095
 
 
2096
/*
 
2097
 * Client handling
 
2098
 */
 
2099
 
 
2100
static GHashTable *client_table = NULL;
 
2101
 
 
2102
static void
 
2103
add_client (const ConfigListener client)
 
2104
{
 
2105
  gconfd_need_log_cleanup ();
 
2106
  
 
2107
  if (client_table == NULL)
 
2108
    client_table = g_hash_table_new ((GHashFunc) g_CORBA_Object_hash,
 
2109
                                     (GCompareFunc) g_CORBA_Object_equal);
 
2110
 
 
2111
  if (g_hash_table_lookup (client_table, client))
 
2112
    {
 
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.
 
2116
       */
 
2117
      return;
 
2118
    }
 
2119
  else
 
2120
    {
 
2121
      CORBA_Environment ev;
 
2122
      ConfigListener copy;
 
2123
      
 
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);
 
2128
 
 
2129
      log_client_add (client);
 
2130
 
 
2131
      gconf_log (GCL_DEBUG, "Added a new client");
 
2132
    }
 
2133
}
 
2134
 
 
2135
static void
 
2136
remove_client (const ConfigListener client)
 
2137
{
 
2138
  ConfigListener old_client;
 
2139
  CORBA_Environment ev;
 
2140
 
 
2141
  gconfd_need_log_cleanup ();
 
2142
  
 
2143
  if (client_table == NULL)
 
2144
    goto notfound;
 
2145
  
 
2146
  old_client = g_hash_table_lookup (client_table, 
 
2147
                                    client);
 
2148
 
 
2149
  if (old_client == NULL)
 
2150
    goto notfound;
 
2151
 
 
2152
  g_hash_table_remove (client_table,
 
2153
                       old_client);
 
2154
 
 
2155
  log_client_remove (old_client);
 
2156
  
 
2157
  CORBA_exception_init (&ev);
 
2158
  CORBA_Object_release (old_client, &ev);
 
2159
  CORBA_exception_free (&ev);
 
2160
 
 
2161
  return;
 
2162
  
 
2163
 notfound:
 
2164
  gconf_log (GCL_WARNING, _("Some client removed itself from the GConf server when it hadn't been added."));  
 
2165
}
 
2166
 
 
2167
static void
 
2168
hash_listify_func(gpointer key, gpointer value, gpointer user_data)
 
2169
{
 
2170
  GSList** list_p = user_data;
 
2171
 
 
2172
  *list_p = g_slist_prepend(*list_p, value);
 
2173
}
 
2174
 
 
2175
static GSList*
 
2176
list_clients (void)
 
2177
{
 
2178
  GSList *clients = NULL;
 
2179
 
 
2180
  if (client_table == NULL)
 
2181
    return NULL;
 
2182
 
 
2183
  g_hash_table_foreach (client_table, hash_listify_func, &clients);
 
2184
 
 
2185
  return clients;
 
2186
}
 
2187
 
 
2188
static void
 
2189
log_clients_foreach (gpointer key, gpointer value, gpointer data)
 
2190
{
 
2191
  ConfigListener client;
 
2192
  gchar *ior = NULL;
 
2193
  gchar *quoted_ior = NULL;
 
2194
  GError *err;
 
2195
 
 
2196
  client = value;
 
2197
  
 
2198
  err = NULL;
 
2199
  ior = gconf_object_to_string (client, &err);
 
2200
 
 
2201
  if (err != NULL)
 
2202
    {
 
2203
      gconf_log (GCL_WARNING, _("Failed to get IOR for client: %s"),
 
2204
                 err->message);
 
2205
      g_error_free (err);
 
2206
      return;
 
2207
    }
 
2208
      
 
2209
  if (ior == NULL)
 
2210
    return;
 
2211
 
 
2212
  quoted_ior = gconf_quote_string (ior);
 
2213
  g_free (ior);
 
2214
  ior = NULL;
 
2215
 
 
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);
 
2220
}
 
2221
 
 
2222
static void
 
2223
log_clients_to_string (GString *str)
 
2224
{
 
2225
  if (client_table == NULL)
 
2226
    return;
 
2227
 
 
2228
  g_hash_table_foreach (client_table, log_clients_foreach, str);
 
2229
}
 
2230
 
 
2231
static void
 
2232
drop_old_clients (void)
 
2233
{
 
2234
  GSList *clients;
 
2235
  GSList *tmp;
 
2236
  
 
2237
  clients = list_clients ();
 
2238
 
 
2239
  if (clients)
 
2240
    {
 
2241
      CORBA_Environment ev;
 
2242
 
 
2243
      CORBA_exception_init (&ev);
 
2244
      
 
2245
      tmp = clients;
 
2246
      while (tmp != NULL)
 
2247
        {
 
2248
          ConfigListener cl = tmp->data;
 
2249
          
 
2250
          ConfigListener_ping (cl, &ev);
 
2251
 
 
2252
          if (ev._major != CORBA_NO_EXCEPTION)
 
2253
            {
 
2254
              gconf_log (GCL_DEBUG, "Removing stale client");
 
2255
              
 
2256
              remove_client (cl);
 
2257
              
 
2258
              CORBA_exception_free (&ev);
 
2259
            }
 
2260
          
 
2261
          tmp = g_slist_next (tmp);
 
2262
        }
 
2263
 
 
2264
      g_slist_free (clients);
 
2265
    }
 
2266
}
 
2267
 
 
2268
static guint
 
2269
client_count (void)
 
2270
{
 
2271
  if (client_table == NULL)
 
2272
    return 0;
 
2273
  else
 
2274
    return g_hash_table_size (client_table);
 
2275
}