18c2aff776a775d34a4c9893a4c72e0434d68e36artem/***************************************************************************
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * CVSID: $Id$
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * hald.c : main startup for HAL daemon
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Copyright (C) 2005 Danny Kukawka, <danny.kukawka@web.de>
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Licensed under the Academic Free License version 2.1
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * This program is free software; you can redistribute it and/or modify
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * it under the terms of the GNU General Public License as published by
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * the Free Software Foundation; either version 2 of the License, or
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * (at your option) any later version.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * This program is distributed in the hope that it will be useful,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * but WITHOUT ANY WARRANTY; without even the implied warranty of
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * GNU General Public License for more details.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * You should have received a copy of the GNU General Public License
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * along with this program; if not, write to the Free Software
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18c2aff776a775d34a4c9893a4c72e0434d68e36artem **************************************************************************/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/*#include "master_slave.h"*/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @defgroup HalDaemon HAL daemon
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @brief The HAL daemon manages persistent device objects available through
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * a D-BUS network API
18c2aff776a775d34a4c9893a4c72e0434d68e36artemaddon_terminated (HalDevice *device, guint32 exit_type,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem HAL_INFO (("in addon_terminated for udi=%s", device->udi));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* however, the world can stop, mark this addon as ready
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
18c2aff776a775d34a4c9893a4c72e0434d68e36artemgdl_store_changed (HalDeviceStore *store, HalDevice *device,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem HAL_INFO (("Added device to GDL; udi=%s", hal_device_get_udi(device)));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if ((addons = hal_device_property_get_strlist (device, "info.addons")) != NULL) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (hald_runner_start(device, command_line, extra_env, addon_terminated, NULL, NULL)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /*hal_device_print (device);*/
18c2aff776a775d34a4c9893a4c72e0434d68e36artemgdl_property_changed (HalDeviceStore *store, HalDevice *device,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem device_send_signal_property_modified (device, key, removed, added);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* only execute the callouts if the property _changed_ */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /*hal_callout_property (device, key)*/;
18c2aff776a775d34a4c9893a4c72e0434d68e36artemgdl_capability_added (HalDeviceStore *store, HalDevice *device,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem manager_send_signal_new_capability (device, capability);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /*hal_callout_capability (device, capability, TRUE)*/;
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "store_changed",
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "device_property_changed",
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "device_capability_added",
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @defgroup MainDaemon Basic functions
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @ingroup HalDaemon
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @brief Basic functions in the HAL daemon
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/** Print out program usage.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]\n");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " --daemon=yes|no Become a daemon\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " --verbose=yes|no Print out debug (overrides HALD_VERBOSE)\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " --use-syslog Print out debug messages to syslog instead of stderr.\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " Use this option to get debug messages if HAL runs as\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " daemon.\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " --help Show this information and exit\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " --version Output version information and exit"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "The HAL daemon detects devices present in the system and provides the\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "org.freedesktop.Hal service through the system-wide message bus provided\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "by D-BUS.\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem "For more information visit http://freedesktop.org/Software/hal\n"
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/** If #TRUE, we will daemonize */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/** If #TRUE, we will spew out debug */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* write a 'S' character to the other end to tell about
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * the signal. Note that 'the other end' is a GIOChannel thingy
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * that is only called from the mainloop - thus this is how we
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * defer this since UNIX signal handlers are evil
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Oh, and write(2) is indeed reentrant */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem written = write (sigterm_unix_signal_pipe_fds[1], marker, 1);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Empty the pipe */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/** This is set to #TRUE if we are probing and #FALSE otherwise */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/*--------------------------------------------------------------------------------------------------*/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* wait for either
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * o Child writes something to the child_fd; means that device
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * probing is completed and the parent should exit with success
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * o Child is killed (segfault etc.); means that parent should exit
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * with failure
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * o Timeout; means that we should kill the child and exit with
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Wait up to 250 seconds for device probing */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem retval = select (child_fd + 1, &rfds, NULL, &efds, &tv);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* written from handle_sigchld */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* means child wrote to socket or closed it; all good */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* assume timeout; kill child */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/*--------------------------------------------------------------------------------------------------*/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/** Entry point for HAL daemon
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @param argc Number of arguments
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @param argv Array of arguments
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * @return Exit code
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* our helpers are installed into libexec, so adjust out $PATH
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * to include this at the end (since we want to overide in
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * run-hald.sh and friends)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* No PATH was set */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem g_strlcat (newpath, PACKAGE_LIBEXEC_DIR, sizeof (newpath));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem g_strlcat (newpath, PACKAGE_SCRIPT_DIR, sizeof (newpath));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem while (1) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (c == -1)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem switch (c) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* will fork into two; only the child will return here if we are successful */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /*master_slave_setup ();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sleep (100000000);*/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem fprintf (stderr, "Could not setup pipe: %s\n", strerror(errno));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem fprintf (stderr, "Could not chdir to /: %s\n", strerror(errno));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem fprintf (stderr, "Cannot fork(): %s\n", strerror(errno));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* child */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* ignore if we can't open /dev/null */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* attach /dev/null to stdout, stdin, stderr */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* parent, block until child writes */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem exit (parent_wait_for_child (startup_daemonize_pipe[0], child_pid));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Create session */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* remove old pid file */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Make a new one */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if ((pf= open (HALD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* we need to do stuff when we are expected to terminate, thus
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * this involves looking for SIGTERM; UNIX signal handlers are
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * evil though, so set up a pipe to transmit the signal.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* create pipe */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* setup glib handler - 0 is for reading, 1 is for writing */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* get callback when there is data to read */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Finally, setup unix signal handler for TERM */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* set up the local dbus server */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Start the runner helper daemon */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* initialize operating system specific parts */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* detect devices */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* run the main loop and serve clients */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/* useful for valgrinding; see below */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem printf ("Num devices in TDL: %d\n", g_slist_length ((hald_get_tdl ())->devices));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem printf ("Num devices in GDL: %d\n", g_slist_length ((hald_get_gdl ())->devices));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem printf ("hal_device_object_delta = %d (should be zero)\n", dbg_hal_device_object_delta);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* tell parent to exit */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem written = write (startup_daemonize_pipe[1], buf, sizeof (buf));