/***************************************************************************
* CVSID: $Id$
*
* hald.c : main startup for HAL daemon
*
* Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
* Copyright (C) 2005 Danny Kukawka, <danny.kukawka@web.de>
*
* Licensed under the Academic Free License version 2.1
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <pwd.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <grp.h>
#include <syslog.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
/*#include "master_slave.h"*/
#include "logger.h"
#include "hald.h"
#include "device_store.h"
#include "device_info.h"
#include "osspec.h"
#include "hald_dbus.h"
#include "util.h"
#include "hald_runner.h"
#include "util_helper.h"
static void delete_pid(void)
{
}
/**
* @defgroup HalDaemon HAL daemon
* @brief The HAL daemon manages persistent device objects available through
* a D-BUS network API
*/
static void
{
/* TODO: log to syslog - addons shouldn't just terminate, this is a bug with the addon */
/* however, the world can stop, mark this addon as ready
* (TODO: potential bug if the addon crashed after calling libhal_device_addon_is_ready())
*/
if (hal_device_inc_num_ready_addons (device)) {
if (hal_device_are_all_addons_ready (device)) {
}
}
}
static void
{
if (is_added) {
GSList *i;
HAL_INFO (("Started addon %s for udi %s",
} else {
HAL_ERROR (("Cannot start addon %s for udi %s",
}
}
}
} else {
}
/*hal_device_print (device);*/
if (is_added) {
if (hal_device_are_all_addons_ready (device)) {
}
} else {
if (hal_device_are_all_addons_ready (device)) {
}
}
}
static void
{
if (hal_device_are_all_addons_ready (device)) {
}
/* only execute the callouts if the property _changed_ */
/*hal_callout_property (device, key)*/;
}
static void
{
if (hal_device_are_all_addons_ready (device)) {
}
/*hal_callout_capability (device, capability, TRUE)*/;
}
hald_get_gdl (void)
{
if (global_device_list == NULL) {
"store_changed",
"device_property_changed",
"device_capability_added",
}
return global_device_list;
}
hald_get_tdl (void)
{
if (temporary_device_list == NULL) {
}
return temporary_device_list;
}
/**
* @defgroup MainDaemon Basic functions
* @ingroup HalDaemon
* @brief Basic functions in the HAL daemon
* @{
*/
/** Print out program usage.
*
*/
static void
usage ()
{
"\n"
" --daemon=yes|no Become a daemon\n"
" --verbose=yes|no Print out debug (overrides HALD_VERBOSE)\n"
" --use-syslog Print out debug messages to syslog instead of stderr.\n"
" Use this option to get debug messages if HAL runs as\n"
" daemon.\n"
" --help Show this information and exit\n"
" --version Output version information and exit"
"\n"
"The HAL daemon detects devices present in the system and provides the\n"
"org.freedesktop.Hal service through the system-wide message bus provided\n"
"by D-BUS.\n"
"\n"
"For more information visit http://freedesktop.org/Software/hal\n"
"\n");
}
/** If #TRUE, we will daemonize */
/** If #TRUE, we will spew out debug */
static void
{
/* write a 'S' character to the other end to tell about
* the signal. Note that 'the other end' is a GIOChannel thingy
* that is only called from the mainloop - thus this is how we
* defer this since UNIX signal handlers are evil
*
* Oh, and write(2) is indeed reentrant */
}
static gboolean
{
/* Empty the pipe */
if (G_IO_STATUS_NORMAL !=
HAL_ERROR (("Error emptying sigterm pipe: %s",
g_error_free (err);
goto out;
}
HAL_INFO (("Caught SIGTERM, initiating shutdown"));
exit (0);
out:
return TRUE;
}
/** This is set to #TRUE if we are probing and #FALSE otherwise */
/*--------------------------------------------------------------------------------------------------*/
static void
{
child_died = TRUE;
}
static int
{
int retval;
int ret;
/* wait for either
*
* o Child writes something to the child_fd; means that device
* probing is completed and the parent should exit with success
*
* o Child is killed (segfault etc.); means that parent should exit
* with failure
*
* o Timeout; we do not set timeout here; hal service has its own
* timeout. The default timeout is 600 seconds.
*
*/
if (child_died) {
/* written from handle_sigchld */
ret = 1;
goto out;
}
if (retval > 0) {
/* means child wrote to socket or closed it; all good */
ret = 0;
goto out;
}
/* assume timeout; kill child */
ret = 2;
out:
return ret;
}
/*--------------------------------------------------------------------------------------------------*/
/** Entry point for HAL daemon
*
* @param argc Number of arguments
* @param argv Array of arguments
* @return Exit code
*/
int
{
char *path;
g_type_init ();
if (getenv ("HALD_VERBOSE"))
else
/* our helpers are installed into libexec, so adjust out $PATH
* to include this at the end (since we want to overide in
* run-hald.sh and friends)
*/
} else {
/* No PATH was set */
newpath[0] = '\0';
}
while (1) {
int c;
int option_index = 0;
const char *opt;
{"use-syslog", 0, NULL, 0},
{"help", 0, NULL, 0},
{"version", 0, NULL, 0},
};
if (c == -1)
break;
switch (c) {
case 0:
usage ();
return 0;
return 0;
} else {
usage ();
return 1;
}
} else {
usage ();
return 1;
}
}
break;
default:
usage ();
return 1;
break;
}
}
if (hald_is_verbose)
logger_enable ();
else
logger_disable ();
if (hald_use_syslog)
else
/* will fork into two; only the child will return here if we are successful */
/*master_slave_setup ();
sleep (100000000);*/
HAL_INFO ((PACKAGE_STRING));
if (opt_become_daemon) {
int child_pid;
int dev_null_fd;
int pf;
HAL_INFO (("Will daemonize"));
HAL_INFO (("Becoming a daemon"));
if (pipe (startup_daemonize_pipe) != 0) {
exit (1);
}
if (chdir ("/") < 0) {
exit (1);
}
switch (child_pid) {
case -1:
break;
case 0:
/* child */
if (dev_null_fd >= 0) {
dup2 (dev_null_fd, 0);
close (dev_null_fd);
}
umask (022);
break;
default:
/* parent, block until child writes */
break;
}
/* Create session */
setsid ();
/* remove old pid file */
/* Make a new one */
atexit (delete_pid);
}
} else {
HAL_INFO (("Will not daemonize"));
}
/* we need to do stuff when we are expected to terminate, thus
* this involves looking for SIGTERM; UNIX signal handlers are
* evil though, so set up a pipe to transmit the signal.
*/
/* create pipe */
if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
}
/* setup glib handler - 0 is for reading, 1 is for writing */
if (sigterm_iochn == NULL)
DIE (("Could not create GIOChannel"));
/* get callback when there is data to read */
/* Finally, setup unix signal handler for TERM */
/* set up the local dbus server */
if (!hald_dbus_local_server_init ())
return 1;
/* Start the runner helper daemon */
if (!hald_runner_start_runner ()) {
return 1;
}
drop_privileges(0);
/* initialize operating system specific parts */
osspec_init ();
/* detect devices */
osspec_probe ();
/* run the main loop and serve clients */
return 0;
}
#ifdef HALD_MEMLEAK_DBG
extern int dbg_hal_device_object_delta;
/* useful for valgrinding; see below */
static gboolean
{
gdl = hald_get_gdl ();
next:
hal_device_store_remove (gdl, d);
g_object_unref (d);
goto next;
}
exit (1);
}
#endif
void
osspec_probe_done (void)
{
HAL_INFO (("Device probing completed"));
if (!hald_dbus_init ()) {
exit (1);
}
/* tell parent to exit */
close (startup_daemonize_pipe[0]);
#ifdef HALD_MEMLEAK_DBG
NULL);
#endif
}
/** @} */