1*2912Sartem /***************************************************************************
2*2912Sartem * CVSID: $Id$
3*2912Sartem *
4*2912Sartem * hald.c : main startup for HAL daemon
5*2912Sartem *
6*2912Sartem * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7*2912Sartem * Copyright (C) 2005 Danny Kukawka, <danny.kukawka@web.de>
8*2912Sartem *
9*2912Sartem * Licensed under the Academic Free License version 2.1
10*2912Sartem *
11*2912Sartem * This program is free software; you can redistribute it and/or modify
12*2912Sartem * it under the terms of the GNU General Public License as published by
13*2912Sartem * the Free Software Foundation; either version 2 of the License, or
14*2912Sartem * (at your option) any later version.
15*2912Sartem *
16*2912Sartem * This program is distributed in the hope that it will be useful,
17*2912Sartem * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*2912Sartem * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19*2912Sartem * GNU General Public License for more details.
20*2912Sartem *
21*2912Sartem * You should have received a copy of the GNU General Public License
22*2912Sartem * along with this program; if not, write to the Free Software
23*2912Sartem * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*2912Sartem *
25*2912Sartem **************************************************************************/
26*2912Sartem
27*2912Sartem #ifdef HAVE_CONFIG_H
28*2912Sartem # include <config.h>
29*2912Sartem #endif
30*2912Sartem
31*2912Sartem #include <stdio.h>
32*2912Sartem #include <stdlib.h>
33*2912Sartem #include <string.h>
34*2912Sartem #include <unistd.h>
35*2912Sartem #include <getopt.h>
36*2912Sartem #include <pwd.h>
37*2912Sartem #include <stdint.h>
38*2912Sartem #include <sys/stat.h>
39*2912Sartem #include <fcntl.h>
40*2912Sartem #include <errno.h>
41*2912Sartem #include <signal.h>
42*2912Sartem #include <grp.h>
43*2912Sartem #include <syslog.h>
44*2912Sartem
45*2912Sartem #include <dbus/dbus.h>
46*2912Sartem #include <dbus/dbus-glib.h>
47*2912Sartem #include <dbus/dbus-glib-lowlevel.h>
48*2912Sartem
49*2912Sartem /*#include "master_slave.h"*/
50*2912Sartem
51*2912Sartem #include "logger.h"
52*2912Sartem #include "hald.h"
53*2912Sartem #include "device_store.h"
54*2912Sartem #include "device_info.h"
55*2912Sartem #include "osspec.h"
56*2912Sartem #include "hald_dbus.h"
57*2912Sartem #include "util.h"
58*2912Sartem #include "hald_runner.h"
59*2912Sartem #include "util_helper.h"
60*2912Sartem
delete_pid(void)61*2912Sartem static void delete_pid(void)
62*2912Sartem {
63*2912Sartem unlink(HALD_PID_FILE);
64*2912Sartem }
65*2912Sartem
66*2912Sartem /**
67*2912Sartem * @defgroup HalDaemon HAL daemon
68*2912Sartem * @brief The HAL daemon manages persistent device objects available through
69*2912Sartem * a D-BUS network API
70*2912Sartem */
71*2912Sartem
72*2912Sartem static HalDeviceStore *global_device_list = NULL;
73*2912Sartem
74*2912Sartem static HalDeviceStore *temporary_device_list = NULL;
75*2912Sartem
76*2912Sartem
77*2912Sartem static void
addon_terminated(HalDevice * device,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)78*2912Sartem addon_terminated (HalDevice *device, guint32 exit_type,
79*2912Sartem gint return_code, gchar **error,
80*2912Sartem gpointer data1, gpointer data2)
81*2912Sartem {
82*2912Sartem HAL_INFO (("in addon_terminated for udi=%s", device->udi));
83*2912Sartem
84*2912Sartem /* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
85*2912Sartem
86*2912Sartem /* however, the world can stop, mark this addon as ready
87*2912Sartem * (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
88*2912Sartem */
89*2912Sartem if (hal_device_inc_num_ready_addons (device)) {
90*2912Sartem if (hal_device_are_all_addons_ready (device)) {
91*2912Sartem manager_send_signal_device_added (device);
92*2912Sartem }
93*2912Sartem }
94*2912Sartem }
95*2912Sartem
96*2912Sartem
97*2912Sartem
98*2912Sartem
99*2912Sartem static void
gdl_store_changed(HalDeviceStore * store,HalDevice * device,gboolean is_added,gpointer user_data)100*2912Sartem gdl_store_changed (HalDeviceStore *store, HalDevice *device,
101*2912Sartem gboolean is_added, gpointer user_data)
102*2912Sartem {
103*2912Sartem if (is_added) {
104*2912Sartem GSList *addons;
105*2912Sartem
106*2912Sartem HAL_INFO (("Added device to GDL; udi=%s", hal_device_get_udi(device)));
107*2912Sartem
108*2912Sartem if ((addons = hal_device_property_get_strlist (device, "info.addons")) != NULL) {
109*2912Sartem GSList *i;
110*2912Sartem
111*2912Sartem for (i = addons; i != NULL; i = g_slist_next (i)) {
112*2912Sartem const gchar *command_line;
113*2912Sartem gchar *extra_env[2] = {"HALD_ACTION=addon", NULL};
114*2912Sartem
115*2912Sartem command_line = (const gchar *) i->data;
116*2912Sartem if (hald_runner_start(device, command_line, extra_env, addon_terminated, NULL, NULL)) {
117*2912Sartem HAL_INFO (("Started addon %s for udi %s",
118*2912Sartem command_line, hal_device_get_udi(device)));
119*2912Sartem hal_device_inc_num_addons (device);
120*2912Sartem } else {
121*2912Sartem HAL_ERROR (("Cannot start addon %s for udi %s",
122*2912Sartem command_line, hal_device_get_udi(device)));
123*2912Sartem }
124*2912Sartem }
125*2912Sartem }
126*2912Sartem } else {
127*2912Sartem HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
128*2912Sartem hald_runner_kill_device(device);
129*2912Sartem }
130*2912Sartem
131*2912Sartem /*hal_device_print (device);*/
132*2912Sartem
133*2912Sartem if (is_added) {
134*2912Sartem if (hal_device_are_all_addons_ready (device)) {
135*2912Sartem manager_send_signal_device_added (device);
136*2912Sartem }
137*2912Sartem } else {
138*2912Sartem if (hal_device_are_all_addons_ready (device)) {
139*2912Sartem manager_send_signal_device_removed (device);
140*2912Sartem }
141*2912Sartem }
142*2912Sartem }
143*2912Sartem
144*2912Sartem static void
gdl_property_changed(HalDeviceStore * store,HalDevice * device,const char * key,gboolean added,gboolean removed,gpointer user_data)145*2912Sartem gdl_property_changed (HalDeviceStore *store, HalDevice *device,
146*2912Sartem const char *key, gboolean added, gboolean removed,
147*2912Sartem gpointer user_data)
148*2912Sartem {
149*2912Sartem if (hal_device_are_all_addons_ready (device)) {
150*2912Sartem device_send_signal_property_modified (device, key, removed, added);
151*2912Sartem }
152*2912Sartem
153*2912Sartem /* only execute the callouts if the property _changed_ */
154*2912Sartem if (added == FALSE && removed == FALSE)
155*2912Sartem /*hal_callout_property (device, key)*/;
156*2912Sartem }
157*2912Sartem
158*2912Sartem static void
gdl_capability_added(HalDeviceStore * store,HalDevice * device,const char * capability,gpointer user_data)159*2912Sartem gdl_capability_added (HalDeviceStore *store, HalDevice *device,
160*2912Sartem const char *capability, gpointer user_data)
161*2912Sartem {
162*2912Sartem if (hal_device_are_all_addons_ready (device)) {
163*2912Sartem manager_send_signal_new_capability (device, capability);
164*2912Sartem }
165*2912Sartem /*hal_callout_capability (device, capability, TRUE)*/;
166*2912Sartem }
167*2912Sartem
168*2912Sartem HalDeviceStore *
hald_get_gdl(void)169*2912Sartem hald_get_gdl (void)
170*2912Sartem {
171*2912Sartem if (global_device_list == NULL) {
172*2912Sartem global_device_list = hal_device_store_new ();
173*2912Sartem
174*2912Sartem g_signal_connect (global_device_list,
175*2912Sartem "store_changed",
176*2912Sartem G_CALLBACK (gdl_store_changed), NULL);
177*2912Sartem g_signal_connect (global_device_list,
178*2912Sartem "device_property_changed",
179*2912Sartem G_CALLBACK (gdl_property_changed), NULL);
180*2912Sartem g_signal_connect (global_device_list,
181*2912Sartem "device_capability_added",
182*2912Sartem G_CALLBACK (gdl_capability_added), NULL);
183*2912Sartem }
184*2912Sartem
185*2912Sartem return global_device_list;
186*2912Sartem }
187*2912Sartem
188*2912Sartem HalDeviceStore *
hald_get_tdl(void)189*2912Sartem hald_get_tdl (void)
190*2912Sartem {
191*2912Sartem if (temporary_device_list == NULL) {
192*2912Sartem temporary_device_list = hal_device_store_new ();
193*2912Sartem
194*2912Sartem }
195*2912Sartem
196*2912Sartem return temporary_device_list;
197*2912Sartem }
198*2912Sartem
199*2912Sartem /**
200*2912Sartem * @defgroup MainDaemon Basic functions
201*2912Sartem * @ingroup HalDaemon
202*2912Sartem * @brief Basic functions in the HAL daemon
203*2912Sartem * @{
204*2912Sartem */
205*2912Sartem
206*2912Sartem /** Print out program usage.
207*2912Sartem *
208*2912Sartem */
209*2912Sartem static void
usage()210*2912Sartem usage ()
211*2912Sartem {
212*2912Sartem fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]\n");
213*2912Sartem fprintf (stderr,
214*2912Sartem "\n"
215*2912Sartem " --daemon=yes|no Become a daemon\n"
216*2912Sartem " --verbose=yes|no Print out debug (overrides HALD_VERBOSE)\n"
217*2912Sartem " --use-syslog Print out debug messages to syslog instead of stderr.\n"
218*2912Sartem " Use this option to get debug messages if HAL runs as\n"
219*2912Sartem " daemon.\n"
220*2912Sartem " --help Show this information and exit\n"
221*2912Sartem " --version Output version information and exit"
222*2912Sartem "\n"
223*2912Sartem "The HAL daemon detects devices present in the system and provides the\n"
224*2912Sartem "org.freedesktop.Hal service through the system-wide message bus provided\n"
225*2912Sartem "by D-BUS.\n"
226*2912Sartem "\n"
227*2912Sartem "For more information visit http://freedesktop.org/Software/hal\n"
228*2912Sartem "\n");
229*2912Sartem }
230*2912Sartem
231*2912Sartem /** If #TRUE, we will daemonize */
232*2912Sartem static dbus_bool_t opt_become_daemon = TRUE;
233*2912Sartem
234*2912Sartem /** If #TRUE, we will spew out debug */
235*2912Sartem dbus_bool_t hald_is_verbose = FALSE;
236*2912Sartem dbus_bool_t hald_use_syslog = FALSE;
237*2912Sartem
238*2912Sartem static int sigterm_unix_signal_pipe_fds[2];
239*2912Sartem static GIOChannel *sigterm_iochn;
240*2912Sartem
241*2912Sartem static void
handle_sigterm(int value)242*2912Sartem handle_sigterm (int value)
243*2912Sartem {
244*2912Sartem ssize_t written;
245*2912Sartem static char marker[1] = {'S'};
246*2912Sartem
247*2912Sartem /* write a 'S' character to the other end to tell about
248*2912Sartem * the signal. Note that 'the other end' is a GIOChannel thingy
249*2912Sartem * that is only called from the mainloop - thus this is how we
250*2912Sartem * defer this since UNIX signal handlers are evil
251*2912Sartem *
252*2912Sartem * Oh, and write(2) is indeed reentrant */
253*2912Sartem written = write (sigterm_unix_signal_pipe_fds[1], marker, 1);
254*2912Sartem }
255*2912Sartem
256*2912Sartem static gboolean
sigterm_iochn_data(GIOChannel * source,GIOCondition condition,gpointer user_data)257*2912Sartem sigterm_iochn_data (GIOChannel *source,
258*2912Sartem GIOCondition condition,
259*2912Sartem gpointer user_data)
260*2912Sartem {
261*2912Sartem GError *err = NULL;
262*2912Sartem gchar data[1];
263*2912Sartem gsize bytes_read;
264*2912Sartem
265*2912Sartem /* Empty the pipe */
266*2912Sartem if (G_IO_STATUS_NORMAL !=
267*2912Sartem g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
268*2912Sartem HAL_ERROR (("Error emptying sigterm pipe: %s",
269*2912Sartem err->message));
270*2912Sartem g_error_free (err);
271*2912Sartem goto out;
272*2912Sartem }
273*2912Sartem
274*2912Sartem HAL_INFO (("Caught SIGTERM, initiating shutdown"));
275*2912Sartem hald_runner_kill_all();
276*2912Sartem exit (0);
277*2912Sartem
278*2912Sartem out:
279*2912Sartem return TRUE;
280*2912Sartem }
281*2912Sartem
282*2912Sartem
283*2912Sartem /** This is set to #TRUE if we are probing and #FALSE otherwise */
284*2912Sartem dbus_bool_t hald_is_initialising;
285*2912Sartem
286*2912Sartem static int startup_daemonize_pipe[2];
287*2912Sartem
288*2912Sartem
289*2912Sartem /*--------------------------------------------------------------------------------------------------*/
290*2912Sartem
291*2912Sartem static gboolean child_died = FALSE;
292*2912Sartem
293*2912Sartem static void
handle_sigchld(int value)294*2912Sartem handle_sigchld (int value)
295*2912Sartem {
296*2912Sartem child_died = TRUE;
297*2912Sartem }
298*2912Sartem
299*2912Sartem static int
parent_wait_for_child(int child_fd,pid_t child_pid)300*2912Sartem parent_wait_for_child (int child_fd, pid_t child_pid)
301*2912Sartem {
302*2912Sartem fd_set rfds;
303*2912Sartem fd_set efds;
304*2912Sartem struct timeval tv;
305*2912Sartem int retval;
306*2912Sartem int ret;
307*2912Sartem
308*2912Sartem signal(SIGCHLD, handle_sigchld);
309*2912Sartem
310*2912Sartem /* wait for either
311*2912Sartem *
312*2912Sartem * o Child writes something to the child_fd; means that device
313*2912Sartem * probing is completed and the parent should exit with success
314*2912Sartem *
315*2912Sartem * o Child is killed (segfault etc.); means that parent should exit
316*2912Sartem * with failure
317*2912Sartem *
318*2912Sartem * o Timeout; means that we should kill the child and exit with
319*2912Sartem * failure
320*2912Sartem *
321*2912Sartem */
322*2912Sartem
323*2912Sartem FD_ZERO(&rfds);
324*2912Sartem FD_SET(child_fd, &rfds);
325*2912Sartem FD_ZERO(&efds);
326*2912Sartem FD_SET(child_fd, &efds);
327*2912Sartem /* Wait up to 250 seconds for device probing */
328*2912Sartem tv.tv_sec = 250;
329*2912Sartem tv.tv_usec = 0;
330*2912Sartem
331*2912Sartem retval = select (child_fd + 1, &rfds, NULL, &efds, &tv);
332*2912Sartem
333*2912Sartem if (child_died) {
334*2912Sartem /* written from handle_sigchld */
335*2912Sartem ret = 1;
336*2912Sartem goto out;
337*2912Sartem }
338*2912Sartem
339*2912Sartem if (retval > 0) {
340*2912Sartem /* means child wrote to socket or closed it; all good */
341*2912Sartem ret = 0;
342*2912Sartem goto out;
343*2912Sartem }
344*2912Sartem
345*2912Sartem /* assume timeout; kill child */
346*2912Sartem kill (child_pid, SIGTERM);
347*2912Sartem ret = 2;
348*2912Sartem
349*2912Sartem out:
350*2912Sartem return ret;
351*2912Sartem }
352*2912Sartem
353*2912Sartem /*--------------------------------------------------------------------------------------------------*/
354*2912Sartem
355*2912Sartem /** Entry point for HAL daemon
356*2912Sartem *
357*2912Sartem * @param argc Number of arguments
358*2912Sartem * @param argv Array of arguments
359*2912Sartem * @return Exit code
360*2912Sartem */
361*2912Sartem int
main(int argc,char * argv[])362*2912Sartem main (int argc, char *argv[])
363*2912Sartem {
364*2912Sartem GMainLoop *loop;
365*2912Sartem guint sigterm_iochn_listener_source_id;
366*2912Sartem char *path;
367*2912Sartem char newpath[512];
368*2912Sartem
369*2912Sartem openlog ("hald", LOG_PID, LOG_DAEMON);
370*2912Sartem
371*2912Sartem g_type_init ();
372*2912Sartem
373*2912Sartem if (getenv ("HALD_VERBOSE"))
374*2912Sartem hald_is_verbose = TRUE;
375*2912Sartem else
376*2912Sartem hald_is_verbose = FALSE;
377*2912Sartem
378*2912Sartem /* our helpers are installed into libexec, so adjust out $PATH
379*2912Sartem * to include this at the end (since we want to overide in
380*2912Sartem * run-hald.sh and friends)
381*2912Sartem */
382*2912Sartem path = getenv ("PATH");
383*2912Sartem if (path != NULL) {
384*2912Sartem g_strlcpy (newpath, path, sizeof (newpath));
385*2912Sartem g_strlcat (newpath, ":", sizeof (newpath));
386*2912Sartem } else {
387*2912Sartem /* No PATH was set */
388*2912Sartem newpath[0] = '\0';
389*2912Sartem }
390*2912Sartem
391*2912Sartem g_strlcat (newpath, PACKAGE_LIBEXEC_DIR, sizeof (newpath));
392*2912Sartem g_strlcat (newpath, ":", sizeof (newpath));
393*2912Sartem g_strlcat (newpath, PACKAGE_SCRIPT_DIR, sizeof (newpath));
394*2912Sartem
395*2912Sartem setenv ("PATH", newpath, TRUE);
396*2912Sartem
397*2912Sartem while (1) {
398*2912Sartem int c;
399*2912Sartem int option_index = 0;
400*2912Sartem const char *opt;
401*2912Sartem static struct option long_options[] = {
402*2912Sartem {"daemon", 1, NULL, 0},
403*2912Sartem {"verbose", 1, NULL, 0},
404*2912Sartem {"use-syslog", 0, NULL, 0},
405*2912Sartem {"help", 0, NULL, 0},
406*2912Sartem {"version", 0, NULL, 0},
407*2912Sartem {NULL, 0, NULL, 0}
408*2912Sartem };
409*2912Sartem
410*2912Sartem c = getopt_long (argc, argv, "",
411*2912Sartem long_options, &option_index);
412*2912Sartem if (c == -1)
413*2912Sartem break;
414*2912Sartem
415*2912Sartem switch (c) {
416*2912Sartem case 0:
417*2912Sartem opt = long_options[option_index].name;
418*2912Sartem
419*2912Sartem if (strcmp (opt, "help") == 0) {
420*2912Sartem usage ();
421*2912Sartem return 0;
422*2912Sartem } else if (strcmp (opt, "version") == 0) {
423*2912Sartem fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
424*2912Sartem return 0;
425*2912Sartem } else if (strcmp (opt, "daemon") == 0) {
426*2912Sartem if (strcmp ("yes", optarg) == 0) {
427*2912Sartem opt_become_daemon = TRUE;
428*2912Sartem } else if (strcmp ("no", optarg) == 0) {
429*2912Sartem opt_become_daemon = FALSE;
430*2912Sartem } else {
431*2912Sartem usage ();
432*2912Sartem return 1;
433*2912Sartem }
434*2912Sartem } else if (strcmp (opt, "verbose") == 0) {
435*2912Sartem if (strcmp ("yes", optarg) == 0) {
436*2912Sartem hald_is_verbose = TRUE;
437*2912Sartem } else if (strcmp ("no", optarg) == 0) {
438*2912Sartem hald_is_verbose = FALSE;
439*2912Sartem } else {
440*2912Sartem usage ();
441*2912Sartem return 1;
442*2912Sartem }
443*2912Sartem } else if (strcmp (opt, "use-syslog") == 0) {
444*2912Sartem hald_use_syslog = TRUE;
445*2912Sartem }
446*2912Sartem
447*2912Sartem break;
448*2912Sartem
449*2912Sartem default:
450*2912Sartem usage ();
451*2912Sartem return 1;
452*2912Sartem break;
453*2912Sartem }
454*2912Sartem }
455*2912Sartem
456*2912Sartem if (hald_is_verbose)
457*2912Sartem logger_enable ();
458*2912Sartem else
459*2912Sartem logger_disable ();
460*2912Sartem
461*2912Sartem if (hald_use_syslog)
462*2912Sartem logger_enable_syslog ();
463*2912Sartem else
464*2912Sartem logger_disable_syslog ();
465*2912Sartem
466*2912Sartem /* will fork into two; only the child will return here if we are successful */
467*2912Sartem /*master_slave_setup ();
468*2912Sartem sleep (100000000);*/
469*2912Sartem
470*2912Sartem loop = g_main_loop_new (NULL, FALSE);
471*2912Sartem
472*2912Sartem HAL_INFO ((PACKAGE_STRING));
473*2912Sartem
474*2912Sartem if (opt_become_daemon) {
475*2912Sartem int child_pid;
476*2912Sartem int dev_null_fd;
477*2912Sartem int pf;
478*2912Sartem ssize_t written;
479*2912Sartem char pid[9];
480*2912Sartem
481*2912Sartem HAL_INFO (("Will daemonize"));
482*2912Sartem HAL_INFO (("Becoming a daemon"));
483*2912Sartem
484*2912Sartem if (pipe (startup_daemonize_pipe) != 0) {
485*2912Sartem fprintf (stderr, "Could not setup pipe: %s\n", strerror(errno));
486*2912Sartem exit (1);
487*2912Sartem }
488*2912Sartem
489*2912Sartem
490*2912Sartem if (chdir ("/") < 0) {
491*2912Sartem fprintf (stderr, "Could not chdir to /: %s\n", strerror(errno));
492*2912Sartem exit (1);
493*2912Sartem }
494*2912Sartem
495*2912Sartem child_pid = fork ();
496*2912Sartem switch (child_pid) {
497*2912Sartem case -1:
498*2912Sartem fprintf (stderr, "Cannot fork(): %s\n", strerror(errno));
499*2912Sartem break;
500*2912Sartem
501*2912Sartem case 0:
502*2912Sartem /* child */
503*2912Sartem
504*2912Sartem dev_null_fd = open ("/dev/null", O_RDWR);
505*2912Sartem /* ignore if we can't open /dev/null */
506*2912Sartem if (dev_null_fd >= 0) {
507*2912Sartem /* attach /dev/null to stdout, stdin, stderr */
508*2912Sartem dup2 (dev_null_fd, 0);
509*2912Sartem dup2 (dev_null_fd, 1);
510*2912Sartem dup2 (dev_null_fd, 2);
511*2912Sartem close (dev_null_fd);
512*2912Sartem }
513*2912Sartem
514*2912Sartem umask (022);
515*2912Sartem break;
516*2912Sartem
517*2912Sartem default:
518*2912Sartem /* parent, block until child writes */
519*2912Sartem exit (parent_wait_for_child (startup_daemonize_pipe[0], child_pid));
520*2912Sartem break;
521*2912Sartem }
522*2912Sartem
523*2912Sartem /* Create session */
524*2912Sartem setsid ();
525*2912Sartem
526*2912Sartem /* remove old pid file */
527*2912Sartem unlink (HALD_PID_FILE);
528*2912Sartem
529*2912Sartem /* Make a new one */
530*2912Sartem if ((pf= open (HALD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
531*2912Sartem snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
532*2912Sartem written = write (pf, pid, strlen(pid));
533*2912Sartem close (pf);
534*2912Sartem atexit (delete_pid);
535*2912Sartem }
536*2912Sartem } else {
537*2912Sartem HAL_INFO (("Will not daemonize"));
538*2912Sartem }
539*2912Sartem
540*2912Sartem
541*2912Sartem /* we need to do stuff when we are expected to terminate, thus
542*2912Sartem * this involves looking for SIGTERM; UNIX signal handlers are
543*2912Sartem * evil though, so set up a pipe to transmit the signal.
544*2912Sartem */
545*2912Sartem
546*2912Sartem /* create pipe */
547*2912Sartem if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
548*2912Sartem DIE (("Could not setup pipe, errno=%d", errno));
549*2912Sartem }
550*2912Sartem
551*2912Sartem /* setup glib handler - 0 is for reading, 1 is for writing */
552*2912Sartem sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
553*2912Sartem if (sigterm_iochn == NULL)
554*2912Sartem DIE (("Could not create GIOChannel"));
555*2912Sartem
556*2912Sartem /* get callback when there is data to read */
557*2912Sartem sigterm_iochn_listener_source_id = g_io_add_watch (
558*2912Sartem sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
559*2912Sartem
560*2912Sartem /* Finally, setup unix signal handler for TERM */
561*2912Sartem signal (SIGTERM, handle_sigterm);
562*2912Sartem
563*2912Sartem /* set up the local dbus server */
564*2912Sartem if (!hald_dbus_local_server_init ())
565*2912Sartem return 1;
566*2912Sartem /* Start the runner helper daemon */
567*2912Sartem if (!hald_runner_start_runner ()) {
568*2912Sartem return 1;
569*2912Sartem }
570*2912Sartem
571*2912Sartem drop_privileges(0);
572*2912Sartem
573*2912Sartem /* initialize operating system specific parts */
574*2912Sartem osspec_init ();
575*2912Sartem
576*2912Sartem hald_is_initialising = TRUE;
577*2912Sartem
578*2912Sartem /* detect devices */
579*2912Sartem osspec_probe ();
580*2912Sartem
581*2912Sartem /* run the main loop and serve clients */
582*2912Sartem g_main_loop_run (loop);
583*2912Sartem
584*2912Sartem return 0;
585*2912Sartem }
586*2912Sartem
587*2912Sartem #ifdef HALD_MEMLEAK_DBG
588*2912Sartem extern int dbg_hal_device_object_delta;
589*2912Sartem
590*2912Sartem /* useful for valgrinding; see below */
591*2912Sartem static gboolean
my_shutdown(gpointer data)592*2912Sartem my_shutdown (gpointer data)
593*2912Sartem {
594*2912Sartem HalDeviceStore *gdl;
595*2912Sartem
596*2912Sartem printf ("Num devices in TDL: %d\n", g_slist_length ((hald_get_tdl ())->devices));
597*2912Sartem printf ("Num devices in GDL: %d\n", g_slist_length ((hald_get_gdl ())->devices));
598*2912Sartem
599*2912Sartem gdl = hald_get_gdl ();
600*2912Sartem next:
601*2912Sartem if (g_slist_length (gdl->devices) > 0) {
602*2912Sartem HalDevice *d = HAL_DEVICE(gdl->devices->data);
603*2912Sartem hal_device_store_remove (gdl, d);
604*2912Sartem g_object_unref (d);
605*2912Sartem goto next;
606*2912Sartem }
607*2912Sartem
608*2912Sartem printf ("hal_device_object_delta = %d (should be zero)\n", dbg_hal_device_object_delta);
609*2912Sartem exit (1);
610*2912Sartem }
611*2912Sartem #endif
612*2912Sartem
613*2912Sartem void
osspec_probe_done(void)614*2912Sartem osspec_probe_done (void)
615*2912Sartem {
616*2912Sartem ssize_t written;
617*2912Sartem char buf[1] = {0};
618*2912Sartem
619*2912Sartem HAL_INFO (("Device probing completed"));
620*2912Sartem
621*2912Sartem if (!hald_dbus_init ()) {
622*2912Sartem hald_runner_kill_all();
623*2912Sartem exit (1);
624*2912Sartem }
625*2912Sartem
626*2912Sartem /* tell parent to exit */
627*2912Sartem written = write (startup_daemonize_pipe[1], buf, sizeof (buf));
628*2912Sartem close (startup_daemonize_pipe[0]);
629*2912Sartem close (startup_daemonize_pipe[1]);
630*2912Sartem
631*2912Sartem hald_is_initialising = FALSE;
632*2912Sartem
633*2912Sartem #ifdef HALD_MEMLEAK_DBG
634*2912Sartem g_timeout_add ((HALD_MEMLEAK_DBG) * 1000,
635*2912Sartem my_shutdown,
636*2912Sartem NULL);
637*2912Sartem #endif
638*2912Sartem }
639*2912Sartem
640*2912Sartem
641*2912Sartem /** @} */
642