xref: /illumos-gate/usr/src/cmd/hal/hald/hald.c (revision 55fea89d)
118c2aff7Sartem /***************************************************************************
218c2aff7Sartem  * CVSID: $Id$
318c2aff7Sartem  *
418c2aff7Sartem  * hald.c : main startup for HAL daemon
518c2aff7Sartem  *
618c2aff7Sartem  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
718c2aff7Sartem  * Copyright (C) 2005 Danny Kukawka, <danny.kukawka@web.de>
818c2aff7Sartem  *
918c2aff7Sartem  * Licensed under the Academic Free License version 2.1
1018c2aff7Sartem  *
1118c2aff7Sartem  * This program is free software; you can redistribute it and/or modify
1218c2aff7Sartem  * it under the terms of the GNU General Public License as published by
1318c2aff7Sartem  * the Free Software Foundation; either version 2 of the License, or
1418c2aff7Sartem  * (at your option) any later version.
1518c2aff7Sartem  *
1618c2aff7Sartem  * This program is distributed in the hope that it will be useful,
1718c2aff7Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1818c2aff7Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1918c2aff7Sartem  * GNU General Public License for more details.
2018c2aff7Sartem  *
2118c2aff7Sartem  * You should have received a copy of the GNU General Public License
2218c2aff7Sartem  * along with this program; if not, write to the Free Software
2318c2aff7Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
2418c2aff7Sartem  *
2518c2aff7Sartem  **************************************************************************/
2618c2aff7Sartem 
2718c2aff7Sartem #ifdef HAVE_CONFIG_H
2818c2aff7Sartem #  include <config.h>
2918c2aff7Sartem #endif
3018c2aff7Sartem 
3118c2aff7Sartem #include <stdio.h>
3218c2aff7Sartem #include <stdlib.h>
3318c2aff7Sartem #include <string.h>
3418c2aff7Sartem #include <unistd.h>
3518c2aff7Sartem #include <getopt.h>
3618c2aff7Sartem #include <pwd.h>
3718c2aff7Sartem #include <stdint.h>
3818c2aff7Sartem #include <sys/stat.h>
3918c2aff7Sartem #include <fcntl.h>
4018c2aff7Sartem #include <errno.h>
4118c2aff7Sartem #include <signal.h>
4218c2aff7Sartem #include <grp.h>
4318c2aff7Sartem #include <syslog.h>
4418c2aff7Sartem 
4518c2aff7Sartem #include <dbus/dbus.h>
4618c2aff7Sartem #include <dbus/dbus-glib.h>
4718c2aff7Sartem #include <dbus/dbus-glib-lowlevel.h>
4818c2aff7Sartem 
4918c2aff7Sartem /*#include "master_slave.h"*/
5018c2aff7Sartem 
5118c2aff7Sartem #include "logger.h"
5218c2aff7Sartem #include "hald.h"
5318c2aff7Sartem #include "device_store.h"
5418c2aff7Sartem #include "device_info.h"
5518c2aff7Sartem #include "osspec.h"
5618c2aff7Sartem #include "hald_dbus.h"
5718c2aff7Sartem #include "util.h"
5818c2aff7Sartem #include "hald_runner.h"
5918c2aff7Sartem #include "util_helper.h"
6018c2aff7Sartem 
delete_pid(void)6118c2aff7Sartem static void delete_pid(void)
6218c2aff7Sartem {
6318c2aff7Sartem 	unlink(HALD_PID_FILE);
6418c2aff7Sartem }
6518c2aff7Sartem 
6618c2aff7Sartem /**
6718c2aff7Sartem  * @defgroup HalDaemon HAL daemon
6818c2aff7Sartem  * @brief The HAL daemon manages persistent device objects available through
6918c2aff7Sartem  *        a D-BUS network API
7018c2aff7Sartem  */
7118c2aff7Sartem 
7218c2aff7Sartem static HalDeviceStore *global_device_list = NULL;
7318c2aff7Sartem 
7418c2aff7Sartem static HalDeviceStore *temporary_device_list = NULL;
7518c2aff7Sartem 
7618c2aff7Sartem 
7718c2aff7Sartem static void
addon_terminated(HalDevice * device,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)78*55fea89dSDan Cross addon_terminated (HalDevice *device, guint32 exit_type,
7918c2aff7Sartem 		  gint return_code, gchar **error,
8018c2aff7Sartem 		  gpointer data1, gpointer data2)
8118c2aff7Sartem {
8218c2aff7Sartem 	HAL_INFO (("in addon_terminated for udi=%s", device->udi));
8318c2aff7Sartem 
8418c2aff7Sartem 	/* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
8518c2aff7Sartem 
86*55fea89dSDan Cross 	/* however, the world can stop, mark this addon as ready
8718c2aff7Sartem 	 * (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
8818c2aff7Sartem 	 */
8918c2aff7Sartem 	if (hal_device_inc_num_ready_addons (device)) {
9018c2aff7Sartem 		if (hal_device_are_all_addons_ready (device)) {
9118c2aff7Sartem 			manager_send_signal_device_added (device);
9218c2aff7Sartem 		}
9318c2aff7Sartem 	}
9418c2aff7Sartem }
9518c2aff7Sartem 
9618c2aff7Sartem 
9718c2aff7Sartem 
9818c2aff7Sartem 
9918c2aff7Sartem static void
gdl_store_changed(HalDeviceStore * store,HalDevice * device,gboolean is_added,gpointer user_data)10018c2aff7Sartem gdl_store_changed (HalDeviceStore *store, HalDevice *device,
10118c2aff7Sartem 		   gboolean is_added, gpointer user_data)
10218c2aff7Sartem {
10318c2aff7Sartem 	if (is_added) {
10418c2aff7Sartem 		GSList *addons;
10518c2aff7Sartem 
10618c2aff7Sartem 		HAL_INFO (("Added device to GDL; udi=%s", hal_device_get_udi(device)));
10718c2aff7Sartem 
10818c2aff7Sartem 		if ((addons = hal_device_property_get_strlist (device, "info.addons")) != NULL) {
10918c2aff7Sartem 			GSList *i;
11018c2aff7Sartem 
11118c2aff7Sartem 			for (i = addons; i != NULL; i = g_slist_next (i)) {
11218c2aff7Sartem 				const gchar *command_line;
11318c2aff7Sartem 				gchar *extra_env[2] = {"HALD_ACTION=addon", NULL};
11418c2aff7Sartem 
11518c2aff7Sartem 				command_line = (const gchar *) i->data;
11618c2aff7Sartem 				if (hald_runner_start(device, command_line, extra_env, addon_terminated, NULL, NULL)) {
117*55fea89dSDan Cross 					HAL_INFO (("Started addon %s for udi %s",
11818c2aff7Sartem 						   command_line, hal_device_get_udi(device)));
11918c2aff7Sartem 					hal_device_inc_num_addons (device);
12018c2aff7Sartem 				} else {
121*55fea89dSDan Cross 					HAL_ERROR (("Cannot start addon %s for udi %s",
12218c2aff7Sartem 						    command_line, hal_device_get_udi(device)));
12318c2aff7Sartem 				}
12418c2aff7Sartem 			}
12518c2aff7Sartem 		}
12618c2aff7Sartem 	} else {
12718c2aff7Sartem 		HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
12818c2aff7Sartem 		hald_runner_kill_device(device);
12918c2aff7Sartem 	}
13018c2aff7Sartem 
13118c2aff7Sartem 	/*hal_device_print (device);*/
13218c2aff7Sartem 
13318c2aff7Sartem 	if (is_added) {
13418c2aff7Sartem 		if (hal_device_are_all_addons_ready (device)) {
13518c2aff7Sartem 			manager_send_signal_device_added (device);
13618c2aff7Sartem 		}
13718c2aff7Sartem 	} else {
13818c2aff7Sartem 		if (hal_device_are_all_addons_ready (device)) {
13918c2aff7Sartem 			manager_send_signal_device_removed (device);
14018c2aff7Sartem 		}
14118c2aff7Sartem 	}
14218c2aff7Sartem }
14318c2aff7Sartem 
14418c2aff7Sartem static void
gdl_property_changed(HalDeviceStore * store,HalDevice * device,const char * key,gboolean added,gboolean removed,gpointer user_data)14518c2aff7Sartem gdl_property_changed (HalDeviceStore *store, HalDevice *device,
14618c2aff7Sartem 		      const char *key, gboolean added, gboolean removed,
14718c2aff7Sartem 		      gpointer user_data)
14818c2aff7Sartem {
14918c2aff7Sartem 	if (hal_device_are_all_addons_ready (device)) {
15018c2aff7Sartem 		device_send_signal_property_modified (device, key, removed, added);
15118c2aff7Sartem 	}
15218c2aff7Sartem 
15318c2aff7Sartem 	/* only execute the callouts if the property _changed_ */
15418c2aff7Sartem 	if (added == FALSE && removed == FALSE)
15518c2aff7Sartem 		/*hal_callout_property (device, key)*/;
15618c2aff7Sartem }
15718c2aff7Sartem 
15818c2aff7Sartem static void
gdl_capability_added(HalDeviceStore * store,HalDevice * device,const char * capability,gpointer user_data)15918c2aff7Sartem gdl_capability_added (HalDeviceStore *store, HalDevice *device,
16018c2aff7Sartem 		      const char *capability, gpointer user_data)
16118c2aff7Sartem {
16218c2aff7Sartem 	if (hal_device_are_all_addons_ready (device)) {
16318c2aff7Sartem 		manager_send_signal_new_capability (device, capability);
16418c2aff7Sartem 	}
16518c2aff7Sartem 	/*hal_callout_capability (device, capability, TRUE)*/;
16618c2aff7Sartem }
16718c2aff7Sartem 
16818c2aff7Sartem HalDeviceStore *
hald_get_gdl(void)16918c2aff7Sartem hald_get_gdl (void)
17018c2aff7Sartem {
17118c2aff7Sartem 	if (global_device_list == NULL) {
17218c2aff7Sartem 		global_device_list = hal_device_store_new ();
173*55fea89dSDan Cross 
17418c2aff7Sartem 		g_signal_connect (global_device_list,
17518c2aff7Sartem 				  "store_changed",
17618c2aff7Sartem 				  G_CALLBACK (gdl_store_changed), NULL);
17718c2aff7Sartem 		g_signal_connect (global_device_list,
17818c2aff7Sartem 				  "device_property_changed",
17918c2aff7Sartem 				  G_CALLBACK (gdl_property_changed), NULL);
18018c2aff7Sartem 		g_signal_connect (global_device_list,
18118c2aff7Sartem 				  "device_capability_added",
18218c2aff7Sartem 				  G_CALLBACK (gdl_capability_added), NULL);
18318c2aff7Sartem 	}
18418c2aff7Sartem 
18518c2aff7Sartem 	return global_device_list;
18618c2aff7Sartem }
18718c2aff7Sartem 
18818c2aff7Sartem HalDeviceStore *
hald_get_tdl(void)18918c2aff7Sartem hald_get_tdl (void)
19018c2aff7Sartem {
19118c2aff7Sartem 	if (temporary_device_list == NULL) {
19218c2aff7Sartem 		temporary_device_list = hal_device_store_new ();
193*55fea89dSDan Cross 
19418c2aff7Sartem 	}
19518c2aff7Sartem 
19618c2aff7Sartem 	return temporary_device_list;
19718c2aff7Sartem }
19818c2aff7Sartem 
19918c2aff7Sartem /**
20018c2aff7Sartem  * @defgroup MainDaemon Basic functions
20118c2aff7Sartem  * @ingroup HalDaemon
20218c2aff7Sartem  * @brief Basic functions in the HAL daemon
20318c2aff7Sartem  * @{
20418c2aff7Sartem  */
20518c2aff7Sartem 
20618c2aff7Sartem /** Print out program usage.
20718c2aff7Sartem  *
20818c2aff7Sartem  */
20918c2aff7Sartem static void
usage()21018c2aff7Sartem usage ()
21118c2aff7Sartem {
21218c2aff7Sartem 	fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]\n");
21318c2aff7Sartem 	fprintf (stderr,
21418c2aff7Sartem 		 "\n"
21518c2aff7Sartem 		 "        --daemon=yes|no      Become a daemon\n"
21618c2aff7Sartem 		 "        --verbose=yes|no     Print out debug (overrides HALD_VERBOSE)\n"
21718c2aff7Sartem  		 "        --use-syslog         Print out debug messages to syslog instead of stderr.\n"
21818c2aff7Sartem 		 "                             Use this option to get debug messages if HAL runs as\n"
21918c2aff7Sartem 		 "                             daemon.\n"
22018c2aff7Sartem 		 "        --help               Show this information and exit\n"
22118c2aff7Sartem 		 "        --version            Output version information and exit"
22218c2aff7Sartem 		 "\n"
22318c2aff7Sartem 		 "The HAL daemon detects devices present in the system and provides the\n"
22418c2aff7Sartem 		 "org.freedesktop.Hal service through the system-wide message bus provided\n"
22518c2aff7Sartem 		 "by D-BUS.\n"
22618c2aff7Sartem 		 "\n"
22718c2aff7Sartem 		 "For more information visit http://freedesktop.org/Software/hal\n"
22818c2aff7Sartem 		 "\n");
22918c2aff7Sartem }
23018c2aff7Sartem 
23118c2aff7Sartem /** If #TRUE, we will daemonize */
23218c2aff7Sartem static dbus_bool_t opt_become_daemon = TRUE;
23318c2aff7Sartem 
23418c2aff7Sartem /** If #TRUE, we will spew out debug */
23518c2aff7Sartem dbus_bool_t hald_is_verbose = FALSE;
23618c2aff7Sartem dbus_bool_t hald_use_syslog = FALSE;
23718c2aff7Sartem 
23818c2aff7Sartem static int sigterm_unix_signal_pipe_fds[2];
23918c2aff7Sartem static GIOChannel *sigterm_iochn;
24018c2aff7Sartem 
241*55fea89dSDan Cross static void
handle_sigterm(int value)24218c2aff7Sartem handle_sigterm (int value)
24318c2aff7Sartem {
24418c2aff7Sartem 	static char marker[1] = {'S'};
24518c2aff7Sartem 
24618c2aff7Sartem 	/* write a 'S' character to the other end to tell about
24718c2aff7Sartem 	 * the signal. Note that 'the other end' is a GIOChannel thingy
24818c2aff7Sartem 	 * that is only called from the mainloop - thus this is how we
24918c2aff7Sartem 	 * defer this since UNIX signal handlers are evil
25018c2aff7Sartem 	 *
25118c2aff7Sartem 	 * Oh, and write(2) is indeed reentrant */
252d9e525a8SToomas Soome 	(void) write (sigterm_unix_signal_pipe_fds[1], marker, 1);
25318c2aff7Sartem }
25418c2aff7Sartem 
25518c2aff7Sartem static gboolean
sigterm_iochn_data(GIOChannel * source,GIOCondition condition,gpointer user_data)256*55fea89dSDan Cross sigterm_iochn_data (GIOChannel *source,
257*55fea89dSDan Cross 		    GIOCondition condition,
25818c2aff7Sartem 		    gpointer user_data)
25918c2aff7Sartem {
26018c2aff7Sartem 	GError *err = NULL;
26118c2aff7Sartem 	gchar data[1];
26218c2aff7Sartem 	gsize bytes_read;
26318c2aff7Sartem 
26418c2aff7Sartem 	/* Empty the pipe */
265*55fea89dSDan Cross 	if (G_IO_STATUS_NORMAL !=
26618c2aff7Sartem 	    g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
26718c2aff7Sartem 		HAL_ERROR (("Error emptying sigterm pipe: %s",
26818c2aff7Sartem 				   err->message));
26918c2aff7Sartem 		g_error_free (err);
27018c2aff7Sartem 		goto out;
27118c2aff7Sartem 	}
27218c2aff7Sartem 
27318c2aff7Sartem 	HAL_INFO (("Caught SIGTERM, initiating shutdown"));
27418c2aff7Sartem 	hald_runner_kill_all();
27518c2aff7Sartem 	exit (0);
27618c2aff7Sartem 
27718c2aff7Sartem out:
27818c2aff7Sartem 	return TRUE;
27918c2aff7Sartem }
28018c2aff7Sartem 
28118c2aff7Sartem 
28218c2aff7Sartem /** This is set to #TRUE if we are probing and #FALSE otherwise */
28318c2aff7Sartem dbus_bool_t hald_is_initialising;
28418c2aff7Sartem 
28518c2aff7Sartem static int startup_daemonize_pipe[2];
28618c2aff7Sartem 
28718c2aff7Sartem 
28818c2aff7Sartem /*--------------------------------------------------------------------------------------------------*/
28918c2aff7Sartem 
29018c2aff7Sartem static gboolean child_died = FALSE;
29118c2aff7Sartem 
292*55fea89dSDan Cross static void
handle_sigchld(int value)29318c2aff7Sartem handle_sigchld (int value)
29418c2aff7Sartem {
29518c2aff7Sartem 	child_died = TRUE;
29618c2aff7Sartem }
29718c2aff7Sartem 
298*55fea89dSDan Cross static int
parent_wait_for_child(int child_fd,pid_t child_pid)29918c2aff7Sartem parent_wait_for_child (int child_fd, pid_t child_pid)
30018c2aff7Sartem {
30118c2aff7Sartem 	fd_set rfds;
30218c2aff7Sartem 	fd_set efds;
30318c2aff7Sartem 	struct timeval tv;
30418c2aff7Sartem 	int retval;
30518c2aff7Sartem 	int ret;
30618c2aff7Sartem 
30718c2aff7Sartem 	signal(SIGCHLD, handle_sigchld);
30818c2aff7Sartem 
30918c2aff7Sartem 	/* wait for either
31018c2aff7Sartem 	 *
31118c2aff7Sartem 	 * o Child writes something to the child_fd; means that device
31218c2aff7Sartem 	 *   probing is completed and the parent should exit with success
31318c2aff7Sartem 	 *
31418c2aff7Sartem 	 * o Child is killed (segfault etc.); means that parent should exit
31518c2aff7Sartem 	 *   with failure
31618c2aff7Sartem 	 *
31718c2aff7Sartem 	 * o Timeout; means that we should kill the child and exit with
31818c2aff7Sartem 	 *   failure
31918c2aff7Sartem 	 *
32018c2aff7Sartem 	 */
32118c2aff7Sartem 
32218c2aff7Sartem 	FD_ZERO(&rfds);
32318c2aff7Sartem 	FD_SET(child_fd, &rfds);
32418c2aff7Sartem 	FD_ZERO(&efds);
32518c2aff7Sartem 	FD_SET(child_fd, &efds);
32618c2aff7Sartem 	/* Wait up to 250 seconds for device probing */
32718c2aff7Sartem 	tv.tv_sec = 250;
32818c2aff7Sartem 	tv.tv_usec = 0;
32918c2aff7Sartem 
33018c2aff7Sartem 	retval = select (child_fd + 1, &rfds, NULL, &efds, &tv);
33118c2aff7Sartem 
33218c2aff7Sartem 	if (child_died) {
33318c2aff7Sartem 		/* written from handle_sigchld */
33418c2aff7Sartem 		ret = 1;
33518c2aff7Sartem 		goto out;
33618c2aff7Sartem 	}
33718c2aff7Sartem 
33818c2aff7Sartem 	if (retval > 0) {
33918c2aff7Sartem 		/* means child wrote to socket or closed it; all good */
34018c2aff7Sartem 		ret = 0;
34118c2aff7Sartem 		goto out;
34218c2aff7Sartem 	}
34318c2aff7Sartem 
34418c2aff7Sartem 	/* assume timeout; kill child */
34518c2aff7Sartem 	kill (child_pid, SIGTERM);
34618c2aff7Sartem 	ret = 2;
34718c2aff7Sartem 
34818c2aff7Sartem out:
34918c2aff7Sartem 	return ret;
35018c2aff7Sartem }
35118c2aff7Sartem 
35218c2aff7Sartem /*--------------------------------------------------------------------------------------------------*/
35318c2aff7Sartem 
35418c2aff7Sartem /** Entry point for HAL daemon
35518c2aff7Sartem  *
35618c2aff7Sartem  *  @param  argc                Number of arguments
35718c2aff7Sartem  *  @param  argv                Array of arguments
35818c2aff7Sartem  *  @return                     Exit code
35918c2aff7Sartem  */
36018c2aff7Sartem int
main(int argc,char * argv[])36118c2aff7Sartem main (int argc, char *argv[])
36218c2aff7Sartem {
36318c2aff7Sartem 	GMainLoop *loop;
36418c2aff7Sartem 	char *path;
36518c2aff7Sartem 	char newpath[512];
36618c2aff7Sartem 
36718c2aff7Sartem 	openlog ("hald", LOG_PID, LOG_DAEMON);
36861f847afSAlexander Pyhalov #if !GLIB_CHECK_VERSION(2,35,0)
36918c2aff7Sartem 	g_type_init ();
37061f847afSAlexander Pyhalov #endif
37118c2aff7Sartem 	if (getenv ("HALD_VERBOSE"))
37218c2aff7Sartem 		hald_is_verbose = TRUE;
37318c2aff7Sartem 	else
37418c2aff7Sartem 		hald_is_verbose = FALSE;
37518c2aff7Sartem 
37618c2aff7Sartem 	/* our helpers are installed into libexec, so adjust out $PATH
37718c2aff7Sartem 	 * to include this at the end (since we want to overide in
37818c2aff7Sartem 	 * run-hald.sh and friends)
37918c2aff7Sartem 	 */
38018c2aff7Sartem 	path = getenv ("PATH");
38118c2aff7Sartem 	if (path != NULL) {
38218c2aff7Sartem 		g_strlcpy (newpath, path, sizeof (newpath));
38318c2aff7Sartem 		g_strlcat (newpath, ":", sizeof (newpath));
38418c2aff7Sartem 	} else {
38518c2aff7Sartem 		/* No PATH was set */
38618c2aff7Sartem 		newpath[0] = '\0';
387*55fea89dSDan Cross 	}
38818c2aff7Sartem 
38918c2aff7Sartem 	g_strlcat (newpath, PACKAGE_LIBEXEC_DIR, sizeof (newpath));
39018c2aff7Sartem 	g_strlcat (newpath, ":", sizeof (newpath));
39118c2aff7Sartem 	g_strlcat (newpath, PACKAGE_SCRIPT_DIR, sizeof (newpath));
39218c2aff7Sartem 
39318c2aff7Sartem 	setenv ("PATH", newpath, TRUE);
39418c2aff7Sartem 
39518c2aff7Sartem 	while (1) {
39618c2aff7Sartem 		int c;
39718c2aff7Sartem 		int option_index = 0;
39818c2aff7Sartem 		const char *opt;
39918c2aff7Sartem 		static struct option long_options[] = {
40018c2aff7Sartem 			{"daemon", 1, NULL, 0},
40118c2aff7Sartem 			{"verbose", 1, NULL, 0},
40218c2aff7Sartem 			{"use-syslog", 0, NULL, 0},
40318c2aff7Sartem 			{"help", 0, NULL, 0},
40418c2aff7Sartem 			{"version", 0, NULL, 0},
40518c2aff7Sartem 			{NULL, 0, NULL, 0}
40618c2aff7Sartem 		};
40718c2aff7Sartem 
40818c2aff7Sartem 		c = getopt_long (argc, argv, "",
40918c2aff7Sartem 				 long_options, &option_index);
41018c2aff7Sartem 		if (c == -1)
41118c2aff7Sartem 			break;
41218c2aff7Sartem 
41318c2aff7Sartem 		switch (c) {
41418c2aff7Sartem 		case 0:
41518c2aff7Sartem 			opt = long_options[option_index].name;
41618c2aff7Sartem 
41718c2aff7Sartem 			if (strcmp (opt, "help") == 0) {
41818c2aff7Sartem 				usage ();
41918c2aff7Sartem 				return 0;
42018c2aff7Sartem 			} else if (strcmp (opt, "version") == 0) {
42118c2aff7Sartem 				fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
42218c2aff7Sartem 				return 0;
42318c2aff7Sartem 			} else if (strcmp (opt, "daemon") == 0) {
42418c2aff7Sartem 				if (strcmp ("yes", optarg) == 0) {
42518c2aff7Sartem 					opt_become_daemon = TRUE;
42618c2aff7Sartem 				} else if (strcmp ("no", optarg) == 0) {
42718c2aff7Sartem 					opt_become_daemon = FALSE;
42818c2aff7Sartem 				} else {
42918c2aff7Sartem 					usage ();
43018c2aff7Sartem 					return 1;
43118c2aff7Sartem 				}
43218c2aff7Sartem 			} else if (strcmp (opt, "verbose") == 0) {
43318c2aff7Sartem 				if (strcmp ("yes", optarg) == 0) {
43418c2aff7Sartem 					hald_is_verbose = TRUE;
43518c2aff7Sartem 				} else if (strcmp ("no", optarg) == 0) {
43618c2aff7Sartem 					hald_is_verbose = FALSE;
43718c2aff7Sartem 				} else {
43818c2aff7Sartem 					usage ();
43918c2aff7Sartem 					return 1;
44018c2aff7Sartem 				}
44118c2aff7Sartem 			} else if (strcmp (opt, "use-syslog") == 0) {
44218c2aff7Sartem                                 hald_use_syslog = TRUE;
44318c2aff7Sartem 			}
44418c2aff7Sartem 
44518c2aff7Sartem 			break;
44618c2aff7Sartem 
44718c2aff7Sartem 		default:
44818c2aff7Sartem 			usage ();
44918c2aff7Sartem 			return 1;
45018c2aff7Sartem 			break;
45118c2aff7Sartem 		}
45218c2aff7Sartem 	}
45318c2aff7Sartem 
45418c2aff7Sartem 	if (hald_is_verbose)
45518c2aff7Sartem 		logger_enable ();
45618c2aff7Sartem 	else
45718c2aff7Sartem 		logger_disable ();
45818c2aff7Sartem 
45918c2aff7Sartem 	if (hald_use_syslog)
46018c2aff7Sartem 		logger_enable_syslog ();
46118c2aff7Sartem 	else
46218c2aff7Sartem 		logger_disable_syslog ();
46318c2aff7Sartem 
46418c2aff7Sartem 	/* will fork into two; only the child will return here if we are successful */
46518c2aff7Sartem 	/*master_slave_setup ();
46618c2aff7Sartem 	  sleep (100000000);*/
46718c2aff7Sartem 
46818c2aff7Sartem 	loop = g_main_loop_new (NULL, FALSE);
46918c2aff7Sartem 
47018c2aff7Sartem 	HAL_INFO ((PACKAGE_STRING));
47118c2aff7Sartem 
47218c2aff7Sartem 	if (opt_become_daemon) {
47318c2aff7Sartem 		int child_pid;
47418c2aff7Sartem 		int dev_null_fd;
47518c2aff7Sartem 		int pf;
47618c2aff7Sartem 		char pid[9];
477*55fea89dSDan Cross 
47818c2aff7Sartem 		HAL_INFO (("Will daemonize"));
47918c2aff7Sartem 		HAL_INFO (("Becoming a daemon"));
48018c2aff7Sartem 
48118c2aff7Sartem 		if (pipe (startup_daemonize_pipe) != 0) {
48218c2aff7Sartem 			fprintf (stderr, "Could not setup pipe: %s\n", strerror(errno));
48318c2aff7Sartem 			exit (1);
48418c2aff7Sartem 		}
48518c2aff7Sartem 
48618c2aff7Sartem 
48718c2aff7Sartem 		if (chdir ("/") < 0) {
48818c2aff7Sartem 			fprintf (stderr, "Could not chdir to /: %s\n", strerror(errno));
48918c2aff7Sartem 			exit (1);
49018c2aff7Sartem 		}
49118c2aff7Sartem 
49218c2aff7Sartem 		child_pid = fork ();
49318c2aff7Sartem 		switch (child_pid) {
49418c2aff7Sartem 		case -1:
49518c2aff7Sartem 			fprintf (stderr, "Cannot fork(): %s\n", strerror(errno));
49618c2aff7Sartem 			break;
49718c2aff7Sartem 
49818c2aff7Sartem 		case 0:
49918c2aff7Sartem 			/* child */
50018c2aff7Sartem 
50118c2aff7Sartem 			dev_null_fd = open ("/dev/null", O_RDWR);
50218c2aff7Sartem 			/* ignore if we can't open /dev/null */
50318c2aff7Sartem 			if (dev_null_fd >= 0) {
50418c2aff7Sartem 				/* attach /dev/null to stdout, stdin, stderr */
50518c2aff7Sartem 				dup2 (dev_null_fd, 0);
50618c2aff7Sartem 				dup2 (dev_null_fd, 1);
50718c2aff7Sartem 				dup2 (dev_null_fd, 2);
50818c2aff7Sartem 				close (dev_null_fd);
50918c2aff7Sartem 			}
51018c2aff7Sartem 
51118c2aff7Sartem 			umask (022);
51218c2aff7Sartem 			break;
51318c2aff7Sartem 
51418c2aff7Sartem 		default:
51518c2aff7Sartem 			/* parent, block until child writes */
51618c2aff7Sartem 			exit (parent_wait_for_child (startup_daemonize_pipe[0], child_pid));
51718c2aff7Sartem 			break;
51818c2aff7Sartem 		}
51918c2aff7Sartem 
52018c2aff7Sartem 		/* Create session */
52118c2aff7Sartem 		setsid ();
52218c2aff7Sartem 
52318c2aff7Sartem 		/* remove old pid file */
52418c2aff7Sartem 		unlink (HALD_PID_FILE);
52518c2aff7Sartem 
52618c2aff7Sartem 		/* Make a new one */
52718c2aff7Sartem 		if ((pf= open (HALD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
52818c2aff7Sartem 			snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
529d9e525a8SToomas Soome 			(void) write (pf, pid, strlen(pid));
53018c2aff7Sartem 			close (pf);
53118c2aff7Sartem 			atexit (delete_pid);
53218c2aff7Sartem 		}
53318c2aff7Sartem 	} else {
53418c2aff7Sartem 		HAL_INFO (("Will not daemonize"));
53518c2aff7Sartem 	}
53618c2aff7Sartem 
53718c2aff7Sartem 
53818c2aff7Sartem 	/* we need to do stuff when we are expected to terminate, thus
53918c2aff7Sartem 	 * this involves looking for SIGTERM; UNIX signal handlers are
54018c2aff7Sartem 	 * evil though, so set up a pipe to transmit the signal.
54118c2aff7Sartem 	 */
54218c2aff7Sartem 
54318c2aff7Sartem 	/* create pipe */
54418c2aff7Sartem 	if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
54518c2aff7Sartem 		DIE (("Could not setup pipe, errno=%d", errno));
54618c2aff7Sartem 	}
547*55fea89dSDan Cross 
54818c2aff7Sartem 	/* setup glib handler - 0 is for reading, 1 is for writing */
54918c2aff7Sartem 	sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
55018c2aff7Sartem 	if (sigterm_iochn == NULL)
55118c2aff7Sartem 		DIE (("Could not create GIOChannel"));
552*55fea89dSDan Cross 
55318c2aff7Sartem 	/* get callback when there is data to read */
554d9e525a8SToomas Soome 	(void) g_io_add_watch (
55518c2aff7Sartem 		sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
556*55fea89dSDan Cross 
55718c2aff7Sartem 	/* Finally, setup unix signal handler for TERM */
55818c2aff7Sartem 	signal (SIGTERM, handle_sigterm);
55918c2aff7Sartem 
56018c2aff7Sartem 	/* set up the local dbus server */
56118c2aff7Sartem 	if (!hald_dbus_local_server_init ())
56218c2aff7Sartem 		return 1;
56318c2aff7Sartem 	/* Start the runner helper daemon */
56418c2aff7Sartem 	if (!hald_runner_start_runner ()) {
56518c2aff7Sartem 		return 1;
56618c2aff7Sartem 	}
56718c2aff7Sartem 
56818c2aff7Sartem 	drop_privileges(0);
56918c2aff7Sartem 
57018c2aff7Sartem 	/* initialize operating system specific parts */
57118c2aff7Sartem 	osspec_init ();
57218c2aff7Sartem 
57318c2aff7Sartem 	hald_is_initialising = TRUE;
57418c2aff7Sartem 
57518c2aff7Sartem 	/* detect devices */
57618c2aff7Sartem 	osspec_probe ();
57718c2aff7Sartem 
57818c2aff7Sartem 	/* run the main loop and serve clients */
57918c2aff7Sartem 	g_main_loop_run (loop);
58018c2aff7Sartem 
58118c2aff7Sartem 	return 0;
58218c2aff7Sartem }
58318c2aff7Sartem 
58418c2aff7Sartem #ifdef HALD_MEMLEAK_DBG
58518c2aff7Sartem extern int dbg_hal_device_object_delta;
58618c2aff7Sartem 
58718c2aff7Sartem /* useful for valgrinding; see below */
58818c2aff7Sartem static gboolean
my_shutdown(gpointer data)58918c2aff7Sartem my_shutdown (gpointer data)
59018c2aff7Sartem {
59118c2aff7Sartem 	HalDeviceStore *gdl;
592*55fea89dSDan Cross 
59318c2aff7Sartem 	printf ("Num devices in TDL: %d\n", g_slist_length ((hald_get_tdl ())->devices));
59418c2aff7Sartem 	printf ("Num devices in GDL: %d\n", g_slist_length ((hald_get_gdl ())->devices));
595*55fea89dSDan Cross 
59618c2aff7Sartem 	gdl = hald_get_gdl ();
59718c2aff7Sartem next:
59818c2aff7Sartem 	if (g_slist_length (gdl->devices) > 0) {
59918c2aff7Sartem 		HalDevice *d = HAL_DEVICE(gdl->devices->data);
60018c2aff7Sartem 		hal_device_store_remove (gdl, d);
60118c2aff7Sartem 		g_object_unref (d);
60218c2aff7Sartem 		goto next;
60318c2aff7Sartem 	}
604*55fea89dSDan Cross 
60518c2aff7Sartem 	printf ("hal_device_object_delta = %d (should be zero)\n", dbg_hal_device_object_delta);
60618c2aff7Sartem 	exit (1);
60718c2aff7Sartem }
60818c2aff7Sartem #endif
60918c2aff7Sartem 
610*55fea89dSDan Cross void
osspec_probe_done(void)61118c2aff7Sartem osspec_probe_done (void)
61218c2aff7Sartem {
61318c2aff7Sartem 	char buf[1] = {0};
61418c2aff7Sartem 
61518c2aff7Sartem 	HAL_INFO (("Device probing completed"));
61618c2aff7Sartem 
61718c2aff7Sartem 	if (!hald_dbus_init ()) {
61818c2aff7Sartem 		hald_runner_kill_all();
61918c2aff7Sartem 		exit (1);
62018c2aff7Sartem 	}
62118c2aff7Sartem 
62218c2aff7Sartem 	/* tell parent to exit */
623d9e525a8SToomas Soome 	(void) write (startup_daemonize_pipe[1], buf, sizeof (buf));
62418c2aff7Sartem 	close (startup_daemonize_pipe[0]);
62518c2aff7Sartem 	close (startup_daemonize_pipe[1]);
62618c2aff7Sartem 
62718c2aff7Sartem 	hald_is_initialising = FALSE;
62818c2aff7Sartem 
62918c2aff7Sartem #ifdef HALD_MEMLEAK_DBG
63018c2aff7Sartem 	g_timeout_add ((HALD_MEMLEAK_DBG) * 1000,
63118c2aff7Sartem 		       my_shutdown,
63218c2aff7Sartem 		       NULL);
63318c2aff7Sartem #endif
63418c2aff7Sartem }
63518c2aff7Sartem 
63618c2aff7Sartem 
63718c2aff7Sartem /** @} */
638