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)7818c2aff7Sartem 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
8618c2aff7Sartem /* 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)) {
11718c2aff7Sartem 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 {
12118c2aff7Sartem 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 ();
17318c2aff7Sartem
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 ();
19318c2aff7Sartem
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
24118c2aff7Sartem static void
handle_sigterm(int value)24218c2aff7Sartem handle_sigterm (int value)
24318c2aff7Sartem {
24418c2aff7Sartem ssize_t written;
24518c2aff7Sartem static char marker[1] = {'S'};
24618c2aff7Sartem
24718c2aff7Sartem /* write a 'S' character to the other end to tell about
24818c2aff7Sartem * the signal. Note that 'the other end' is a GIOChannel thingy
24918c2aff7Sartem * that is only called from the mainloop - thus this is how we
25018c2aff7Sartem * defer this since UNIX signal handlers are evil
25118c2aff7Sartem *
25218c2aff7Sartem * Oh, and write(2) is indeed reentrant */
25318c2aff7Sartem written = write (sigterm_unix_signal_pipe_fds[1], marker, 1);
25418c2aff7Sartem }
25518c2aff7Sartem
25618c2aff7Sartem static gboolean
sigterm_iochn_data(GIOChannel * source,GIOCondition condition,gpointer user_data)25718c2aff7Sartem sigterm_iochn_data (GIOChannel *source,
25818c2aff7Sartem GIOCondition condition,
25918c2aff7Sartem gpointer user_data)
26018c2aff7Sartem {
26118c2aff7Sartem GError *err = NULL;
26218c2aff7Sartem gchar data[1];
26318c2aff7Sartem gsize bytes_read;
26418c2aff7Sartem
26518c2aff7Sartem /* Empty the pipe */
26618c2aff7Sartem if (G_IO_STATUS_NORMAL !=
26718c2aff7Sartem g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
26818c2aff7Sartem HAL_ERROR (("Error emptying sigterm pipe: %s",
26918c2aff7Sartem err->message));
27018c2aff7Sartem g_error_free (err);
27118c2aff7Sartem goto out;
27218c2aff7Sartem }
27318c2aff7Sartem
27418c2aff7Sartem HAL_INFO (("Caught SIGTERM, initiating shutdown"));
27518c2aff7Sartem hald_runner_kill_all();
27618c2aff7Sartem exit (0);
27718c2aff7Sartem
27818c2aff7Sartem out:
27918c2aff7Sartem return TRUE;
28018c2aff7Sartem }
28118c2aff7Sartem
28218c2aff7Sartem
28318c2aff7Sartem /** This is set to #TRUE if we are probing and #FALSE otherwise */
28418c2aff7Sartem dbus_bool_t hald_is_initialising;
28518c2aff7Sartem
28618c2aff7Sartem static int startup_daemonize_pipe[2];
28718c2aff7Sartem
28818c2aff7Sartem
28918c2aff7Sartem /*--------------------------------------------------------------------------------------------------*/
29018c2aff7Sartem
29118c2aff7Sartem static gboolean child_died = FALSE;
29218c2aff7Sartem
29318c2aff7Sartem static void
handle_sigchld(int value)29418c2aff7Sartem handle_sigchld (int value)
29518c2aff7Sartem {
29618c2aff7Sartem child_died = TRUE;
29718c2aff7Sartem }
29818c2aff7Sartem
29918c2aff7Sartem static int
parent_wait_for_child(int child_fd,pid_t child_pid)30018c2aff7Sartem parent_wait_for_child (int child_fd, pid_t child_pid)
30118c2aff7Sartem {
30218c2aff7Sartem fd_set rfds;
30318c2aff7Sartem fd_set efds;
30418c2aff7Sartem struct timeval tv;
30518c2aff7Sartem int retval;
30618c2aff7Sartem int ret;
30718c2aff7Sartem
30818c2aff7Sartem signal(SIGCHLD, handle_sigchld);
30918c2aff7Sartem
31018c2aff7Sartem /* wait for either
31118c2aff7Sartem *
31218c2aff7Sartem * o Child writes something to the child_fd; means that device
31318c2aff7Sartem * probing is completed and the parent should exit with success
31418c2aff7Sartem *
31518c2aff7Sartem * o Child is killed (segfault etc.); means that parent should exit
31618c2aff7Sartem * with failure
31718c2aff7Sartem *
31818c2aff7Sartem * o Timeout; means that we should kill the child and exit with
31918c2aff7Sartem * failure
32018c2aff7Sartem *
32118c2aff7Sartem */
32218c2aff7Sartem
32318c2aff7Sartem FD_ZERO(&rfds);
32418c2aff7Sartem FD_SET(child_fd, &rfds);
32518c2aff7Sartem FD_ZERO(&efds);
32618c2aff7Sartem FD_SET(child_fd, &efds);
32718c2aff7Sartem /* Wait up to 250 seconds for device probing */
32818c2aff7Sartem tv.tv_sec = 250;
32918c2aff7Sartem tv.tv_usec = 0;
33018c2aff7Sartem
33118c2aff7Sartem retval = select (child_fd + 1, &rfds, NULL, &efds, &tv);
33218c2aff7Sartem
33318c2aff7Sartem if (child_died) {
33418c2aff7Sartem /* written from handle_sigchld */
33518c2aff7Sartem ret = 1;
33618c2aff7Sartem goto out;
33718c2aff7Sartem }
33818c2aff7Sartem
33918c2aff7Sartem if (retval > 0) {
34018c2aff7Sartem /* means child wrote to socket or closed it; all good */
34118c2aff7Sartem ret = 0;
34218c2aff7Sartem goto out;
34318c2aff7Sartem }
34418c2aff7Sartem
34518c2aff7Sartem /* assume timeout; kill child */
34618c2aff7Sartem kill (child_pid, SIGTERM);
34718c2aff7Sartem ret = 2;
34818c2aff7Sartem
34918c2aff7Sartem out:
35018c2aff7Sartem return ret;
35118c2aff7Sartem }
35218c2aff7Sartem
35318c2aff7Sartem /*--------------------------------------------------------------------------------------------------*/
35418c2aff7Sartem
35518c2aff7Sartem /** Entry point for HAL daemon
35618c2aff7Sartem *
35718c2aff7Sartem * @param argc Number of arguments
35818c2aff7Sartem * @param argv Array of arguments
35918c2aff7Sartem * @return Exit code
36018c2aff7Sartem */
36118c2aff7Sartem int
main(int argc,char * argv[])36218c2aff7Sartem main (int argc, char *argv[])
36318c2aff7Sartem {
36418c2aff7Sartem GMainLoop *loop;
36518c2aff7Sartem guint sigterm_iochn_listener_source_id;
36618c2aff7Sartem char *path;
36718c2aff7Sartem char newpath[512];
36818c2aff7Sartem
36918c2aff7Sartem openlog ("hald", LOG_PID, LOG_DAEMON);
370*6f391373SAlexander Pyhalov #if !GLIB_CHECK_VERSION(2,35,0)
37118c2aff7Sartem g_type_init ();
372*6f391373SAlexander Pyhalov #endif
37318c2aff7Sartem if (getenv ("HALD_VERBOSE"))
37418c2aff7Sartem hald_is_verbose = TRUE;
37518c2aff7Sartem else
37618c2aff7Sartem hald_is_verbose = FALSE;
37718c2aff7Sartem
37818c2aff7Sartem /* our helpers are installed into libexec, so adjust out $PATH
37918c2aff7Sartem * to include this at the end (since we want to overide in
38018c2aff7Sartem * run-hald.sh and friends)
38118c2aff7Sartem */
38218c2aff7Sartem path = getenv ("PATH");
38318c2aff7Sartem if (path != NULL) {
38418c2aff7Sartem g_strlcpy (newpath, path, sizeof (newpath));
38518c2aff7Sartem g_strlcat (newpath, ":", sizeof (newpath));
38618c2aff7Sartem } else {
38718c2aff7Sartem /* No PATH was set */
38818c2aff7Sartem newpath[0] = '\0';
38918c2aff7Sartem }
39018c2aff7Sartem
39118c2aff7Sartem g_strlcat (newpath, PACKAGE_LIBEXEC_DIR, sizeof (newpath));
39218c2aff7Sartem g_strlcat (newpath, ":", sizeof (newpath));
39318c2aff7Sartem g_strlcat (newpath, PACKAGE_SCRIPT_DIR, sizeof (newpath));
39418c2aff7Sartem
39518c2aff7Sartem setenv ("PATH", newpath, TRUE);
39618c2aff7Sartem
39718c2aff7Sartem while (1) {
39818c2aff7Sartem int c;
39918c2aff7Sartem int option_index = 0;
40018c2aff7Sartem const char *opt;
40118c2aff7Sartem static struct option long_options[] = {
40218c2aff7Sartem {"daemon", 1, NULL, 0},
40318c2aff7Sartem {"verbose", 1, NULL, 0},
40418c2aff7Sartem {"use-syslog", 0, NULL, 0},
40518c2aff7Sartem {"help", 0, NULL, 0},
40618c2aff7Sartem {"version", 0, NULL, 0},
40718c2aff7Sartem {NULL, 0, NULL, 0}
40818c2aff7Sartem };
40918c2aff7Sartem
41018c2aff7Sartem c = getopt_long (argc, argv, "",
41118c2aff7Sartem long_options, &option_index);
41218c2aff7Sartem if (c == -1)
41318c2aff7Sartem break;
41418c2aff7Sartem
41518c2aff7Sartem switch (c) {
41618c2aff7Sartem case 0:
41718c2aff7Sartem opt = long_options[option_index].name;
41818c2aff7Sartem
41918c2aff7Sartem if (strcmp (opt, "help") == 0) {
42018c2aff7Sartem usage ();
42118c2aff7Sartem return 0;
42218c2aff7Sartem } else if (strcmp (opt, "version") == 0) {
42318c2aff7Sartem fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
42418c2aff7Sartem return 0;
42518c2aff7Sartem } else if (strcmp (opt, "daemon") == 0) {
42618c2aff7Sartem if (strcmp ("yes", optarg) == 0) {
42718c2aff7Sartem opt_become_daemon = TRUE;
42818c2aff7Sartem } else if (strcmp ("no", optarg) == 0) {
42918c2aff7Sartem opt_become_daemon = FALSE;
43018c2aff7Sartem } else {
43118c2aff7Sartem usage ();
43218c2aff7Sartem return 1;
43318c2aff7Sartem }
43418c2aff7Sartem } else if (strcmp (opt, "verbose") == 0) {
43518c2aff7Sartem if (strcmp ("yes", optarg) == 0) {
43618c2aff7Sartem hald_is_verbose = TRUE;
43718c2aff7Sartem } else if (strcmp ("no", optarg) == 0) {
43818c2aff7Sartem hald_is_verbose = FALSE;
43918c2aff7Sartem } else {
44018c2aff7Sartem usage ();
44118c2aff7Sartem return 1;
44218c2aff7Sartem }
44318c2aff7Sartem } else if (strcmp (opt, "use-syslog") == 0) {
44418c2aff7Sartem hald_use_syslog = TRUE;
44518c2aff7Sartem }
44618c2aff7Sartem
44718c2aff7Sartem break;
44818c2aff7Sartem
44918c2aff7Sartem default:
45018c2aff7Sartem usage ();
45118c2aff7Sartem return 1;
45218c2aff7Sartem break;
45318c2aff7Sartem }
45418c2aff7Sartem }
45518c2aff7Sartem
45618c2aff7Sartem if (hald_is_verbose)
45718c2aff7Sartem logger_enable ();
45818c2aff7Sartem else
45918c2aff7Sartem logger_disable ();
46018c2aff7Sartem
46118c2aff7Sartem if (hald_use_syslog)
46218c2aff7Sartem logger_enable_syslog ();
46318c2aff7Sartem else
46418c2aff7Sartem logger_disable_syslog ();
46518c2aff7Sartem
46618c2aff7Sartem /* will fork into two; only the child will return here if we are successful */
46718c2aff7Sartem /*master_slave_setup ();
46818c2aff7Sartem sleep (100000000);*/
46918c2aff7Sartem
47018c2aff7Sartem loop = g_main_loop_new (NULL, FALSE);
47118c2aff7Sartem
47218c2aff7Sartem HAL_INFO ((PACKAGE_STRING));
47318c2aff7Sartem
47418c2aff7Sartem if (opt_become_daemon) {
47518c2aff7Sartem int child_pid;
47618c2aff7Sartem int dev_null_fd;
47718c2aff7Sartem int pf;
47818c2aff7Sartem ssize_t written;
47918c2aff7Sartem char pid[9];
48018c2aff7Sartem
48118c2aff7Sartem HAL_INFO (("Will daemonize"));
48218c2aff7Sartem HAL_INFO (("Becoming a daemon"));
48318c2aff7Sartem
48418c2aff7Sartem if (pipe (startup_daemonize_pipe) != 0) {
48518c2aff7Sartem fprintf (stderr, "Could not setup pipe: %s\n", strerror(errno));
48618c2aff7Sartem exit (1);
48718c2aff7Sartem }
48818c2aff7Sartem
48918c2aff7Sartem
49018c2aff7Sartem if (chdir ("/") < 0) {
49118c2aff7Sartem fprintf (stderr, "Could not chdir to /: %s\n", strerror(errno));
49218c2aff7Sartem exit (1);
49318c2aff7Sartem }
49418c2aff7Sartem
49518c2aff7Sartem child_pid = fork ();
49618c2aff7Sartem switch (child_pid) {
49718c2aff7Sartem case -1:
49818c2aff7Sartem fprintf (stderr, "Cannot fork(): %s\n", strerror(errno));
49918c2aff7Sartem break;
50018c2aff7Sartem
50118c2aff7Sartem case 0:
50218c2aff7Sartem /* child */
50318c2aff7Sartem
50418c2aff7Sartem dev_null_fd = open ("/dev/null", O_RDWR);
50518c2aff7Sartem /* ignore if we can't open /dev/null */
50618c2aff7Sartem if (dev_null_fd >= 0) {
50718c2aff7Sartem /* attach /dev/null to stdout, stdin, stderr */
50818c2aff7Sartem dup2 (dev_null_fd, 0);
50918c2aff7Sartem dup2 (dev_null_fd, 1);
51018c2aff7Sartem dup2 (dev_null_fd, 2);
51118c2aff7Sartem close (dev_null_fd);
51218c2aff7Sartem }
51318c2aff7Sartem
51418c2aff7Sartem umask (022);
51518c2aff7Sartem break;
51618c2aff7Sartem
51718c2aff7Sartem default:
51818c2aff7Sartem /* parent, block until child writes */
51918c2aff7Sartem exit (parent_wait_for_child (startup_daemonize_pipe[0], child_pid));
52018c2aff7Sartem break;
52118c2aff7Sartem }
52218c2aff7Sartem
52318c2aff7Sartem /* Create session */
52418c2aff7Sartem setsid ();
52518c2aff7Sartem
52618c2aff7Sartem /* remove old pid file */
52718c2aff7Sartem unlink (HALD_PID_FILE);
52818c2aff7Sartem
52918c2aff7Sartem /* Make a new one */
53018c2aff7Sartem if ((pf= open (HALD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
53118c2aff7Sartem snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
53218c2aff7Sartem written = write (pf, pid, strlen(pid));
53318c2aff7Sartem close (pf);
53418c2aff7Sartem atexit (delete_pid);
53518c2aff7Sartem }
53618c2aff7Sartem } else {
53718c2aff7Sartem HAL_INFO (("Will not daemonize"));
53818c2aff7Sartem }
53918c2aff7Sartem
54018c2aff7Sartem
54118c2aff7Sartem /* we need to do stuff when we are expected to terminate, thus
54218c2aff7Sartem * this involves looking for SIGTERM; UNIX signal handlers are
54318c2aff7Sartem * evil though, so set up a pipe to transmit the signal.
54418c2aff7Sartem */
54518c2aff7Sartem
54618c2aff7Sartem /* create pipe */
54718c2aff7Sartem if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
54818c2aff7Sartem DIE (("Could not setup pipe, errno=%d", errno));
54918c2aff7Sartem }
55018c2aff7Sartem
55118c2aff7Sartem /* setup glib handler - 0 is for reading, 1 is for writing */
55218c2aff7Sartem sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
55318c2aff7Sartem if (sigterm_iochn == NULL)
55418c2aff7Sartem DIE (("Could not create GIOChannel"));
55518c2aff7Sartem
55618c2aff7Sartem /* get callback when there is data to read */
55718c2aff7Sartem sigterm_iochn_listener_source_id = g_io_add_watch (
55818c2aff7Sartem sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
55918c2aff7Sartem
56018c2aff7Sartem /* Finally, setup unix signal handler for TERM */
56118c2aff7Sartem signal (SIGTERM, handle_sigterm);
56218c2aff7Sartem
56318c2aff7Sartem /* set up the local dbus server */
56418c2aff7Sartem if (!hald_dbus_local_server_init ())
56518c2aff7Sartem return 1;
56618c2aff7Sartem /* Start the runner helper daemon */
56718c2aff7Sartem if (!hald_runner_start_runner ()) {
56818c2aff7Sartem return 1;
56918c2aff7Sartem }
57018c2aff7Sartem
57118c2aff7Sartem drop_privileges(0);
57218c2aff7Sartem
57318c2aff7Sartem /* initialize operating system specific parts */
57418c2aff7Sartem osspec_init ();
57518c2aff7Sartem
57618c2aff7Sartem hald_is_initialising = TRUE;
57718c2aff7Sartem
57818c2aff7Sartem /* detect devices */
57918c2aff7Sartem osspec_probe ();
58018c2aff7Sartem
58118c2aff7Sartem /* run the main loop and serve clients */
58218c2aff7Sartem g_main_loop_run (loop);
58318c2aff7Sartem
58418c2aff7Sartem return 0;
58518c2aff7Sartem }
58618c2aff7Sartem
58718c2aff7Sartem #ifdef HALD_MEMLEAK_DBG
58818c2aff7Sartem extern int dbg_hal_device_object_delta;
58918c2aff7Sartem
59018c2aff7Sartem /* useful for valgrinding; see below */
59118c2aff7Sartem static gboolean
my_shutdown(gpointer data)59218c2aff7Sartem my_shutdown (gpointer data)
59318c2aff7Sartem {
59418c2aff7Sartem HalDeviceStore *gdl;
59518c2aff7Sartem
59618c2aff7Sartem printf ("Num devices in TDL: %d\n", g_slist_length ((hald_get_tdl ())->devices));
59718c2aff7Sartem printf ("Num devices in GDL: %d\n", g_slist_length ((hald_get_gdl ())->devices));
59818c2aff7Sartem
59918c2aff7Sartem gdl = hald_get_gdl ();
60018c2aff7Sartem next:
60118c2aff7Sartem if (g_slist_length (gdl->devices) > 0) {
60218c2aff7Sartem HalDevice *d = HAL_DEVICE(gdl->devices->data);
60318c2aff7Sartem hal_device_store_remove (gdl, d);
60418c2aff7Sartem g_object_unref (d);
60518c2aff7Sartem goto next;
60618c2aff7Sartem }
60718c2aff7Sartem
60818c2aff7Sartem printf ("hal_device_object_delta = %d (should be zero)\n", dbg_hal_device_object_delta);
60918c2aff7Sartem exit (1);
61018c2aff7Sartem }
61118c2aff7Sartem #endif
61218c2aff7Sartem
61318c2aff7Sartem void
osspec_probe_done(void)61418c2aff7Sartem osspec_probe_done (void)
61518c2aff7Sartem {
61618c2aff7Sartem ssize_t written;
61718c2aff7Sartem char buf[1] = {0};
61818c2aff7Sartem
61918c2aff7Sartem HAL_INFO (("Device probing completed"));
62018c2aff7Sartem
62118c2aff7Sartem if (!hald_dbus_init ()) {
62218c2aff7Sartem hald_runner_kill_all();
62318c2aff7Sartem exit (1);
62418c2aff7Sartem }
62518c2aff7Sartem
62618c2aff7Sartem /* tell parent to exit */
62718c2aff7Sartem written = write (startup_daemonize_pipe[1], buf, sizeof (buf));
62818c2aff7Sartem close (startup_daemonize_pipe[0]);
62918c2aff7Sartem close (startup_daemonize_pipe[1]);
63018c2aff7Sartem
63118c2aff7Sartem hald_is_initialising = FALSE;
63218c2aff7Sartem
63318c2aff7Sartem #ifdef HALD_MEMLEAK_DBG
63418c2aff7Sartem g_timeout_add ((HALD_MEMLEAK_DBG) * 1000,
63518c2aff7Sartem my_shutdown,
63618c2aff7Sartem NULL);
63718c2aff7Sartem #endif
63818c2aff7Sartem }
63918c2aff7Sartem
64018c2aff7Sartem
64118c2aff7Sartem /** @} */
642