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 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 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 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 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 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 * 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 * 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 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 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 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 29418c2aff7Sartem handle_sigchld (int value) 29518c2aff7Sartem { 29618c2aff7Sartem child_died = TRUE; 29718c2aff7Sartem } 29818c2aff7Sartem 29918c2aff7Sartem static int 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 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*61f847afSAlexander Pyhalov #if !GLIB_CHECK_VERSION(2,35,0) 37118c2aff7Sartem g_type_init (); 372*61f847afSAlexander 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 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 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