xref: /onnv-gate/usr/src/cmd/hal/hald/hald.c (revision 2912:85ea316d9c18)
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