~ubuntu-branches/ubuntu/wily/hal/wily

« back to all changes in this revision

Viewing changes to .pc/60-create-run-hald-directory.patch/hald/hald.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2011-08-12 16:41:12 UTC
  • mfrom: (1.1.23 sid)
  • Revision ID: james.westby@ubuntu.com-20110812164112-74c2yxeuv0hwchhj
Tags: 0.5.14-7
* debian/control
  - Drop Suggests: gnome-device-manager, this package no longer is in the
    archive.
* debian/patches/60-create-run-hald-directory.patch
  - Create /var/run/hald/ when starting hald. This directory contains
    runtime data like pid files and sockets and needs to be created
    dynamically as (/var)/run resides on a tmpfs. (Closes: #632900)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 * CVSID: $Id$
 
3
 *
 
4
 * hald.c : main startup for HAL daemon
 
5
 *
 
6
 * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
 
7
 * Copyright (C) 2005 Danny Kukawka, <danny.kukawka@web.de>
 
8
 * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk>
 
9
 *
 
10
 * Licensed under the Academic Free License version 2.1
 
11
 *
 
12
 * This program is free software; you can redistribute it and/or modify
 
13
 * it under the terms of the GNU General Public License as published by
 
14
 * the Free Software Foundation; either version 2 of the License, or
 
15
 * (at your option) any later version.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 * GNU General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
25
 *
 
26
 **************************************************************************/
 
27
 
 
28
#ifdef HAVE_CONFIG_H
 
29
#  include <config.h>
 
30
#endif
 
31
 
 
32
#include <stdio.h>
 
33
#include <stdlib.h>
 
34
 
 
35
#ifdef HAVE_MALLOPT
 
36
#include <malloc.h>
 
37
#endif
 
38
 
 
39
#include <string.h>
 
40
#include <unistd.h>
 
41
#include <getopt.h>
 
42
#include <pwd.h>
 
43
#include <stdint.h>
 
44
#include <sys/stat.h>
 
45
#include <fcntl.h>
 
46
#include <errno.h>
 
47
#include <signal.h>
 
48
#include <grp.h>
 
49
#include <syslog.h>
 
50
#include <sys/time.h>
 
51
#include <sys/resource.h>
 
52
#include <dbus/dbus.h>
 
53
#include <dbus/dbus-glib.h>
 
54
#include <dbus/dbus-glib-lowlevel.h>
 
55
 
 
56
/*#include "master_slave.h"*/
 
57
 
 
58
#include "logger.h"
 
59
#include "hald.h"
 
60
#include "device_store.h"
 
61
#include "device_info.h"
 
62
#include "osspec.h"
 
63
#include "hald_dbus.h"
 
64
#include "util.h"
 
65
#include "hald_runner.h"
 
66
#include "util_helper.h"
 
67
#include "mmap_cache.h"
 
68
 
 
69
static void delete_pid(void)
 
70
{
 
71
        unlink(HALD_PID_FILE);
 
72
}
 
73
 
 
74
static HalDeviceStore *global_device_list = NULL;
 
75
 
 
76
static HalDeviceStore *temporary_device_list = NULL;
 
77
 
 
78
 
 
79
static void
 
80
addon_terminated (HalDevice *device, guint32 exit_type, 
 
81
                  gint return_code, gchar **error,
 
82
                  gpointer data1, gpointer data2)
 
83
{
 
84
        HAL_INFO (("in addon_terminated for udi=%s", hal_device_get_udi (device)));
 
85
 
 
86
        /* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
 
87
 
 
88
        /* however, the world can stop, mark this addon as ready 
 
89
         * (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
 
90
         */
 
91
        if (hal_device_inc_num_ready_addons (device)) {
 
92
                if (hal_device_are_all_addons_ready (device)) {
 
93
                        manager_send_signal_device_added (device);
 
94
                }
 
95
        }
 
96
}
 
97
 
 
98
 
 
99
 
 
100
 
 
101
static void
 
102
gdl_store_changed (HalDeviceStore *store, HalDevice *device,
 
103
                   gboolean is_added, gpointer user_data)
 
104
{
 
105
        if (is_added) {
 
106
                HalDeviceStrListIter iter;
 
107
 
 
108
                HAL_INFO (("Added device to GDL; udi=%s", hal_device_get_udi(device)));
 
109
 
 
110
                for (hal_device_property_strlist_iter_init (device, "info.addons", &iter);
 
111
                     hal_device_property_strlist_iter_is_valid (&iter);
 
112
                     hal_device_property_strlist_iter_next (&iter)) {
 
113
                        const gchar *command_line;
 
114
                        gchar *extra_env[2] = {"HALD_ACTION=addon", NULL};
 
115
                        
 
116
                        command_line = hal_device_property_strlist_iter_get_value (&iter);
 
117
 
 
118
                        if (hald_runner_start(device, command_line, extra_env, addon_terminated, NULL, NULL)) {
 
119
                                HAL_INFO (("Started addon %s for udi %s", 
 
120
                                           command_line, hal_device_get_udi(device)));
 
121
                                hal_device_inc_num_addons (device);
 
122
                        } else {
 
123
                                HAL_ERROR (("Cannot start addon %s for udi %s", 
 
124
                                            command_line, hal_device_get_udi(device)));
 
125
                        }
 
126
                }
 
127
                for (hal_device_property_strlist_iter_init (device, "info.addons.singleton", &iter);
 
128
                     hal_device_property_strlist_iter_is_valid (&iter);
 
129
                     hal_device_property_strlist_iter_next (&iter)) {
 
130
                        const gchar *command_line;
 
131
 
 
132
                        command_line = hal_device_property_strlist_iter_get_value (&iter);
 
133
 
 
134
                        if (hald_singleton_device_added (command_line, device))
 
135
                                hal_device_inc_num_addons (device);
 
136
                        else
 
137
                                HAL_ERROR(("Couldn't add device to singleton"));
 
138
                }
 
139
 
 
140
        } else {
 
141
                HalDeviceStrListIter iter;
 
142
 
 
143
                HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
 
144
                for (hal_device_property_strlist_iter_init (device, "info.addons.singleton", &iter);
 
145
                     hal_device_property_strlist_iter_is_valid (&iter);
 
146
                     hal_device_property_strlist_iter_next (&iter)) {
 
147
                        const gchar *command_line;
 
148
 
 
149
                        command_line = hal_device_property_strlist_iter_get_value (&iter);
 
150
 
 
151
                        hald_singleton_device_removed (command_line, device);
 
152
                }
 
153
 
 
154
                hald_runner_kill_device(device);
 
155
        }
 
156
 
 
157
        /*hal_device_print (device);*/
 
158
 
 
159
        if (is_added) {
 
160
                if (hal_device_are_all_addons_ready (device)) {
 
161
                        manager_send_signal_device_added (device);
 
162
                }
 
163
        } else {
 
164
                if (hal_device_are_all_addons_ready (device)) {
 
165
                        manager_send_signal_device_removed (device);
 
166
                }
 
167
        }
 
168
}
 
169
 
 
170
static void
 
171
gdl_property_changed (HalDeviceStore *store, HalDevice *device,
 
172
                      const char *key, gboolean added, gboolean removed,
 
173
                      gpointer user_data)
 
174
{
 
175
        if (hal_device_are_all_addons_ready (device)) {
 
176
                device_send_signal_property_modified (device, key, removed, added);
 
177
        }
 
178
 
 
179
        /* only execute the callouts if the property _changed_ */
 
180
        if (added == FALSE && removed == FALSE)
 
181
                /*hal_callout_property (device, key)*/;
 
182
}
 
183
 
 
184
static void
 
185
gdl_capability_added (HalDeviceStore *store, HalDevice *device,
 
186
                      const char *capability, gpointer user_data)
 
187
{
 
188
        if (hal_device_are_all_addons_ready (device)) {
 
189
                manager_send_signal_new_capability (device, capability);
 
190
        }
 
191
        /*hal_callout_capability (device, capability, TRUE)*/;
 
192
}
 
193
 
 
194
static void
 
195
gdl_lock_acquired (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner)
 
196
{
 
197
        if (hal_device_are_all_addons_ready (device)) {
 
198
                if (strncmp (lock_name, "Global.", 7) == 0 && 
 
199
                    strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) {
 
200
                        manager_send_signal_interface_lock_acquired (lock_name + 7, lock_owner);
 
201
                } else {
 
202
                        device_send_signal_interface_lock_acquired (device, lock_name, lock_owner);
 
203
                }
 
204
        }
 
205
}
 
206
 
 
207
static void
 
208
gdl_lock_released (HalDeviceStore *store, HalDevice *device, const char *lock_name, const char *lock_owner)
 
209
{
 
210
        if (hal_device_are_all_addons_ready (device)) {
 
211
                if (strncmp (lock_name, "Global.", 7) == 0 && 
 
212
                    strcmp (hal_device_get_udi (device), "/org/freedesktop/Hal/devices/computer") == 0) {
 
213
                        manager_send_signal_interface_lock_released (lock_name + 7, lock_owner);
 
214
                } else {
 
215
                        device_send_signal_interface_lock_released (device, lock_name, lock_owner);
 
216
                }
 
217
        }
 
218
}
 
219
 
 
220
HalDeviceStore *
 
221
hald_get_gdl (void)
 
222
{
 
223
        if (global_device_list == NULL) {
 
224
                global_device_list = hal_device_store_new ();
 
225
                
 
226
                g_signal_connect (global_device_list,
 
227
                                  "store_changed",
 
228
                                  G_CALLBACK (gdl_store_changed), NULL);
 
229
                g_signal_connect (global_device_list,
 
230
                                  "device_property_changed",
 
231
                                  G_CALLBACK (gdl_property_changed), NULL);
 
232
                g_signal_connect (global_device_list,
 
233
                                  "device_capability_added",
 
234
                                  G_CALLBACK (gdl_capability_added), NULL);
 
235
                g_signal_connect (global_device_list,
 
236
                                  "device_lock_acquired",
 
237
                                  G_CALLBACK (gdl_lock_acquired), NULL);
 
238
                g_signal_connect (global_device_list,
 
239
                                  "device_lock_released",
 
240
                                  G_CALLBACK (gdl_lock_released), NULL);
 
241
        }
 
242
 
 
243
        return global_device_list;
 
244
}
 
245
 
 
246
HalDeviceStore *
 
247
hald_get_tdl (void)
 
248
{
 
249
        if (temporary_device_list == NULL) {
 
250
                temporary_device_list = hal_device_store_new ();
 
251
                
 
252
        }
 
253
 
 
254
        return temporary_device_list;
 
255
}
 
256
 
 
257
void
 
258
hald_compute_udi (gchar *dst, gsize dstsize, const gchar *format, ...)
 
259
{
 
260
        int i;
 
261
        char buf[256];
 
262
        va_list args;
 
263
 
 
264
        va_start (args, format);
 
265
        hal_util_compute_udi_valist (hald_get_gdl (), dst, dstsize, format, args);
 
266
        va_end (args);
 
267
 
 
268
        hal_util_validate_udi (dst, dstsize);
 
269
 
 
270
        if (hal_device_store_find (hald_get_gdl (), dst) == NULL &&
 
271
            hal_device_store_find (hald_get_tdl (), dst) == NULL)
 
272
                goto out;
 
273
 
 
274
        for (i = 0; ; i++) {
 
275
                g_snprintf (buf, sizeof(buf), "%s_%d", dst, i);
 
276
                if (hal_device_store_find (hald_get_gdl (), buf) == NULL &&
 
277
                    hal_device_store_find (hald_get_tdl (), buf) == NULL) {
 
278
                        g_strlcpy (dst, buf, dstsize);
 
279
                        goto out;
 
280
                }
 
281
        }
 
282
 
 
283
out:
 
284
        ;
 
285
 
 
286
}
 
287
 
 
288
/** 
 
289
 * usage: 
 
290
 *
 
291
 * Print out program usage.
 
292
 */
 
293
static void
 
294
usage (void)
 
295
{
 
296
        fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]\n");
 
297
        fprintf (stderr,
 
298
                 "\n"
 
299
                 "        --daemon=yes|no       Become a daemon\n"
 
300
                 "        --verbose=yes|no      Print out debug (overrides HALD_VERBOSE)\n"
 
301
                 "        --retain-privileges   Retain privileges (for debugging)\n"
 
302
                 "        --child-timeout=time  Set this timout for the child prober. A larger\n"
 
303
                 "                              number than the default 250s is required for systems\n"
 
304
                 "                              with many resources to be probed at boot time\n"
 
305
                 "        --use-syslog          Print out debug messages to syslog instead of\n"
 
306
                 "                              stderr. Use this option to get debug messages\n"
 
307
                 "                              if hald runs as a daemon.\n"
 
308
                 "        --help                Show this information and exit\n"
 
309
                 "        --version             Output version information and exit\n"
 
310
                 "        --exit-after-probing  Exit when probing is complete. Useful only\n"
 
311
                 "                              when profiling hald.\n"
 
312
                 "\n"
 
313
                 "The HAL daemon detects devices present in the system and provides the\n"
 
314
                 "org.freedesktop.Hal service through the system-wide message bus provided\n"
 
315
                 "by D-BUS.\n"
 
316
                 "\n"
 
317
                 "For more information visit http://freedesktop.org/Software/hal\n"
 
318
                 "\n");
 
319
}
 
320
 
 
321
/** If #TRUE, we will daemonize */
 
322
static dbus_bool_t opt_become_daemon = TRUE;
 
323
 
 
324
/** If #TRUE, we will retain privs */
 
325
static dbus_bool_t opt_retain_privileges = FALSE;
 
326
 
 
327
/** If #TRUE, we will spew out debug */
 
328
dbus_bool_t hald_is_verbose = FALSE;
 
329
dbus_bool_t hald_use_syslog = FALSE;
 
330
static dbus_bool_t hald_debug_exit_after_probing = FALSE;
 
331
 
 
332
#ifdef HAVE_POLKIT
 
333
PolKitContext *pk_context;
 
334
#endif
 
335
 
 
336
static int sigterm_unix_signal_pipe_fds[2];
 
337
static GIOChannel *sigterm_iochn;
 
338
 
 
339
static void 
 
340
handle_sigterm (int value)
 
341
{
 
342
        ssize_t written;
 
343
        static char marker[1] = {'S'};
 
344
 
 
345
        /* write a 'S' character to the other end to tell about
 
346
         * the signal. Note that 'the other end' is a GIOChannel thingy
 
347
         * that is only called from the mainloop - thus this is how we
 
348
         * defer this since UNIX signal handlers are evil
 
349
         *
 
350
         * Oh, and write(2) is indeed reentrant */
 
351
        written = write (sigterm_unix_signal_pipe_fds[1], marker, 1);
 
352
}
 
353
 
 
354
static gboolean
 
355
sigterm_iochn_data (GIOChannel *source, 
 
356
                    GIOCondition condition, 
 
357
                    gpointer user_data)
 
358
{
 
359
        GError *err = NULL;
 
360
        gchar data[1];
 
361
        gsize bytes_read;
 
362
 
 
363
        /* Empty the pipe */
 
364
        if (G_IO_STATUS_NORMAL != 
 
365
            g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
 
366
                HAL_ERROR (("Error emptying sigterm pipe: %s",
 
367
                                   err->message));
 
368
                g_error_free (err);
 
369
                goto out;
 
370
        }
 
371
 
 
372
        HAL_INFO (("Caught SIGTERM, initiating shutdown"));
 
373
        hald_runner_kill_all();
 
374
        exit (0);
 
375
 
 
376
out:
 
377
        return TRUE;
 
378
}
 
379
 
 
380
 
 
381
/** This is set to #TRUE if we are probing and #FALSE otherwise */
 
382
dbus_bool_t hald_is_initialising;
 
383
 
 
384
static int startup_daemonize_pipe[2];
 
385
 
 
386
 
 
387
/*--------------------------------------------------------------------------------------------------*/
 
388
 
 
389
static gboolean child_died = FALSE;
 
390
 
 
391
static void 
 
392
handle_sigchld (int value)
 
393
{
 
394
        child_died = TRUE;
 
395
}
 
396
 
 
397
static int 
 
398
parent_wait_for_child (guint timeout, int child_fd, pid_t child_pid)
 
399
{
 
400
        fd_set rfds;
 
401
        fd_set efds;
 
402
        struct timeval tv;
 
403
        int retval;
 
404
        int ret;
 
405
 
 
406
        signal(SIGCHLD, handle_sigchld);
 
407
 
 
408
        /* wait for either
 
409
         *
 
410
         * o Child writes something to the child_fd; means that device
 
411
         *   probing is completed and the parent should exit with success
 
412
         *
 
413
         * o Child is killed (segfault etc.); means that parent should exit
 
414
         *   with failure
 
415
         *
 
416
         * o Timeout; means that we should kill the child and exit with
 
417
         *   failure
 
418
         *
 
419
         */
 
420
 
 
421
        FD_ZERO(&rfds);
 
422
        FD_SET(child_fd, &rfds);
 
423
        FD_ZERO(&efds);
 
424
        FD_SET(child_fd, &efds);
 
425
        /* Wait up to a set time for device probing */
 
426
        tv.tv_sec = timeout;
 
427
        tv.tv_usec = 0;
 
428
 
 
429
        retval = select (child_fd + 1, &rfds, NULL, &efds, &tv);
 
430
 
 
431
        if (child_died) {
 
432
                /* written from handle_sigchld */
 
433
                ret = 1;
 
434
                goto out;
 
435
        }
 
436
 
 
437
        if (retval > 0) {
 
438
                /* means child wrote to socket or closed it; all good */
 
439
                ret = 0;
 
440
                goto out;
 
441
        }
 
442
 
 
443
        /* assume timeout; kill child */
 
444
        kill (child_pid, SIGTERM);
 
445
        ret = 2;
 
446
 
 
447
out:
 
448
        return ret;
 
449
}
 
450
 
 
451
/*--------------------------------------------------------------------------------------------------*/
 
452
 
 
453
#ifdef HAVE_POLKIT
 
454
 
 
455
static gboolean
 
456
_polkit_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
 
457
{
 
458
        int fd;
 
459
        PolKitContext *pk_context = user_data;
 
460
        fd = g_io_channel_unix_get_fd (channel);
 
461
        polkit_context_io_func (pk_context, fd);
 
462
        return TRUE;
 
463
}
 
464
 
 
465
static int 
 
466
_polkit_io_add_watch (PolKitContext *pk_context, int fd)
 
467
{
 
468
        guint id = 0;
 
469
        GIOChannel *channel;
 
470
        channel = g_io_channel_unix_new (fd);
 
471
        if (channel == NULL)
 
472
                goto out;
 
473
        id = g_io_add_watch (channel, G_IO_IN, _polkit_io_watch_have_data, pk_context);
 
474
        if (id == 0) {
 
475
                g_io_channel_unref (channel);
 
476
                goto out;
 
477
        }
 
478
        g_io_channel_unref (channel);
 
479
out:
 
480
        return id;
 
481
}
 
482
 
 
483
static void 
 
484
_polkit_io_remove_watch (PolKitContext *pk_context, int watch_id)
 
485
{
 
486
        g_source_remove (watch_id);
 
487
}
 
488
 
 
489
static guint _polkit_cooloff_timer = 0;
 
490
 
 
491
static gboolean
 
492
_polkit_config_really_changed (gpointer user_data)
 
493
{
 
494
        HAL_INFO (("Acting on PolicyKit config change"));
 
495
        _polkit_cooloff_timer = 0;
 
496
        reconfigure_all_policy ();
 
497
        return FALSE;
 
498
}
 
499
 
 
500
static void
 
501
_polkit_config_changed_cb (PolKitContext *pk_context, gpointer user_data)
 
502
{
 
503
        HAL_INFO (("PolicyKit reports that the config have changed; starting cool-off timer"));
 
504
 
 
505
        /* Start a cool-off timer since we get a lot of events within
 
506
         * a short time-frame...
 
507
         */
 
508
 
 
509
        if (_polkit_cooloff_timer > 0) {
 
510
                /* cancel old cool-off timer */
 
511
                g_source_remove (_polkit_cooloff_timer);
 
512
                HAL_INFO (("restarting cool-off timer"));
 
513
        }
 
514
#ifdef HAVE_GLIB_2_14
 
515
        _polkit_cooloff_timer = g_timeout_add_seconds (1,
 
516
                                                       _polkit_config_really_changed,
 
517
                                                       NULL);
 
518
#else
 
519
        _polkit_cooloff_timer = g_timeout_add (1000, /* one second... */
 
520
                                               _polkit_config_really_changed,
 
521
                                               NULL);
 
522
#endif
 
523
}
 
524
 
 
525
#endif /* HAVE_POLKIT */
 
526
 
 
527
 
 
528
/**  
 
529
 *  main:
 
530
 *  @argc:               Number of arguments
 
531
 *  @argv:               Array of arguments
 
532
 *  Returns:             Exit code
 
533
 *
 
534
 *  Entry point for HAL daemon
 
535
 */
 
536
int
 
537
main (int argc, char *argv[])
 
538
{
 
539
        GMainLoop *loop;
 
540
        guint sigterm_iochn_listener_source_id;
 
541
        guint opt_child_timeout;
 
542
#ifdef HAVE_POLKIT
 
543
        PolKitError *p_error;
 
544
#endif
 
545
        openlog ("hald", LOG_PID, LOG_DAEMON);
 
546
 
 
547
#ifdef HAVE_MALLOPT
 
548
 
 
549
#define HAL_MMAP_THRESHOLD 100
 
550
#define HAL_TRIM_THRESHOLD 100
 
551
 
 
552
        /* We use memory in small chunks, thus optimize
 
553
           it this way.
 
554
         */
 
555
        mallopt(M_MMAP_THRESHOLD, HAL_MMAP_THRESHOLD);
 
556
        mallopt(M_TRIM_THRESHOLD, HAL_TRIM_THRESHOLD);
 
557
 
 
558
#endif
 
559
 
 
560
#ifdef HALD_MEMLEAK_DBG
 
561
        /*g_mem_set_vtable (glib_mem_profiler_table);*/
 
562
#endif
 
563
 
 
564
        g_type_init ();
 
565
 
 
566
        if (getenv ("HALD_VERBOSE"))
 
567
                hald_is_verbose = TRUE;
 
568
        else
 
569
                hald_is_verbose = FALSE;
 
570
 
 
571
        /* our helpers are installed into libexec, so adjust out $PATH
 
572
         * to include this at the end (since we want to overide in
 
573
         * run-hald.sh and friends)
 
574
         */
 
575
        GString *path = g_string_new(getenv("PATH"));
 
576
        if ( path->len > 0 ) {
 
577
                g_string_append_c(path, ':');   
 
578
        }
 
579
        
 
580
        g_string_append_printf(path, "%s:%s", PACKAGE_LIBEXEC_DIR, PACKAGE_SCRIPT_DIR);
 
581
 
 
582
        setenv ("PATH", path->str, TRUE);
 
583
        g_string_free(path, TRUE);
 
584
 
 
585
        /* set the default child timeout to 250 seconds */
 
586
        opt_child_timeout = 250;
 
587
 
 
588
        while (1) {
 
589
                int c;
 
590
                int option_index = 0;
 
591
                const char *opt;
 
592
                static struct option long_options[] = {
 
593
                        {"exit-after-probing", 0, NULL, 0},
 
594
                        {"daemon", 1, NULL, 0},
 
595
                        {"verbose", 1, NULL, 0},
 
596
                        {"retain-privileges", 0, NULL, 0},
 
597
                        {"child-timeout", 1, NULL, 0},
 
598
                        {"use-syslog", 0, NULL, 0},
 
599
                        {"help", 0, NULL, 0},
 
600
                        {"version", 0, NULL, 0},
 
601
                        {NULL, 0, NULL, 0}
 
602
                };
 
603
 
 
604
                c = getopt_long (argc, argv, "",
 
605
                                 long_options, &option_index);
 
606
                if (c == -1)
 
607
                        break;
 
608
 
 
609
                switch (c) {
 
610
                case 0:
 
611
                        opt = long_options[option_index].name;
 
612
 
 
613
                        if (strcmp (opt, "help") == 0) {
 
614
                                usage ();
 
615
                                return 0;
 
616
                        } else if (strcmp (opt, "version") == 0) {
 
617
                                fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
 
618
                                return 0;
 
619
                        } else if (strcmp (opt, "exit-after-probing") == 0) {
 
620
                                hald_debug_exit_after_probing = TRUE;
 
621
                        } else if (strcmp (opt, "child-timeout") == 0) {
 
622
                                opt_child_timeout = atoi (optarg);
 
623
                        } else if (strcmp (opt, "daemon") == 0) {
 
624
                                if (strcmp ("yes", optarg) == 0) {
 
625
                                        opt_become_daemon = TRUE;
 
626
                                } else if (strcmp ("no", optarg) == 0) {
 
627
                                        opt_become_daemon = FALSE;
 
628
                                } else {
 
629
                                        usage ();
 
630
                                        return 1;
 
631
                                }
 
632
                        } else if (strcmp (opt, "verbose") == 0) {
 
633
                                if (strcmp ("yes", optarg) == 0) {
 
634
                                        hald_is_verbose = TRUE;
 
635
                                } else if (strcmp ("no", optarg) == 0) {
 
636
                                        hald_is_verbose = FALSE;
 
637
                                } else {
 
638
                                        usage ();
 
639
                                        return 1;
 
640
                                }
 
641
                        } else if (strcmp (opt, "retain-privileges") == 0) {
 
642
                                opt_retain_privileges = TRUE;
 
643
                        } else if (strcmp (opt, "use-syslog") == 0) {
 
644
                                hald_use_syslog = TRUE;
 
645
                        }
 
646
 
 
647
                        break;
 
648
 
 
649
                default:
 
650
                        usage ();
 
651
                        return 1;
 
652
                        break;
 
653
                }
 
654
        }
 
655
 
 
656
        if (hald_is_verbose)
 
657
                logger_enable ();
 
658
        else
 
659
                logger_disable ();
 
660
 
 
661
        if (hald_use_syslog)
 
662
                logger_enable_syslog ();
 
663
        else
 
664
                logger_disable_syslog ();
 
665
 
 
666
        /* will fork into two; only the child will return here if we are successful */
 
667
        /*master_slave_setup ();
 
668
          sleep (100000000);*/
 
669
 
 
670
 
 
671
        loop = g_main_loop_new (NULL, FALSE);
 
672
 
 
673
        HAL_INFO ((PACKAGE_STRING));
 
674
        HAL_INFO (("using child timeout %is", opt_child_timeout));
 
675
        
 
676
        if (opt_become_daemon) {
 
677
                int child_pid;
 
678
                int dev_null_fd;
 
679
                int pf;
 
680
                ssize_t written;
 
681
                char pid[9];
 
682
                
 
683
                HAL_INFO (("Will daemonize"));
 
684
                HAL_INFO (("Becoming a daemon"));
 
685
 
 
686
                if (pipe (startup_daemonize_pipe) != 0) {
 
687
                        fprintf (stderr, "Could not setup pipe: %s\n", strerror(errno));
 
688
                        exit (1);
 
689
                }
 
690
 
 
691
 
 
692
                if (chdir ("/") < 0) {
 
693
                        fprintf (stderr, "Could not chdir to /: %s\n", strerror(errno));
 
694
                        exit (1);
 
695
                }
 
696
 
 
697
                child_pid = fork ();
 
698
                switch (child_pid) {
 
699
                case -1:
 
700
                        fprintf (stderr, "Cannot fork(): %s\n", strerror(errno));
 
701
                        break;
 
702
 
 
703
                case 0:
 
704
                        /* child */
 
705
 
 
706
                        dev_null_fd = open ("/dev/null", O_RDWR);
 
707
                        /* ignore if we can't open /dev/null */
 
708
                        if (dev_null_fd >= 0) {
 
709
                                /* attach /dev/null to stdout, stdin, stderr */
 
710
                                dup2 (dev_null_fd, 0);
 
711
                                dup2 (dev_null_fd, 1);
 
712
                                dup2 (dev_null_fd, 2);
 
713
                                close (dev_null_fd);
 
714
                        }
 
715
 
 
716
                        umask (022);
 
717
                        break;
 
718
 
 
719
                default:
 
720
                        /* parent, block until child writes */
 
721
                        exit (parent_wait_for_child (opt_child_timeout, startup_daemonize_pipe[0], child_pid));
 
722
                        break;
 
723
                }
 
724
 
 
725
                /* Create session */
 
726
                setsid ();
 
727
 
 
728
                /* remove old pid file */
 
729
                unlink (HALD_PID_FILE);
 
730
 
 
731
                /* Make a new one */
 
732
                if ((pf= open (HALD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
 
733
                        snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
 
734
                        written = write (pf, pid, strlen(pid));
 
735
                        close (pf);
 
736
                        atexit (delete_pid);
 
737
                }
 
738
        } else {
 
739
                HAL_INFO (("Will not daemonize"));
 
740
        }
 
741
 
 
742
        /* we need to do stuff when we are expected to terminate, thus
 
743
         * this involves looking for SIGTERM; UNIX signal handlers are
 
744
         * evil though, so set up a pipe to transmit the signal.
 
745
         */
 
746
 
 
747
        /* create pipe */
 
748
        if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
 
749
                DIE (("Could not setup pipe, errno=%d", errno));
 
750
        }
 
751
        
 
752
        /* setup glib handler - 0 is for reading, 1 is for writing */
 
753
        sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
 
754
        if (sigterm_iochn == NULL)
 
755
                DIE (("Could not create GIOChannel"));
 
756
        
 
757
        /* get callback when there is data to read */
 
758
        sigterm_iochn_listener_source_id = g_io_add_watch (
 
759
                sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
 
760
        
 
761
        /* Finally, setup unix signal handler for TERM */
 
762
        signal (SIGTERM, handle_sigterm);
 
763
 
 
764
        /* set up the local dbus server */
 
765
        if (!hald_dbus_local_server_init ())
 
766
                return 1;
 
767
 
 
768
        if (!hald_dbus_init_preprobe ()) {
 
769
                return 1;
 
770
        }
 
771
 
 
772
        /* Start the runner helper daemon */
 
773
        if (!hald_runner_start_runner ()) {
 
774
                return 1;
 
775
        }
 
776
 
 
777
        /* initialize privileged operating system specific parts */
 
778
        osspec_privileged_init ();
 
779
 
 
780
#ifdef HAVE_POLKIT
 
781
        p_error = NULL;
 
782
        pk_context = polkit_context_new ();
 
783
        if (pk_context == NULL)
 
784
                DIE (("Could not create PolicyKit context"));
 
785
        polkit_context_set_config_changed (pk_context,
 
786
                                           _polkit_config_changed_cb,
 
787
                                           NULL);
 
788
        polkit_context_set_io_watch_functions (pk_context, _polkit_io_add_watch, _polkit_io_remove_watch);
 
789
        if (!polkit_context_init (pk_context, &p_error))
 
790
                DIE (("Could not init PolicyKit context: %s", polkit_error_get_error_message (p_error)));
 
791
#endif
 
792
 
 
793
        /* sometimes we don't want to drop root privs, for instance
 
794
           if we are profiling memory usage */
 
795
        if (opt_retain_privileges == FALSE) {
 
796
                drop_privileges(0);
 
797
        }
 
798
 
 
799
        hald_is_initialising = TRUE;
 
800
 
 
801
        /* make sure our fdi rule cache is up to date and setup file monitoring */
 
802
        di_cache_coherency_check(TRUE);
 
803
 
 
804
        /* initialize operating system specific parts */
 
805
        osspec_init ();
 
806
 
 
807
        /* Init FDI files */
 
808
        di_rules_init();
 
809
 
 
810
        /* detect devices */
 
811
        osspec_probe ();
 
812
 
 
813
        /* run the main loop and serve clients */
 
814
        g_main_loop_run (loop);
 
815
 
 
816
        return 0;
 
817
}
 
818
 
 
819
#ifdef HALD_MEMLEAK_DBG
 
820
extern int dbg_hal_device_object_delta;
 
821
 
 
822
/* useful for valgrinding; see below */
 
823
static gboolean
 
824
my_shutdown2 (gpointer data)
 
825
{
 
826
        /*g_mem_profile ();*/
 
827
        /*sleep (10000);*/
 
828
        exit (1);
 
829
        return FALSE;
 
830
}
 
831
 
 
832
static gboolean
 
833
my_shutdown (gpointer data)
 
834
{
 
835
        HalDeviceStore *gdl;
 
836
        
 
837
        HAL_INFO (("Num devices in TDL: %d", g_slist_length ((hald_get_tdl ())->devices)));
 
838
        HAL_INFO (("Num devices in GDL: %d", g_slist_length ((hald_get_gdl ())->devices)));
 
839
        
 
840
        gdl = hald_get_gdl ();
 
841
next:
 
842
        if (g_slist_length (gdl->devices) > 0) {
 
843
                HalDevice *d = HAL_DEVICE(gdl->devices->data);
 
844
                hal_device_store_remove (gdl, d);
 
845
                g_object_unref (d);
 
846
                goto next;
 
847
        }       
 
848
 
 
849
        HAL_INFO (("hal_device_object_delta = %d (should be zero)", dbg_hal_device_object_delta));
 
850
 
 
851
        hald_dbus_local_server_shutdown ();
 
852
        hald_runner_stop_runner ();
 
853
 
 
854
        HAL_INFO (("Shutting down in five seconds"));
 
855
        g_timeout_add (5 * 1000,
 
856
                       my_shutdown2,
 
857
                       NULL);
 
858
 
 
859
        return FALSE;
 
860
}
 
861
#endif
 
862
 
 
863
void 
 
864
osspec_probe_done (void)
 
865
{
 
866
        ssize_t written;
 
867
        char buf[1] = {0};
 
868
 
 
869
        HAL_INFO (("Device probing completed"));
 
870
 
 
871
        if (hald_debug_exit_after_probing) {
 
872
                HAL_INFO (("Exiting on user request (--exit-after-probing)"));
 
873
                hald_runner_kill_all();
 
874
                exit (0);
 
875
        }
 
876
 
 
877
 
 
878
        if (!hald_dbus_init ()) {
 
879
                hald_runner_kill_all();
 
880
                exit (1);
 
881
        }
 
882
 
 
883
        /* tell parent to exit */
 
884
        written = write (startup_daemonize_pipe[1], buf, sizeof (buf));
 
885
        close (startup_daemonize_pipe[0]);
 
886
        close (startup_daemonize_pipe[1]);
 
887
 
 
888
        hald_is_initialising = FALSE;
 
889
 
 
890
#ifdef HALD_MEMLEAK_DBG
 
891
        g_timeout_add ((HALD_MEMLEAK_DBG) * 1000,
 
892
                       my_shutdown,
 
893
                       NULL);
 
894
#endif
 
895
}
 
896