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