gconfd.c 65.7 KB
Newer Older
1
/* GConf
2
 * Copyright (C) 1999, 2000 Red Hat Inc.
Havoc Pennington's avatar
sync    
Havoc Pennington committed
3
 * Developed by Havoc Pennington, some code in here borrowed from 
Havoc Pennington's avatar
Havoc Pennington committed
4
 * gnome-name-server and libgnorba (Elliot Lee)
5
6
7
8
9
10
11
12
13
14
15
16
17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
18
19
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
20
21
22
23
24
 */


/*
 * This is the per-user configuration daemon.
Havoc Pennington's avatar
sync    
Havoc Pennington committed
25
 * (has debug crap in it now)
26
27
 */

Havoc Pennington's avatar
sync    
Havoc Pennington committed
28
#include <config.h>
29

Havoc Pennington's avatar
sync    
Havoc Pennington committed
30
#include "gconf-internals.h"
31
#include "gconf-sources.h"
32
#include "gconf-listeners.h"
33
#include "gconf-locale.h"
34
#include "gconf-schema.h"
35
#include "gconf.h"
36
37
#include "gconfd.h"
#include "gconf-database.h"
38

39
40
41
42
43
#ifdef HAVE_DBUS
#include "gconf-database-dbus.h"
#include "gconfd-dbus.h"
#endif

44
#ifdef HAVE_CORBA
Martin Baulig's avatar
Martin Baulig committed
45
#include <orbit/orbit.h>
Havoc Pennington's avatar
Havoc Pennington committed
46

47
#include "GConfX.h"
48
#endif
49

Havoc Pennington's avatar
sync    
Havoc Pennington committed
50
51
52
53
54
55
56
57
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
58
#include <errno.h>
Havoc Pennington's avatar
etc.    
Havoc Pennington committed
59
#include <ctype.h>
60
#include <time.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
61
#ifdef HAVE_SYS_WAIT_H
62
#include <sys/wait.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
63
#endif
64
#include <locale.h>
65

66
67
#include <dbus/dbus-glib-lowlevel.h>

68
69
static void logfile_remove (void);

70
71
72
73
74
#ifdef G_OS_WIN32
#include <io.h>
#include <conio.h>
#define _WIN32_WINNT 0x0500 
#include <windows.h>
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

static int
fsync (int fd)
{
  HANDLE h = (HANDLE) _get_osfhandle (fd);
  DWORD err;

  if (h == INVALID_HANDLE_VALUE)
    {
      errno = EBADF;
      return -1;
    }

  if (!FlushFileBuffers (h))
    {
      err = GetLastError ();
      switch (err)
        {
           case ERROR_INVALID_HANDLE:
             errno = EINVAL;
             break;

           default:
             errno = EIO;
        }
      return -1;
    }

  return 0;
}
105
106
#endif

107
/* This makes hash table safer when debugging */
108
#ifndef GCONF_ENABLE_DEBUG
109
110
111
112
113
114
115
116
117
#define safe_g_hash_table_insert g_hash_table_insert
#else
static void
safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
{
  gpointer oldkey = NULL, oldval = NULL;

  if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
    {
118
      gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
119
                (gchar*) key);
120
121
122
123
124
125
126
127
128
      return;
    }
  else
    {
      g_hash_table_insert(ht, key, value);
    }
}
#endif

Havoc Pennington's avatar
sync    
Havoc Pennington committed
129
130
131
/*
 * Declarations
 */
132

133
134
static void     gconf_main            (void);
static gboolean gconf_main_is_running (void);
135

136
#ifdef HAVE_CORBA
137
138
static void logfile_save (void);
static void logfile_read (void);
Havoc Pennington's avatar
Havoc Pennington committed
139
140
static void log_client_add (const ConfigListener client);
static void log_client_remove (const ConfigListener client);
141

142
143
144
145
146
147
static void    add_client            (const ConfigListener  client);
static void    remove_client         (const ConfigListener  client);
static GSList *list_clients          (void);
static void    log_clients_to_string (GString              *str);
static void    drop_old_clients      (void);
static guint   client_count          (void);
148
#endif
149

150
static void    enter_shutdown          (void);
Havoc Pennington's avatar
etc.    
Havoc Pennington committed
151

152
153
static void                 init_databases (void);
static void                 shutdown_databases (void);
154
155
156
#ifdef HAVE_DBUS
static void                 reload_databases (void);
#endif
157
158
159
static void                 set_default_database (GConfDatabase* db);
static void                 register_database (GConfDatabase* db);
static void                 unregister_database (GConfDatabase* db);
160
static GConfDatabase*       lookup_database (GSList *addresses);
161
static void                 drop_old_databases (void);
162
static gboolean             no_databases_in_use (void);
Havoc Pennington's avatar
Havoc Pennington committed
163

164
165
166
167
168
169
170
171
172
/*
 * Flag indicating that we are shutting down, so return errors
 * on any attempted operation. We do this instead of unregistering with
 * OAF or deactivating the server object, because we want to avoid
 * another gconfd starting up before we finish shutting down.
 */

static gboolean in_shutdown = FALSE;

173
174
175
176
177
178
/*
 * Flag indicating we received a SIGHUP and we should reaload
 * all sources during the next periodic_cleanup()
 */
static gboolean need_db_reload = FALSE;

179
180
181
182
183
184
/*
 * Flag indicating whether to prepare for respawn or logout
 * when exiting
 */
static gboolean clean_shutdown_requested = FALSE;

185
#ifdef HAVE_CORBA
Havoc Pennington's avatar
Havoc Pennington committed
186
187
188
189
/* 
 * CORBA goo
 */

190
static ConfigServer2 server = CORBA_OBJECT_NIL;
191
static PortableServer_POA the_poa;
Havoc Pennington's avatar
Havoc Pennington committed
192
static GConfLock *daemon_lock = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
193

194
195
196
static ConfigDatabase
gconfd_get_default_database(PortableServer_Servant servant,
                            CORBA_Environment* ev);
197

198
199
200
201
static ConfigDatabase
gconfd_get_database(PortableServer_Servant servant,
                    const CORBA_char* address,
                    CORBA_Environment* ev);
202

203
204
205
206
207
static ConfigDatabase
gconfd_get_database_for_addresses (PortableServer_Servant           servant,
				   const ConfigServer2_AddressList *addresses,
				   CORBA_Environment               *ev);

208
209
210
211
212
213
214
215
216
217
static void
gconfd_add_client (PortableServer_Servant servant,
                   const ConfigListener client,
                   CORBA_Environment *ev);

static void
gconfd_remove_client (PortableServer_Servant servant,
                      const ConfigListener client,
                      CORBA_Environment *ev);

Havoc Pennington's avatar
Havoc Pennington committed
218
static CORBA_long
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
219
220
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev);

Havoc Pennington's avatar
Havoc Pennington committed
221
static void
222
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev);
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
223

Havoc Pennington's avatar
sync    
Havoc Pennington committed
224
static PortableServer_ServantBase__epv base_epv = {
Havoc Pennington's avatar
Havoc Pennington committed
225
226
227
228
229
  NULL,
  NULL,
  NULL
};

Havoc Pennington's avatar
sync    
Havoc Pennington committed
230
static POA_ConfigServer__epv server_epv = { 
231
  NULL,
232
233
  gconfd_get_default_database,
  gconfd_get_database,
234
235
  gconfd_add_client,
  gconfd_remove_client,
236
  gconfd_ping,
237
  gconfd_shutdown
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
238
};
Havoc Pennington's avatar
sync    
Havoc Pennington committed
239

240
241
242
243
244
245
246
static POA_ConfigServer2__epv server2_epv = { 
  NULL,
  gconfd_get_database_for_addresses
};

static POA_ConfigServer2__vepv poa_server_vepv = { &base_epv, &server_epv, &server2_epv };
static POA_ConfigServer2 poa_server_servant = { NULL, &poa_server_vepv };
Havoc Pennington's avatar
Havoc Pennington committed
247

248
249
250
static ConfigDatabase
gconfd_get_default_database(PortableServer_Servant servant,
                            CORBA_Environment* ev)
251
{
252
  GConfDatabase *db;
Havoc Pennington's avatar
sync    
Havoc Pennington committed
253

254
255
256
  if (gconfd_check_in_shutdown (ev))
    return CORBA_OBJECT_NIL;
  
257
  db = lookup_database (NULL);
Havoc Pennington's avatar
sync    
Havoc Pennington committed
258

259
  if (db)
260
    return CORBA_Object_duplicate (db->objref, ev);
Havoc Pennington's avatar
sync    
Havoc Pennington committed
261
  else
262
    return CORBA_OBJECT_NIL;
Havoc Pennington's avatar
Havoc Pennington committed
263
264
}

265
266
267
268
static ConfigDatabase
gconfd_get_database(PortableServer_Servant servant,
                    const CORBA_char* address,
                    CORBA_Environment* ev)
269
{
270
  GConfDatabase *db;
271
  GSList *addresses;
272
  GError* error = NULL;  
273

274
275
276
  if (gconfd_check_in_shutdown (ev))
    return CORBA_OBJECT_NIL;
  
277
  addresses = g_slist_append (NULL, (char *) address);
278
  db = gconfd_obtain_database (addresses, &error);
279
  g_slist_free (addresses);
Havoc Pennington's avatar
Havoc Pennington committed
280

281
  if (db != NULL)
282
    return CORBA_Object_duplicate (db->objref, ev);
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

  gconf_set_exception (&error, ev);

  return CORBA_OBJECT_NIL;
}

static ConfigDatabase
gconfd_get_database_for_addresses (PortableServer_Servant           servant,
				   const ConfigServer2_AddressList *seq,
				   CORBA_Environment               *ev)
{
  GConfDatabase  *db;
  GSList         *addresses = NULL;
  GError         *error = NULL;  
  int             i;

  if (gconfd_check_in_shutdown (ev))
300
    return CORBA_OBJECT_NIL;
301
302
303
304
305

  i = 0;
  while (i < seq->_length)
    addresses = g_slist_append (addresses, seq->_buffer [i++]);

306
  db = gconfd_obtain_database (addresses, &error);
307
308
309
310
311
312
313
314
315

  g_slist_free (addresses);

  if (db != NULL)
    return CORBA_Object_duplicate (db->objref, ev);

  gconf_set_exception (&error, ev);

  return CORBA_OBJECT_NIL;
316
317
318
319
320
321
322
}

static void
gconfd_add_client (PortableServer_Servant servant,
                   const ConfigListener client,
                   CORBA_Environment *ev)
{
323
324
325
  if (gconfd_check_in_shutdown (ev))
    return;
  
Havoc Pennington's avatar
Havoc Pennington committed
326
  add_client (client);
327
328
329
330
331
332
333
}

static void
gconfd_remove_client (PortableServer_Servant servant,
                      const ConfigListener client,
                      CORBA_Environment *ev)
{
334
335
336
  if (gconfd_check_in_shutdown (ev))
    return;
  
Havoc Pennington's avatar
Havoc Pennington committed
337
  remove_client (client);
Havoc Pennington's avatar
Havoc Pennington committed
338
339
}

Havoc Pennington's avatar
Havoc Pennington committed
340
static CORBA_long
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
341
342
gconfd_ping(PortableServer_Servant servant, CORBA_Environment *ev)
{
343
344
345
  if (gconfd_check_in_shutdown (ev))
    return 0;
  
Havoc Pennington's avatar
Hmm    
Havoc Pennington committed
346
347
348
  return getpid();
}

Havoc Pennington's avatar
Havoc Pennington committed
349
static void
350
351
gconfd_shutdown(PortableServer_Servant servant, CORBA_Environment *ev)
{
352
353
354
  if (gconfd_check_in_shutdown (ev))
    return;
  
Havoc Pennington's avatar
Havoc Pennington committed
355
  gconf_log(GCL_DEBUG, _("Shutdown request received"));
356

357
  clean_shutdown_requested = TRUE;
358
  gconfd_main_quit();
359
}
360
#endif /* HAVE_CORBA */
361

Havoc Pennington's avatar
sync    
Havoc Pennington committed
362
363
364
365
/*
 * Main code
 */

366
367
/* This needs to be called before we register with OAF
 */
368
369
static GConfSources *
gconf_server_get_default_sources(void)
Havoc Pennington's avatar
sync    
Havoc Pennington committed
370
{
371
  GSList* addresses;
Havoc Pennington's avatar
sync    
Havoc Pennington committed
372
  GList* tmp;
Havoc Pennington's avatar
Havoc Pennington committed
373
  gboolean have_writable = FALSE;
374
  gchar* conffile;
375
  GConfSources* sources = NULL;
376
  GError* error = NULL;
377
  
378
  conffile = g_strconcat(GCONF_CONFDIR, "/path", NULL);
379

380
  addresses = gconf_load_source_path(conffile, NULL);
381
382
383

  g_free(conffile);

384
#ifdef GCONF_ENABLE_DEBUG
385
  /* -- Debug only */
386
  
387
388
  if (addresses == NULL)
    {
389
      gconf_log(GCL_DEBUG, _("gconfd compiled with debugging; trying to load gconf.path from the source directory"));
390
      conffile = g_strconcat(GCONF_SRCDIR, "/gconf/gconf.path", NULL);
391
      addresses = gconf_load_source_path(conffile, NULL);
392
393
394
395
      g_free(conffile);
    }

  /* -- End of Debug Only */
396
#endif
397
398

  if (addresses == NULL)
399
    {      
400
      const char *configdir = g_get_user_config_dir ();
Tor Lillqvist's avatar
Tor Lillqvist committed
401

402
403
      /* Try using the default address xml:readwrite:$(USERCONFIGDIR)/gconf */
      addresses = g_slist_append(addresses, g_strconcat("xml:readwrite:", configdir, "/gconf", NULL));
404

405
      gconf_log(GCL_DEBUG, _("No configuration files found. Trying to use the default configuration source `%s'"), (char *)addresses->data);
406
    }
Havoc Pennington's avatar
sync    
Havoc Pennington committed
407
408
409
  
  if (addresses == NULL)
    {
410
411
412
      /* We want to stay alive but do nothing, because otherwise every
         request would result in another failed gconfd being spawned.  
      */
413
      gconf_log(GCL_ERR, _("No configuration sources in the source path. Configuration won't be saved; edit %s%s"), GCONF_CONFDIR, "/path");
414
      /* don't request error since there aren't any addresses */
415
      sources = gconf_sources_new_from_addresses(NULL, NULL);
416

417
      return sources;
418
419
    }
  else
420
    {
421
      sources = gconf_sources_new_from_addresses(addresses, &error);
Havoc Pennington's avatar
sync    
Havoc Pennington committed
422

423
424
      if (error != NULL)
        {
425
          gconf_log(GCL_ERR, _("Error loading some configuration sources: %s"),
426
                    error->message);
427

428
          g_error_free(error);
429
430
          error = NULL;
        }
431
      
432
      gconf_address_list_free(addresses);
Havoc Pennington's avatar
sync    
Havoc Pennington committed
433

434
      g_assert(sources != NULL);
Havoc Pennington's avatar
sync    
Havoc Pennington committed
435

436
      if (sources->sources == NULL)
437
        gconf_log(GCL_ERR, _("No configuration source addresses successfully resolved. Can't load or store configuration data"));
438
    
439
      tmp = sources->sources;
Havoc Pennington's avatar
sync    
Havoc Pennington committed
440

441
      while (tmp != NULL)
Havoc Pennington's avatar
sync    
Havoc Pennington committed
442
        {
443
444
          if (((GConfSource*)tmp->data)->flags & GCONF_SOURCE_ALL_WRITEABLE)
            {
Havoc Pennington's avatar
Havoc Pennington committed
445
              have_writable = TRUE;
446
447
              break;
            }
Havoc Pennington's avatar
sync    
Havoc Pennington committed
448

449
450
          tmp = g_list_next(tmp);
        }
Havoc Pennington's avatar
sync    
Havoc Pennington committed
451

Havoc Pennington's avatar
Havoc Pennington committed
452
453
      /* In this case, some sources may still return TRUE from their writable() function */
      if (!have_writable)
454
        gconf_log(GCL_WARNING, _("No writable configuration sources successfully resolved. May be unable to save some configuration changes"));
455

456
      return sources;
457
    }
Havoc Pennington's avatar
sync    
Havoc Pennington committed
458
459
}

460
461
462
463
464
465
466
467
468
469
470
static void
gconf_server_load_sources(void)
{
  GConfSources* sources;

  sources = gconf_server_get_default_sources();

  /* Install the sources as the default database */
  set_default_database (gconf_database_new(sources));
}

471
472
473
474
/*
 * Signal handlers should not log debug messages as this code is non-reentrant.
 * Please avoid calling gconf_log in this function.
 */
Havoc Pennington's avatar
sync    
Havoc Pennington committed
475
476
477
static void
signal_handler (int signo)
{
478
479
480
  static gint in_fatal = 0;

  /* avoid loops */
481
  if (in_fatal > 0)
482
483
484
485
    return;
  
  ++in_fatal;
  
486
  switch (signo) {
487
  case SIGFPE:
Tor Lillqvist's avatar
Tor Lillqvist committed
488
#ifdef SIGPIPE
489
  case SIGPIPE:
Tor Lillqvist's avatar
Tor Lillqvist committed
490
#endif
491
492
493
494
495
    /* Go ahead and try the full cleanup on these,
     * though it could well not work out very well.
     */
    enter_shutdown ();

496
497
    clean_shutdown_requested = FALSE;

498
499
    /* let the fatal signals interrupt us */
    --in_fatal;
500
    
501
    if (gconf_main_is_running ())
502
      gconfd_main_quit ();
503
504
505
506
507
508
    
    break;

  case SIGTERM:
    enter_shutdown ();

509
510
    clean_shutdown_requested = TRUE;

511
    /* let the fatal signals interrupt us */
512
    --in_fatal;
513
514
    
    if (gconf_main_is_running ())
515
      gconfd_main_quit ();
516
    break;
Havoc Pennington's avatar
Havoc Pennington committed
517

Tor Lillqvist's avatar
Tor Lillqvist committed
518
#ifdef SIGHUP
519
520
521
522
523
524
  case SIGHUP:
    --in_fatal;

    /* reload sources during next periodic_cleanup() */
    need_db_reload = TRUE;
    break;
Tor Lillqvist's avatar
Tor Lillqvist committed
525
#endif
526

Tor Lillqvist's avatar
Tor Lillqvist committed
527
#ifdef SIGUSR1
Havoc Pennington's avatar
Havoc Pennington committed
528
  case SIGUSR1:
529
530
    --in_fatal;
    
Havoc Pennington's avatar
Havoc Pennington committed
531
532
533
    /* it'd be nice to log a message here but it's not very safe, so */
    gconf_log_debug_messages = !gconf_log_debug_messages;
    break;
Tor Lillqvist's avatar
Tor Lillqvist committed
534
#endif
Havoc Pennington's avatar
sync    
Havoc Pennington committed
535
536
    
  default:
537
    clean_shutdown_requested = FALSE;
Tor Lillqvist's avatar
Tor Lillqvist committed
538
539
540
#ifndef HAVE_SIGACTION
    signal (signo, signal_handler);
#endif
541
    break;
Havoc Pennington's avatar
sync    
Havoc Pennington committed
542
  }
543
544
}

545
#ifdef HAVE_CORBA
546
PortableServer_POA
547
gconf_get_poa (void)
548
549
550
{
  return the_poa;
}
551
#endif
552

553
#ifdef HAVE_CORBA
554
555
static const char *
get_introspection_xml (void)
Havoc Pennington's avatar
Havoc Pennington committed
556
{
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  return "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
         "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
         "<node>\n"
         "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
         "    <method name=\"Introspect\">\n"
         "      <arg name=\"introspection_xml\" direction=\"out\" type=\"s\"/>\n"
         "    </method>\n"
         "  </interface>\n"
         "  <interface name=\"org.gnome.GConf\">\n"
         "    <method name=\"GetIOR\">\n"
         "      <arg name=\"ior\" direction=\"out\" type=\"s\"/>\n"
         "    </method>\n"
         "  </interface>\n"
         "</node>\n";
}

static DBusHandlerResult
bus_message_handler (DBusConnection *connection,
                     DBusMessage    *message,
576
                     void           *user_data)
577
578
579
580
{
  DBusMessage *reply;

  reply = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
581

582
583
584
  if (dbus_message_is_signal (message,
                              DBUS_INTERFACE_LOCAL,
                              "Disconnected"))
Havoc Pennington's avatar
Havoc Pennington committed
585
    {
586
587
588
589
      /* Since the log file is per-session, we should make sure it's
       * removed when the session is over.
       */
      clean_shutdown_requested = TRUE;
590
      gconfd_main_quit ();
591
      return DBUS_HANDLER_RESULT_HANDLED;
Havoc Pennington's avatar
Havoc Pennington committed
592
    }
593
594
595
  else if (dbus_message_is_method_call (message,
                                        "org.freedesktop.DBus.Introspectable",
                                        "Introspect"))
Havoc Pennington's avatar
Havoc Pennington committed
596
    {
597
598
599
600
601
602
603
604
      const char *introspection_xml;

      introspection_xml = get_introspection_xml ();

      reply = dbus_message_new_method_return (message);
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &introspection_xml,
                                DBUS_TYPE_INVALID);

Havoc Pennington's avatar
Havoc Pennington committed
605
    }
606
607
608
609
610
  else if (dbus_message_is_method_call (message,
                                        "org.gnome.GConf",
                                        "GetIOR"))
    {
      const char *ior;
Tor Lillqvist's avatar
Tor Lillqvist committed
611

612
613
614
615
616
617
618
      ior = gconf_get_daemon_ior ();

      reply = dbus_message_new_method_return (message);
      dbus_message_append_args (reply, DBUS_TYPE_STRING, &ior, DBUS_TYPE_INVALID);
    }

  if (reply != NULL)
Havoc Pennington's avatar
Havoc Pennington committed
619
    {
620
621
622
      dbus_connection_send (connection, reply, NULL);
      dbus_message_unref (reply);
      return DBUS_HANDLER_RESULT_HANDLED;
Havoc Pennington's avatar
Havoc Pennington committed
623
    }
624

625
626
627
628
629
630
631
632
633
634
635
636
637
638
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static DBusConnection *
get_on_d_bus (void)
{
  DBusConnection *connection;
  DBusError bus_error;
  int result;

  dbus_error_init (&bus_error);
  connection = dbus_bus_get (DBUS_BUS_SESSION, &bus_error);

  if (dbus_error_is_set (&bus_error))
Havoc Pennington's avatar
Havoc Pennington committed
639
    {
640
641
642
      gconf_log (GCL_ERR, _("Could not connect to session bus: %s"), bus_error.message);
      dbus_error_free (&bus_error);
      return NULL;
Havoc Pennington's avatar
Havoc Pennington committed
643
    }
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

  dbus_connection_setup_with_g_main (connection, NULL);

  if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
                                  bus_message_handler, NULL, NULL))
    {
      dbus_connection_unref (connection);
      return NULL;
    }

  dbus_connection_set_exit_on_disconnect (connection, FALSE);

  result = dbus_bus_request_name (connection, "org.gnome.GConf",
                                  0, &bus_error);

  if (dbus_error_is_set (&bus_error))
    {
      gconf_log (GCL_WARNING,
                 _("Failed to get bus name for daemon, exiting: %s"),
                 bus_error.message);
      dbus_error_free (&bus_error);
    }

  if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
      dbus_connection_unref (connection);
      return NULL;
    }

  return connection;
Havoc Pennington's avatar
Havoc Pennington committed
674
}
675
#endif
Havoc Pennington's avatar
Havoc Pennington committed
676

677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
#ifdef ENABLE_DEFAULTS_SERVICE
/* listen on system bus for defaults changes */

static DBusHandlerResult
system_bus_message_handler (DBusConnection *connection,
			    DBusMessage    *message,
			    void           *user_data)
{
  DBusMessage *reply;

  reply = NULL;

  if (dbus_message_is_signal (message,
			      "org.gnome.GConf.Defaults",
                              "SystemSet"))
    {
      DBusError bus_error;
      char **keys;
      int n_keys;

      dbus_error_init (&bus_error);
      if (dbus_message_get_args (message, &bus_error,
				 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys,
				 DBUS_TYPE_INVALID))
	{
	  char **key;
	  GConfSources *system_sources;
	  GSList addresses;

	  gconf_log (GCL_DEBUG, "System defaults changed.  Notifying.");

708
	  addresses.data = "xml:merged:" GCONF_ETCDIR "/gconf.xml.system";
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
	  addresses.next = NULL;
	  system_sources = gconf_sources_new_from_addresses (&addresses, NULL);

	  gconfd_clear_cache_for_sources (system_sources);

	  for (key = keys; *key; key++)
	    gconfd_notify_other_listeners (NULL, system_sources, *key);

	  gconf_sources_free (system_sources);

	  dbus_free_string_array (keys);
	}
      else
        {
	  gconf_log (GCL_DEBUG, "SystemSet signal received, but error getting message: %s", bus_error.message);
	}
      dbus_error_free (&bus_error);

      return DBUS_HANDLER_RESULT_HANDLED;
    }

  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static DBusConnection *
get_on_system_bus (void)
{
  DBusConnection *connection;
  DBusError bus_error;

  dbus_error_init (&bus_error);
  connection = dbus_bus_get (DBUS_BUS_SYSTEM, &bus_error);

  if (dbus_error_is_set (&bus_error))
    {
      gconf_log (GCL_ERR, _("Could not connect to system bus: %s"), bus_error.message);
      dbus_error_free (&bus_error);
      return NULL;
    }

  dbus_connection_setup_with_g_main (connection, NULL);

  dbus_bus_add_match (connection, "type='signal',interface='org.gnome.GConf.Defaults'", &bus_error);
  dbus_connection_flush(connection);
  if (dbus_error_is_set (&bus_error))
    {
      gconf_log (GCL_DEBUG, "Failed to add signal match to system bus: %s", bus_error.message);
      dbus_connection_unref (connection);
      return NULL;
    }

  if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
                                   system_bus_message_handler, NULL, NULL))
    {
      gconf_log (GCL_DEBUG, "Failed to add message filter to system bus.");
      dbus_connection_unref (connection);
      return NULL;
    }

  return connection;
}
#endif  /* ENABLE_DEFAULTS_SERVICE */

772
773
774
775
776
777
778
779
780
781
782
783
784
#ifdef G_OS_WIN32

static void
wait_console_window (void)
{
  SetConsoleTitle ("GConf daemon exiting. Type any character to close this window.");
  printf ("\n"
	  "(GConf daemon exiting. Type any character to close this window)\n");
  _getch ();
}

#endif

785
786
787
int 
main(int argc, char** argv)
{
Tor Lillqvist's avatar
Tor Lillqvist committed
788
#ifdef HAVE_SIGACTION
Havoc Pennington's avatar
sync    
Havoc Pennington committed
789
790
  struct sigaction act;
  sigset_t empty_mask;
791
  sigset_t full_mask;
Tor Lillqvist's avatar
Tor Lillqvist committed
792
#endif
793
794

#ifdef HAVE_CORBA
Havoc Pennington's avatar
Havoc Pennington committed
795
796
  CORBA_Environment ev;
  CORBA_ORB orb;
797
  gchar* ior;
798
799
800
  DBusConnection *connection;
#endif

801
  int dev_null_fd;
802
  int exit_code = 0;
803
  int write_byte_fd;
804
805
806
807

  _gconf_init_i18n ();
  setlocale (LC_ALL, "");
  textdomain (GETTEXT_PACKAGE);
808
809
810
811
812
813
  
  /* Now this is an argument parser */
  if (argc > 1)
    write_byte_fd = atoi (argv[1]);
  else
    write_byte_fd = -1;
Havoc Pennington's avatar
Havoc Pennington committed
814
  
Havoc Pennington's avatar
Havoc Pennington committed
815
816
817
  /* This is so we don't prevent unmounting of devices. We divert
   * all messages to syslog
   */
818
  if (g_chdir ("/") < 0)
819
    {
820
       g_printerr ("Could not change to root directory: %s\n",
821
		   g_strerror (errno));
822
823
824
825
826
       exit (1);
    }

  if (!g_getenv ("GCONF_DEBUG_OUTPUT"))
    {
Tor Lillqvist's avatar
Tor Lillqvist committed
827
      dev_null_fd = open (DEV_NULL, O_RDWR);
828
829
830
831
832
833
834
      if (dev_null_fd >= 0)
        {
	  dup2 (dev_null_fd, 0);
	  dup2 (dev_null_fd, 1);
	  dup2 (dev_null_fd, 2);
	}
    }
835
836
837
  else
    {
      gconf_log_debug_messages = TRUE;
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
#ifdef G_OS_WIN32
      if (fileno (stdout) != -1 &&
	  _get_osfhandle (fileno (stdout)) != -1)
	{
	  /* stdout is fine, presumably redirected to a file or pipe */
	}
      else
	{
	  int allocated_new_console = FALSE;

	  typedef BOOL (* WINAPI AttachConsole_t) (DWORD);

	  AttachConsole_t p_AttachConsole =
	    (AttachConsole_t) GetProcAddress (GetModuleHandle ("kernel32.dll"), "AttachConsole");

	  if (p_AttachConsole != NULL)
	    {
	      if (!AttachConsole (ATTACH_PARENT_PROCESS))
		{
		  if (AllocConsole ())
		    allocated_new_console = TRUE;
		}

	      freopen ("CONOUT$", "w", stdout);
	      dup2 (fileno (stdout), 1);
	      freopen ("CONOUT$", "w", stderr);
	      dup2 (fileno (stderr), 2);

	      if (allocated_new_console)
		{
		  SetConsoleTitle ("GConf daemon debugging output. You can minimize this window, but don't close it.");
		  printf ("You asked for debugging output by setting the GCONF_DEBUG_OUTPUT\n"
			  "environment variable, so here it is.\n"
			  "\n");
		  atexit (wait_console_window);
		}
	    }
	}
#endif
877
    }
Havoc Pennington's avatar
Havoc Pennington committed
878
  
879
  umask (022);
Havoc Pennington's avatar
Havoc Pennington committed
880
  
881
882
  gconf_set_daemon_mode(TRUE);
  
883
  gconf_log (GCL_DEBUG, _("starting (version %s), pid %u user '%s'"), 
884
885
886
             VERSION, (guint)getpid(), g_get_user_name());

#ifdef GCONF_ENABLE_DEBUG
Havoc Pennington's avatar
Havoc Pennington committed
887
  gconf_log (GCL_DEBUG, "GConf was built with debugging features enabled");
888
#endif
889
  
Havoc Pennington's avatar
sync    
Havoc Pennington committed
890
  /* Session setup */
Tor Lillqvist's avatar
Tor Lillqvist committed
891
#ifdef HAVE_SIGACTION
892
893
894
  sigfillset (&full_mask);
  sigprocmask (SIG_UNBLOCK, &full_mask, NULL);

Havoc Pennington's avatar
sync    
Havoc Pennington committed
895
896
897
898
  sigemptyset (&empty_mask);
  act.sa_handler = signal_handler;
  act.sa_mask    = empty_mask;
  act.sa_flags   = 0;
899
900
901
  sigaction (SIGTERM,  &act, NULL);
  sigaction (SIGHUP,  &act, NULL);
  sigaction (SIGUSR1,  &act, NULL);
Tor Lillqvist's avatar
Tor Lillqvist committed
902

Havoc Pennington's avatar
sync    
Havoc Pennington committed
903
  act.sa_handler = SIG_IGN;
904
  sigaction (SIGINT, &act, NULL);
Tor Lillqvist's avatar
Tor Lillqvist committed
905
906
907
908
909
910
911
912
913
#else
  signal (SIGTERM, signal_handler);
#ifdef SIGHUP
  signal (SIGHUP,  signal_handler);
#endif
#ifdef SIGUSR1
  signal (SIGUSR1,  signal_handler);
#endif
#endif
Havoc Pennington's avatar
sync    
Havoc Pennington committed
914

915
#ifdef HAVE_CORBA
Havoc Pennington's avatar
sync    
Havoc Pennington committed
916
  CORBA_exception_init(&ev);
917
#endif
Havoc Pennington's avatar
sync    
Havoc Pennington committed
918

919
  init_databases ();
Havoc Pennington's avatar
Havoc Pennington committed
920

921
922
923
924
#ifdef HAVE_DBUS
  if (!gconfd_dbus_init ())
    return 1;
#endif
925
926

#ifdef HAVE_CORBA
927
  orb = gconf_orb_get ();
Havoc Pennington's avatar
Havoc Pennington committed
928
  
929
  POA_ConfigServer2__init (&poa_server_servant, &ev);
Havoc Pennington's avatar
Havoc Pennington committed
930
  
931
932
  the_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
  PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(the_poa, &ev), &ev);
933

934
  server = PortableServer_POA_servant_to_reference(the_poa,
Havoc Pennington's avatar
Havoc Pennington committed
935
936
                                                   &poa_server_servant,
                                                   &ev);
937
  if (CORBA_Object_is_nil(server, &ev)) 
Havoc Pennington's avatar
Havoc Pennington committed
938
    {
939
      gconf_log(GCL_ERR, _("Failed to get object reference for ConfigServer"));
Havoc Pennington's avatar
Havoc Pennington committed
940
941
      return 1;
    }
Havoc Pennington's avatar
Havoc Pennington committed
942

943
  /* Needs to be done before loading sources */
Havoc Pennington's avatar
Havoc Pennington committed
944
945
946
947
  ior = CORBA_ORB_object_to_string (orb, server, &ev);
  gconf_set_daemon_ior (ior);
  CORBA_free (ior);

948
  connection = get_on_d_bus ();
949

950
  if (connection != NULL)
Havoc Pennington's avatar
Havoc Pennington committed
951
    {
952
953
954
955
      /* This loads backends and so on. It needs to be done before
       * we can handle any requests, so before we hit the
       * main loop. if daemon_lock == NULL we won't hit the
       * main loop.
Havoc Pennington's avatar
Havoc Pennington committed
956
       */
957
958
      gconf_server_load_sources ();
    }
959
960
#endif

961
962
963
#ifdef HAVE_DBUS
  gconf_server_load_sources ();
#endif
964
965

#ifdef HAVE_CORBA
966
967
968
969
970
971
972
  /* notify caller that we're done either getting the lock
   * or not getting it
   */
  if (write_byte_fd >= 0)
    {
      char buf[1] = { 'g' };
      if (write (write_byte_fd, buf, 1) != 1)
Havoc Pennington's avatar
Havoc Pennington committed
973
        {
Danilo Šegan's avatar
Danilo Šegan committed
974
          gconf_log (GCL_ERR, _("Failed to write byte to pipe file descriptor %d so client program may hang: %s"), write_byte_fd, g_strerror (errno));
Havoc Pennington's avatar
Havoc Pennington committed
975
        }
Tor Lillqvist's avatar
Tor Lillqvist committed
976
      
977
      close (write_byte_fd);
Havoc Pennington's avatar
Havoc Pennington committed
978
    }
979
  
980
  if (connection == NULL)
981
    {
982
      enter_shutdown ();
983
      shutdown_databases ();
984
      
985
      return 1;
986
    }  
987
988
989

  /* Read saved log file, if any */
  logfile_read ();
990
991
#endif

992
993
994
995
#ifdef ENABLE_DEFAULTS_SERVICE 
  get_on_system_bus ();
#endif

996
  gconf_main ();
997

998
999
1000
1001
1002
1003
1004
  if (in_shutdown)
    exit_code = 1; /* means someone already called enter_shutdown() */
  
  /* This starts bouncing all incoming requests (and we aren't running
   * the main loop anyway, so they won't get processed)
   */
  enter_shutdown ();
1005

1006
#ifdef HAVE_CORBA
1007
  /* Save current state in logfile (may compress the logfile a good
1008
1009
   * bit) if we're exiting but may respawn.  Clean up the logfile, if
   * the session is going away.
1010
   */
1011
1012
1013
1014
  if (clean_shutdown_requested)
    logfile_remove ();
  else
    logfile_save ();
1015
#endif
1016
  
1017
  shutdown_databases ();
Havoc Pennington's avatar
Havoc Pennington committed
1018

1019
  gconfd_locale_cache_drop ();
1020

1021
#ifdef HAVE_CORBA
Havoc Pennington's avatar
Havoc Pennington committed
1022
1023
  if (daemon_lock)
    {
1024
1025
      GError *err;

Havoc Pennington's avatar
Havoc Pennington committed
1026
1027
1028
1029
      err = NULL;
      gconf_release_lock (daemon_lock, &err);
      if (err != NULL)
        {
1030
          gconf_log (GCL_WARNING, _("Error releasing lockfile: %s"),
Havoc Pennington's avatar
Havoc Pennington committed
1031
1032
1033
1034
1035
1036
                     err->message);
          g_error_free (err);
        }
    }

  daemon_lock = NULL;
1037
#endif
1038
  
1039
  gconf_log (GCL_DEBUG, _("Exiting"));
1040

1041
  return exit_code;
1042
}
1043

Havoc Pennington's avatar
sync    
Havoc Pennington committed
1044
1045
1046
1047
1048
/*
 * Main loop
 */

static GSList* main_loops = NULL;
1049
static guint timeout_id = 0;
Havoc Pennington's avatar
Havoc Pennington committed
1050
static gboolean need_log_cleanup = FALSE;
1051
1052

static gboolean
Havoc Pennington's avatar
Havoc Pennington committed
1053
1054
periodic_cleanup_timeout(gpointer data)
{  
1055
1056
1057
1058
1059
  if (need_db_reload)
    {
      gconf_log (GCL_INFO, _("SIGHUP received, reloading all databases"));

      need_db_reload = FALSE;
1060
#ifdef HAVE_CORBA
1061
      logfile_save ();
1062
1063
      shutdown_databases ();
      init_databases ();
1064
1065
      gconf_server_load_sources ();
      logfile_read ();
1066
1067
1068
#endif
#ifdef HAVE_DBUS
      reload_databases ();
1069
#endif
1070
1071
    }
  
1072
  gconf_log (GCL_DEBUG, "Performing periodic cleanup, expiring cache cruft");
Havoc Pennington's avatar
Havoc Pennington committed
1073
  
1074
#ifdef HAVE_CORBA
1075
  drop_old_clients ();
1076
#endif
1077
  drop_old_databases ();
1078

1079
1080
1081
#ifdef HAVE_DBUS
  if (no_databases_in_use () && gconfd_dbus_client_count () == 0)
#else
1082
  if (no_databases_in_use () && client_count () == 0)
1083
#endif
1084
    {
1085
      gconf_log (GCL_INFO, _("GConf server is not in use, shutting down."));
1086
      gconfd_main_quit ();
1087
1088
1089
      return FALSE;
    }
  
1090
  /* expire old locale cache entries */
1091
1092
  gconfd_locale_cache_expire ();

1093
#ifdef HAVE_CORBA
Havoc Pennington's avatar
Havoc Pennington committed
1094
1095
1096
1097
1098
1099
  if (!need_log_cleanup)
    {
      gconf_log (GCL_DEBUG, "No log file saving needed in periodic cleanup handler");
      return TRUE;
    }
  
1100
1101
  /* Compress the running state file */
  logfile_save ();
1102
#endif
Havoc Pennington's avatar
Havoc Pennington committed
1103
1104

  need_log_cleanup = FALSE;
1105
1106