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