hal/hald Makefile.am, 1.52, 1.53 debug-hald.sh, 1.4, 1.5 hald.c, 1.45, 1.46 hald_dbus.c, 1.48, 1.49 hald_dbus.h, 1.10, 1.11 hald_runner.c, NONE, 1.1 hald_runner.h, NONE, 1.1 haldaemon.in, 1.6, 1.7 run-hald.sh, 1.7, 1.8 util.c, 1.34, 1.35 util.h, 1.15, 1.16 valgrind-hald.sh, 1.1, 1.2

David Zeuthen david at freedesktop.org
Fri Jan 20 18:45:29 PST 2006


Update of /cvs/hal/hal/hald
In directory gabe:/tmp/cvs-serv12741/hald

Modified Files:
	Makefile.am debug-hald.sh hald.c hald_dbus.c hald_dbus.h 
	haldaemon.in run-hald.sh util.c util.h valgrind-hald.sh 
Added Files:
	hald_runner.c hald_runner.h 
Log Message:
2006-01-20  David Zeuthen  <davidz at redhat.com>

	Great patch from Sjoerd Simons <sjoerd at luon.net>: As most people
	probably know by now, various people don't really like that hal
	running as root. We'd much rather see only a small process running
	as root and the main hal process running unpriviledged. Which is
	exactly what this patch does :)

	How does it work? Just before drops it's root privs. a small
	program is startup which will remain running as root and does the
	real execution of the addons/probes/callouts on hals
	behalf. Communication between hald and hald-runner is done via a
	p2p dbus connection. Resulting in a process tree like this:

	  hal       /usr/sbin/hald
	  root      \_ /usr/lib/hal/hald-runner
	  root          \_ /usr/lib/hal/hald-addon-acpi
	  root          \_ /usr/lib/hal/hald-addon-storage
	  root          \_ /usr/lib/hal/hald-addon-storage

	The patch consists out of two parts. First the implementation of
	hald-runner, which is about 700 lines of code. And then a part
	transforming the hald code from the current spawning code in utils
	to an interface that can talk to the runner.

	* AUTHORS: Add Sjoerd Simons <sjoerd at luon.net>. Revise my own
	email address.

	* configure.in (AC_OUTPUT): Add hald-runner

	* Makefile.am (SUBDIRS): Add hald-runner

	* hald/Makefile.am (hald_SOURCES): add hald_runner.[ch]

	* hald-runner/utils.c, hald-runner/utils.h, hald-runner/runner.c,
	hald-runner/runner.h, hald-runner/main.c, hald-runner/Makefile.am,
	hald/linux2/osspec.c, hald/linux2/classdev.c,
	hald/linux2/blockdev.c, hald/util.[ch], hald/hald_dbus.c,
	hald/hald.c, hald/hald_runner.[ch]: New and changed files with
	slight changes. See the descriptive text above and discussion at
	http://lists.freedesktop.org/archives/hal/2006-January/004327.html
	for details. 
	Changed function hald_runner_start_runner() in hald/hald_runner.c
	to print out runner path and improve error handling when runner
	is not found. Also removed dbus_server_unref (server) in 
	handle_connection() in same file.

	* hald/haldaemon.in: Remove --retain-privileges as this is no longer
	needed

	* hald/run-hald.sh, hald/debug-hald.sh, hald/valgrind-hald.sh:
	Remove --retain-privileges and use --with-runner pointing to
	../hald-runner/hald-runner



Index: Makefile.am
===================================================================
RCS file: /cvs/hal/hal/hald/Makefile.am,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- Makefile.am	29 Nov 2005 17:57:19 -0000	1.52
+++ Makefile.am	21 Jan 2006 02:45:26 -0000	1.53
@@ -40,6 +40,7 @@
 hald_SOURCES =                                                          \
 	hald_marshal.h			hald_marshal.c			\
 	util.h				util.c				\
+	hald_runner.h			hald_runner.c			\
 	device.h			device.c			\
 	device_info.h			device_info.c			\
 	device_store.h			device_store.c			\

Index: debug-hald.sh
===================================================================
RCS file: /cvs/hal/hal/hald/debug-hald.sh,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- debug-hald.sh	25 Feb 2005 04:52:23 -0000	1.4
+++ debug-hald.sh	21 Jan 2006 02:45:27 -0000	1.5
@@ -7,5 +7,5 @@
 echo ========================================
 echo Just type \'run\' to start debugging hald
 echo ========================================
-gdb run --args ./hald --daemon=no --verbose=yes --retain-privileges
+gdb run --args ./hald --daemon=no --verbose=yes --with-runner=../hald-runner/hald-runner
 

Index: hald.c
===================================================================
RCS file: /cvs/hal/hal/hald/hald.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- hald.c	12 Jan 2006 17:48:44 -0000	1.45
+++ hald.c	21 Jan 2006 02:45:27 -0000	1.46
@@ -55,6 +55,7 @@
 #include "osspec.h"
 #include "hald_dbus.h"
 #include "util.h"
+#include "hald_runner.h"
 
 static void delete_pid(void)
 {
@@ -71,15 +72,6 @@
 
 static HalDeviceStore *temporary_device_list = NULL;
 
-static GSList *running_addons = NULL;
-
-static void 
-addon_terminated (HalDevice *d, gboolean timed_out, gint return_code, 
-		  gpointer data1, gpointer data2, HalHelperData *helper_data)
-{
-	running_addons = g_slist_remove (running_addons, helper_data);
-}
-
 static void
 gdl_store_changed (HalDeviceStore *store, HalDevice *device,
 		   gboolean is_added, gpointer user_data)
@@ -94,45 +86,18 @@
 			
 			for (i = addons; i != NULL; i = g_slist_next (i)) {
 				const gchar *command_line;
-				HalHelperData *helper_data;
 				gchar *extra_env[2] = {"HALD_ACTION=addon", NULL};
 
 				command_line = (const gchar *) i->data;
-				helper_data = hal_util_helper_invoke (command_line, extra_env, device,
-								      NULL, NULL,
-								      addon_terminated, 0 /* no timeout */);
+				hald_runner_start (device, command_line, extra_env);
 
-				if (helper_data != NULL) {
-					HAL_INFO (("Invoked addon %s with pid %d for udi %s", 
-						   command_line, helper_data->pid, helper_data->d->udi));
-					running_addons = g_slist_prepend (running_addons, helper_data);
-				}
+				HAL_INFO (("Started addon %s for udi %s", 
+				           command_line, hal_device_get_udi(device)));
 			}
 		}
 	} else {
-		GSList *i;
-
 		HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
-
-	start_from_beginning:
-
-		/* may have several addons running */
-		for (i = running_addons; i != NULL; i = g_slist_next (i)) {
-			HalHelperData *helper_data;
-
-			helper_data = (HalHelperData *) (i->data);
-			if (helper_data->d == device) {
-				HAL_INFO (("Terminating addon with pid %d for udi %s", 
-					   helper_data->pid, helper_data->d->udi));
-				/* will force a callback - the callback removes us from the list */
-				hal_util_terminate_helper (helper_data);
-				/* TODO: is it safe to remove an elem from a GSList and keep iterating? 
-				 *       Better play it safe for now.
-				 */
-				goto start_from_beginning;
-			}
-		}
-		
+    hald_runner_kill_device(device);
 	}
 
 	/*hal_device_print (device);*/
@@ -207,7 +172,7 @@
 static void
 usage ()
 {
-	fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]\n");
+	fprintf (stderr, "\n" "usage : hald [--daemon=yes|no] [--verbose=yes|no] [--help]  [--with-runner=location]\n");
 	fprintf (stderr,
 		 "\n"
 		 "        --daemon=yes|no      Become a daemon\n"
@@ -215,8 +180,8 @@
  		 "        --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"
-		 "        --retain-privileges  Run as root instead of normal user (calling of\n"
- 		 "                             external scripts to modify fstab etc. will work)\n" 
+		 "        --with-runner        Use the program at the specified location as the\n"
+		                               "helper.\n"
 		 "        --help               Show this information and exit\n"
 		 "        --version            Output version information and exit"
 		 "\n"
@@ -261,7 +226,6 @@
 	GError *err = NULL;
 	gchar data[1];
 	gsize bytes_read;
-	unsigned int num_helpers;
 
 	/* Empty the pipe */
 	if (G_IO_STATUS_NORMAL != 
@@ -273,8 +237,7 @@
 	}
 
 	HAL_INFO (("Caught SIGTERM, initiating shutdown"));
-	num_helpers = hal_util_kill_all_helpers ();
-	HAL_INFO (("Killed %d helpers; exiting"));
+	hald_runner_kill_all();
 	exit (0);
 
 out:
@@ -404,12 +367,9 @@
 {
 	GMainLoop *loop;
 	guint sigterm_iochn_listener_source_id;
-	gboolean retain_privs;
 	char *path;
 	char newpath[512];
-
-	retain_privs = FALSE;
-  
+	char *runner_location = NULL;
 
 	openlog ("hald", LOG_PID, LOG_DAEMON);
 
@@ -443,7 +403,7 @@
 			{"verbose", 1, NULL, 0},
 			{"use-syslog", 0, NULL, 0},
 			{"help", 0, NULL, 0},
-			{"retain-privileges", 0, NULL, 0},
+			{"with-runner", 1, NULL, 0},
 			{"version", 0, NULL, 0},
 			{NULL, 0, NULL, 0}
 		};
@@ -481,8 +441,8 @@
 					usage ();
 					return 1;
 				}
-			} else if (strcmp (opt, "retain-privileges") == 0) {
-				retain_privs = TRUE;
+			} else if (strcmp (opt, "with-runner") == 0) {
+				runner_location = strdup(optarg);
 			} else if (strcmp (opt, "use-syslog") == 0) {
                                 hald_use_syslog = TRUE;
 			}
@@ -606,13 +566,16 @@
 	/* set up the local dbus server */
 	if (!hald_dbus_local_server_init ())
 		return 1;
+	/* Start the runner helper daemon */
+	if (!hald_runner_start_runner(runner_location)) {
+		return 1;
+	}
+
+	drop_privileges();
 
 	/* initialize operating system specific parts */
 	osspec_init ();
 
-	if (!retain_privs)
-		drop_privileges();
-
 	hald_is_initialising = TRUE;
 
 	/* detect devices */
@@ -659,7 +622,7 @@
 	HAL_INFO (("Device probing completed"));
 
 	if (!hald_dbus_init ()) {
-		hal_util_kill_all_helpers ();
+		hald_runner_kill_all();
 		exit (1);
 	}
 

Index: hald_dbus.c
===================================================================
RCS file: /cvs/hal/hal/hald/hald_dbus.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- hald_dbus.c	12 Jan 2006 17:48:44 -0000	1.48
+++ hald_dbus.c	21 Jan 2006 02:45:27 -0000	1.49
@@ -46,6 +46,7 @@
 #include "logger.h"
 #include "osspec.h"
 #include "util.h"
+#include "hald_runner.h"
 
 static DBusConnection *dbus_connection = NULL;
 
@@ -2482,55 +2483,35 @@
 }
 
 static void
-hald_exec_method_cb (HalDevice *d, gboolean timed_out, gint return_code, 
-		     gpointer data1, gpointer data2, HalHelperData *helper_data)
+hald_exec_method_cb (HalDevice *d, guint32 exit_type, 
+                    gint return_code, gchar **error,
+                    gpointer data1, gpointer data2)
 {
 	dbus_uint32_t result;
-	DBusMessage *reply;
+	DBusMessage *reply = NULL;
 	DBusMessage *message;
 	DBusMessageIter iter;
-	int *stderr_fd;
-	char buf[512]; /* TODO: don't hardcode error message size */
-	char *exp_name;
-	char *exp_detail;
-
 	message = (DBusMessage *) data1;
-	stderr_fd = (int *) data2;
-
-	exp_name = NULL;
-	exp_detail = NULL;
+  gchar *exp_name = NULL;
+  gchar *exp_detail = NULL;
 
-	/* read back possible error conditions from stderr */
-	if (stderr_fd != NULL) {
-		ssize_t num_read;
+	if (exit_type == HALD_RUN_SUCCESS && error != NULL) {
+    exp_name = error[0];
+    if (error[0] != NULL) {
+      exp_detail = error[1];
+    }
+    HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
+  }
 
-		num_read = read (*stderr_fd, buf, sizeof (buf) - 2);
-		buf[sizeof (buf) - 2] = '\0';
-		buf[sizeof (buf) - 1] = '\0';
-		if (num_read > 0) {
-			char *p;
-			char *s;
-			p = buf;
-			for (s = p; *s != '\n' && *s != '\0'; s++)
-				;
-			if (*s != '\0') {
-				exp_name = g_strndup (p, s - p);
-				p = s + 1;
-				for (s = p; *s != '\n' && *s != '\0'; s++)
-					;
-				if (*s != '\0') {
-					exp_detail = g_strndup (p, s - p);
-				}
-			}
+  if (exit_type != HALD_RUN_SUCCESS) {
+		reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
+		if (dbus_connection != NULL) {
+			if (!dbus_connection_send (dbus_connection, reply, NULL))
+				DIE (("No memory"));
 		}
-	}
-
-	if (exp_name != NULL && exp_detail != NULL) {
-		HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
-
-		/* throw exception */
-
-		reply = dbus_message_new_error (message, exp_name, exp_detail);
+		dbus_message_unref (reply);
+  } else if (exp_name != NULL && exp_detail != NULL) {
+    reply = dbus_message_new_error (message, exp_name, exp_detail);
 		if (reply == NULL) {
 			/* error name may be invalid - assume caller fucked up and use a generic HAL error name */
 			reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
@@ -2562,22 +2543,17 @@
 		dbus_message_unref (reply);
 	}
 
-	dbus_message_unref (message);
-	g_free (stderr_fd);
 	g_free (exp_name);
 	g_free (exp_detail);
+	dbus_message_unref (message);
 }
 
 static DBusHandlerResult
 hald_exec_method (HalDevice *d, DBusConnection *connection, DBusMessage *message, const char *execpath)
 {
 	int type;
-	char *stdin;
 	GString *stdin_str;
 	DBusMessageIter iter;
-	int stdin_fd;
-	int *stderr_fd;
-	ssize_t written;
 	const char *sender;
 	char *extra_env[2];
 	char uid_export[128];
@@ -2700,21 +2676,15 @@
 		dbus_message_iter_next (&iter);
 	}
 
-	stdin = g_string_free (stdin_str, FALSE);
-
-	stderr_fd = (int *) g_new0 (int, 1);
-
 	/* no timeout */
-	if (hal_util_helper_invoke_with_pipes (execpath, extra_env, d, 
-					       (gpointer) message, (gpointer) stderr_fd, 
-					       hald_exec_method_cb, 0, &stdin_fd, NULL, stderr_fd) != NULL) {
-		written = write (stdin_fd, stdin, strlen (stdin));
-		close (stdin_fd);
-	}
-
+	hald_runner_run_method(d, 
+                         execpath, extra_env, 
+                         stdin_str->str, TRUE,
+                         0,
+                         hald_exec_method_cb,
+                         (gpointer) message, NULL);
 	dbus_message_ref (message);
-
-	g_free (stdin);
+	g_string_free (stdin_str, TRUE);
 
 	return DBUS_HANDLER_RESULT_HANDLED;
 

Index: hald_dbus.h
===================================================================
RCS file: /cvs/hal/hal/hald/hald_dbus.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- hald_dbus.h	2 Nov 2005 15:38:13 -0000	1.10
+++ hald_dbus.h	21 Jan 2006 02:45:27 -0000	1.11
@@ -94,6 +94,4 @@
 DBusHandlerResult hald_dbus_filter_function (DBusConnection * connection, DBusMessage * message, void *user_data);
 
 char *hald_dbus_local_server_addr (void);
-
-
 #endif /* HAL_DBUS_H */

--- NEW FILE: hald_runner.c ---
/***************************************************************************
 * CVSID: $Id: hald_runner.c,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * hald_runner.c - Interface to the hal runner helper daemon
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * 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 <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>

#include "hald.h"
#include "util.h"
#include "logger.h"
#include "hald_dbus.h"
#include "hald_runner.h"

typedef struct {
  HalDevice *d;
  HalRunTerminatedCB cb;
  gpointer data1;
  gpointer data2;
} HelperData;

#define DBUS_SERVER_ADDRESS "unix:tmpdir=/tmp/hald-runner" 

static DBusConnection *runner_connection = NULL;

static void 
handle_connection(DBusServer *server,
                  DBusConnection *new_connection,
                  void *data) {

  if (runner_connection == NULL) {
    runner_connection = new_connection;
    dbus_connection_ref (new_connection);
    dbus_connection_setup_with_g_main (new_connection, NULL);
    /* dbus_server_unref(server); */
  }
}

static void
runner_died(GPid pid, gint status, gpointer data) {
  g_spawn_close_pid (pid);
  DIE (("Runner died"));
}

gboolean
hald_runner_start_runner(gchar *runner_location) {
  DBusServer *server = NULL;
  DBusError err;
  GError *error = NULL;
  GPid pid;
  char *argv[] = { NULL, NULL};
  char *env[] =  { NULL, NULL};

  dbus_error_init(&err);
  server = dbus_server_listen(DBUS_SERVER_ADDRESS, &err);
  if (server == NULL) {
    HAL_ERROR (("Cannot create D-BUS server for the runner"));
    goto error;
  }

  dbus_server_setup_with_g_main(server, NULL);
  dbus_server_set_new_connection_function(server, handle_connection, 
                                          NULL, NULL);
  if (runner_location == NULL) {
    runner_location = g_strdup_printf("%s/hald-runner", PACKAGE_LIBEXEC_DIR);
  } else {
    runner_location = g_strdup(runner_location);
  }
  HAL_INFO (("Using runner '%s'\n", runner_location));
  argv[0] = runner_location;
  env[0] = g_strdup_printf("HALD_RUNNER_DBUS_ADDRESS=%s",
             dbus_server_get_address(server));

  if (!g_spawn_async(NULL, argv, env, G_SPAWN_DO_NOT_REAP_CHILD, 
        NULL, NULL, &pid, &error)) {
    HAL_ERROR (("Could not spawn runner : '%s'", error->message));
    g_error_free (error);
    goto error;
  }
  g_free(argv[0]);
  g_free(env[0]);

  g_child_watch_add(pid, runner_died, NULL);
  while (runner_connection == NULL) {
    /* Wait for the runner */
    g_main_context_iteration(NULL, TRUE);
  }
  return TRUE;

error:
  if (server != NULL)
    dbus_server_unref(server);
  return FALSE;
}

static gboolean
add_property_to_msg (HalDevice *device, HalProperty *property, 
                                     gpointer user_data)
{
  char *prop_upper, *value;
  char *c;
  gchar *env;
  DBusMessageIter *iter = (DBusMessageIter *)user_data;
  
  prop_upper = g_ascii_strup (hal_property_get_key (property), -1);
 
  /* periods aren't valid in the environment, so replace them with
   * underscores. */
  for (c = prop_upper; *c; c++) {
    if (*c == '.')
      *c = '_';
  }

  value = hal_property_to_string (property);
  env = g_strdup_printf ("HAL_PROP_%s=%s", prop_upper, value);
  dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env);

  g_free(env);
  g_free (value);
  g_free (prop_upper);

  return TRUE;
}

static void
add_env(DBusMessageIter *iter, const gchar *key, const gchar *value) {
  gchar *env;
  env = g_strdup_printf ("%s=%s", key, value);
  dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env);
  g_free(env);
}

static void
add_basic_env(DBusMessageIter *iter, const gchar *udi) {
  if (hald_is_verbose) {
    add_env(iter, "HALD_VERBOSE", "1");
  }
  if (hald_is_initialising) {
    add_env(iter, "HALD_STARTUP", "1");
  }
  add_env(iter, "UDI", udi);
  add_env(iter, "HALD_DIRECT_ADDR", hald_dbus_local_server_addr());
}

static void
add_extra_env(DBusMessageIter *iter, gchar **env) {
  int i;
  if (env != NULL) for (i = 0; env[i] != NULL; i++) {
    dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env[i]);
  }
}

static gboolean
add_command(DBusMessageIter *iter, const gchar *command_line) {
  gint argc;
  gint x;
  char **argv;
  GError *err = NULL;
  DBusMessageIter array_iter;

  if (!g_shell_parse_argv(command_line, &argc, &argv, &err)) {
    HAL_ERROR (("Error parsing commandline '%s': %s", 
                 command_line, err->message));
    g_error_free (err);
    return FALSE;
  }
  if (!dbus_message_iter_open_container(iter, 
                                   DBUS_TYPE_ARRAY,
                                   DBUS_TYPE_STRING_AS_STRING,
                                   &array_iter))
    DIE (("No memory"));
  for (x = 0 ; argv[x] != NULL; x++) {
    dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &argv[x]);
  }
  dbus_message_iter_close_container(iter, &array_iter);

  g_strfreev(argv);
  return TRUE;
}

static gboolean
add_first_part(DBusMessageIter *iter, HalDevice *device,
                   const gchar *command_line, char **extra_env) {
  DBusMessageIter array_iter;
  const char *udi;

  udi = hal_device_get_udi(device);
  dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &udi);

  dbus_message_iter_open_container(iter, 
                                   DBUS_TYPE_ARRAY,
                                   DBUS_TYPE_STRING_AS_STRING,
                                   &array_iter);
  hal_device_property_foreach (device, add_property_to_msg, &array_iter);
  add_basic_env(&array_iter, udi);
  add_extra_env(&array_iter, extra_env);
  dbus_message_iter_close_container(iter, &array_iter);

  if (!add_command(iter, command_line)) {
    return FALSE;
  }
  return TRUE;
}

/* Start a helper, returns true on a successfull start */
gboolean
hald_runner_start(HalDevice *device,
                      const gchar *command_line, char **extra_env) {
  DBusMessage *msg, *reply;
  DBusError err;
  DBusMessageIter iter;

  dbus_error_init(&err);
  msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                                     "/org/freedesktop/HalRunner",
                                     "org.freedesktop.HalRunner",
                                     "Start");
  if (msg == NULL) 
    DIE(("No memory"));
  dbus_message_iter_init_append(msg, &iter);

  if (!add_first_part(&iter, device, command_line, extra_env)) 
    goto error;
 
  /* Wait for the reply, should be almost instantanious */
  reply = 
    dbus_connection_send_with_reply_and_block(runner_connection, 
                                              msg, -1, &err);
  if (reply) {
    gboolean ret = 
      (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN);
    dbus_message_unref(reply);
    dbus_message_unref(msg);
    return ret;
  }

error:
  dbus_message_unref(msg);
  return FALSE;
}

static void
call_notify(DBusPendingCall *pending, void *user_data) {
  HelperData *hb = (HelperData *)user_data;
  dbus_uint32_t exitt = HALD_RUN_SUCCESS;
  dbus_int32_t return_code = 0;
  DBusMessage *m;
  GArray *error = NULL;
  DBusMessageIter iter;

  error = g_array_new(TRUE, FALSE, sizeof(char *));

  m = dbus_pending_call_steal_reply(pending);
  if (dbus_message_get_type(m) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
    goto malformed;

  if (!dbus_message_iter_init(m, &iter) ||
       dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) 
    goto malformed;
  dbus_message_iter_get_basic(&iter, &exitt);

  if (!dbus_message_iter_next(&iter) || 
        dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) 
    goto malformed;
  dbus_message_iter_get_basic(&iter, &return_code);

  while (dbus_message_iter_next(&iter) &&
    dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
    const char *value;
    dbus_message_iter_get_basic(&iter, &value);
    g_array_append_vals(error, &value, 1);
  }

  hb->cb(hb->d, exitt, return_code, 
      (gchar **)error->data, hb->data1, hb->data2);

  dbus_message_unref(m);
  g_array_free(error, FALSE);

  return;
malformed:
  /* Send a Fail callback on malformed messages */
  HAL_ERROR (("Malformed or unexpected reply message"));
  hb->cb(hb->d, HALD_RUN_FAILED, return_code, NULL, hb->data1, hb->data2);
  dbus_message_unref(m);
  g_array_free(error, FALSE);
}

/* Run a helper program using the commandline, with input as infomation on
 * stdin */
void
hald_runner_run_method(HalDevice *device,
                           const gchar *command_line, char **extra_env, 
                           gchar *input, gboolean error_on_stderr,
                           guint32 timeout,
                           HalRunTerminatedCB  cb,
                           gpointer data1, gpointer data2) {
  DBusMessage *msg;
  DBusMessageIter iter;
  DBusPendingCall *call;
  HelperData *hd = NULL;
  msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                             "/org/freedesktop/HalRunner",
                             "org.freedesktop.HalRunner",
                             "Run");
  if (msg == NULL) 
    DIE(("No memory"));
  dbus_message_iter_init_append(msg, &iter);
  
  if (!add_first_part(&iter, device, command_line, extra_env)) 
    goto error;

  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &input);
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &error_on_stderr);
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &timeout);

  if (!dbus_connection_send_with_reply(runner_connection, 
                                              msg, &call, INT_MAX))
    DIE (("No memory"));

  hd = malloc(sizeof(HelperData));
  hd->d = device;
  hd->cb = cb;
  hd->data1 = data1;
  hd->data2 = data2;

  dbus_pending_call_set_notify(call, call_notify, hd, free);
  dbus_message_unref(msg);
  return;
error:
  dbus_message_unref(msg);
  free(hd);
  cb(device, HALD_RUN_FAILED, 0, NULL, data1, data2);
}

void
hald_runner_run(HalDevice *device,
                    const gchar *command_line, char **extra_env, 
                    guint timeout,
                    HalRunTerminatedCB  cb,
                    gpointer data1, gpointer data2) {
  hald_runner_run_method(device, command_line, extra_env, 
                             "", FALSE, timeout, cb, data1, data2);
}

void
hald_runner_kill_device(HalDevice *device) {
  DBusMessage *msg, *reply;
  DBusError err;
  DBusMessageIter iter;
  const char *udi;
  
  msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                             "/org/freedesktop/HalRunner",
                             "org.freedesktop.HalRunner",
                             "Kill");
  if (msg == NULL) 
    DIE(("No memory"));
  dbus_message_iter_init_append(msg, &iter);
  udi = hal_device_get_udi(device);
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &udi);

  /* Wait for the reply, should be almost instantanious */
  dbus_error_init(&err);
  reply = 
    dbus_connection_send_with_reply_and_block(runner_connection, msg, -1, &err);
  if (reply) {
    dbus_message_unref(reply);
  }

  dbus_message_unref(msg);
}

void
hald_runner_kill_all(HalDevice *device) {
  DBusMessage *msg, *reply;
  DBusError err;
  msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
                             "/org/freedesktop/HalRunner",
                             "org.freedesktop.HalRunner",
                             "KillAll");
  if (msg == NULL) 
    DIE(("No memory"));

  /* Wait for the reply, should be almost instantanious */
  dbus_error_init(&err);
  reply = 
    dbus_connection_send_with_reply_and_block(runner_connection,
                                              msg, -1, &err);
  if (reply) {
    dbus_message_unref(reply);
  }

  dbus_message_unref(msg);
}

--- NEW FILE: hald_runner.h ---
/***************************************************************************
 *
 * CVSID: $Id: hald_runner.h,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * hald_runner.h - Interface to the hal runner helper daemon
 *
 * Copyright (C) 2006 Sjoerd Simons <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * 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
 *
 **************************************************************************/

#ifndef HALD_RUNNER_H
#define HALD_RUNNER_H

#include "device.h"

/* Successful run of the program */
#define HALD_RUN_SUCCESS 0x0 
/* Process was killed because of running too long */
#define  HALD_RUN_TIMEOUT 0x1 
/* Failed to start for some reason */
#define HALD_RUN_FAILED 0x2
/* Killed on purpose, e.g. hal_runner_kill_device */   
#define HALD_RUN_KILLED 0x4

/* Default sane timeout */
#define HAL_HELPER_TIMEOUT 10000

typedef void (*HalRunTerminatedCB) (HalDevice *d, guint32 exit_type, 
                                       gint return_code, gchar **error,
                                       gpointer data1, gpointer data2);

/* Start the runner daemon */
gboolean
hald_runner_start_runner(gchar *runner_location);

/* Start a helper, returns true on a successfull start */
gboolean
hald_runner_start(HalDevice *device, const gchar *command_line, 
                  char **extra_env);

/* Run a helper program using the commandline, with input as infomation on
 * stdin */
void
hald_runner_run(HalDevice *device,
               const gchar *command_line, char **extra_env, 
               guint32 timeout,
               HalRunTerminatedCB cb,
               gpointer data1, gpointer data2);
void
hald_runner_run_method(HalDevice *device,                                                              
		       const gchar *command_line, char **extra_env, 
                       gchar *input, gboolean error_on_stderr,
                       guint32 timeout,
                       HalRunTerminatedCB  cb,
                       gpointer data1, gpointer data2);

void hald_runner_kill_device(HalDevice *device);
void hald_runner_kill_all();

#endif 

Index: haldaemon.in
===================================================================
RCS file: /cvs/hal/hal/hald/haldaemon.in,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- haldaemon.in	25 Feb 2005 01:55:08 -0000	1.6
+++ haldaemon.in	21 Jan 2006 02:45:27 -0000	1.7
@@ -25,7 +25,7 @@
 
 start() {
     echo -n $"Starting HAL daemon: "
-    daemon --check $servicename $processname --retain-privileges
+    daemon --check $servicename $processname
     RETVAL=$?
     echo
     [ $RETVAL -eq 0 ] && touch @LOCALSTATEDIR@/lock/subsys/$servicename

Index: run-hald.sh
===================================================================
RCS file: /cvs/hal/hal/hald/run-hald.sh,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- run-hald.sh	25 Feb 2005 04:52:23 -0000	1.7
+++ run-hald.sh	21 Jan 2006 02:45:27 -0000	1.8
@@ -4,6 +4,6 @@
 export HAL_FDI_SOURCE_PREPROBE=../fdi/preprobe
 export HAL_FDI_SOURCE_INFORMATION=../fdi/information
 export HAL_FDI_SOURCE_POLICY=../fdi/policy
-./hald --daemon=no --verbose=yes --retain-privileges
-#./hald --daemon=no --retain-privileges
+./hald --daemon=no --verbose=yes --with-runner=../hald-runner/hald-runner
+#./hald --daemon=no --with-runner=../hald-runner/hald-runner
 

Index: util.c
===================================================================
RCS file: /cvs/hal/hal/hald/util.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- util.c	29 Nov 2005 17:38:00 -0000	1.34
+++ util.c	21 Jan 2006 02:45:27 -0000	1.35
@@ -50,6 +50,7 @@
 
 #include "hald_dbus.h"
 #include "util.h"
+#include "hald_runner.h"
 
 typedef struct {
 	int last_level;
@@ -534,235 +535,6 @@
 	;
 }
 
-void
-hal_util_terminate_helper (HalHelperData *ed)
-{
-	if (ed->already_issued_kill) {
-		HAL_INFO (("Already issued SIGTERM for pid %d, udi %s",
-			   ed->pid, ed->d != NULL ? ed->d->udi : "(finalized object)"));
-		goto out;
-	}
-
-	HAL_INFO (("killing %d for udi %s", ed->pid, ed->d != NULL ? ed->d->udi : "(finalized object)"));
-
-	/* kill kenny! kill it!! */
-	ed->already_issued_kill = TRUE;
-	kill (ed->pid, SIGTERM);
-
-	if (ed->timeout_watch_id != (guint) -1) {
-		g_source_remove (ed->timeout_watch_id);
-		ed->timeout_watch_id = -1;
-	}
-
-	if (!ed->already_issued_callback) {
-		ed->already_issued_callback = TRUE;
-		ed->cb (ed->d, TRUE, -1, ed->data1, ed->data2, ed);
-	}
-
-	/* ed will be cleaned up when helper_child_exited reaps the child */
-out:
-	;
-}
-
-static gboolean
-helper_child_timeout (gpointer data)
-{
-	HalHelperData *ed = (HalHelperData *) data;
-
-	HAL_INFO (("child timeout for pid %d", ed->pid));
-
-	/* kill kenny! kill it!! */
-	ed->already_issued_kill = TRUE;
-	kill (ed->pid, SIGTERM);
-
-	ed->timeout_watch_id = -1;
-
-	if (!ed->already_issued_callback) {
-		ed->already_issued_callback = TRUE;
-		ed->cb (ed->d, TRUE, -1, ed->data1, ed->data2, ed);
-	}
-
-	/* ed will be cleaned up when helper_child_exited reaps the child */
-	return FALSE;
-}
-
-static GSList *running_helpers = NULL;
-
-static void 
-helper_device_object_finalized (gpointer data, GObject *where_the_object_was)
-{
-	HalHelperData *ed = (HalHelperData *) data;
-
-	HAL_INFO (("device object finalized for helper with pid %d", ed->pid));
-
-	ed->d = NULL;
-	hal_util_terminate_helper (ed);
-}
-
-static void 
-helper_child_exited (GPid pid, gint status, gpointer data)
-{
-	HalHelperData *ed = (HalHelperData *) data;
-
-	HAL_INFO (("child exited for pid %d", pid));
-
-	if (ed->timeout_watch_id != (guint) -1)
-		g_source_remove (ed->timeout_watch_id);
-	g_spawn_close_pid (ed->pid);
-
-	if (ed->d != NULL)
-		g_object_weak_unref (G_OBJECT (ed->d), helper_device_object_finalized, ed);
-
-	if (!ed->already_issued_callback)
-		ed->cb (ed->d, FALSE, WEXITSTATUS (status), ed->data1, ed->data2, ed);
-
-	running_helpers = g_slist_remove (running_helpers, ed);
-
-	g_free (ed);
-}
-
-static gboolean
-helper_add_property_to_env (HalDevice *device, HalProperty *property, gpointer user_data)
-{
-	char *prop_upper, *value;
-	char *c;
-	gchar ***ienvp = (gchar ***) user_data;
-	gchar **envp;
-
-	envp = *ienvp;
-	*ienvp = *ienvp + 1;
-
-	prop_upper = g_ascii_strup (hal_property_get_key (property), -1);
-	
-	/* periods aren't valid in the environment, so replace them with
-	 * underscores. */
-	for (c = prop_upper; *c; c++) {
-		if (*c == '.')
-			*c = '_';
-	}
-	
-	value = hal_property_to_string (property);
-	
-	*envp = g_strdup_printf ("HAL_PROP_%s=%s", prop_upper, value);
-
-	g_free (value);
-	g_free (prop_upper);
-
-	return TRUE;
-}
-
-static void
-callout_failed (HalHelperData *ed);
-
-HalHelperData *
-hal_util_helper_invoke (const gchar *command_line, gchar **extra_env, HalDevice *d, 
-			gpointer data1, gpointer data2, HalHelperTerminatedCB cb, guint timeout)
-{
-	return hal_util_helper_invoke_with_pipes (command_line, extra_env, d, data1, data2, cb, timeout, NULL, NULL, NULL);
-}
-
-HalHelperData *
-hal_util_helper_invoke_with_pipes (const gchar *command_line, gchar **extra_env, HalDevice *d, 
-				   gpointer data1, gpointer data2, HalHelperTerminatedCB cb, guint timeout,
-				   int *standard_input, int *standard_output, int *standard_error)
-{
-	HalHelperData *ed;
-	gint argc;
-	gchar **argv;
-	gchar **envp;
-	gchar **ienvp;
-	GError *err = NULL;
-	guint num_env_vars;
-	guint i, j;
-	guint num_properties;
-	guint num_extras;
-	char *local_addr;
-
-	ed = g_new0 (HalHelperData, 1);
-	ed->data1 = data1;
-	ed->data2 = data2;
-	ed->d = d;
-	ed->cb = cb;
-	ed->already_issued_callback = FALSE;
-	ed->already_issued_kill = FALSE;
-
-	num_properties = hal_device_num_properties (d);
-	if (extra_env == NULL)
-		num_extras = 0;
-	else
-		num_extras = g_strv_length ((gchar **) extra_env);
-	num_env_vars = num_properties + 2 + num_extras;
-	if (hald_is_verbose)
-		num_env_vars++;
-	if (hald_is_initialising)
-		num_env_vars++;
-	if ((local_addr = hald_dbus_local_server_addr ()) != NULL)
-		num_env_vars++;
-
-	envp = g_new (char *, num_env_vars);
-	ienvp = envp;
-	hal_device_property_foreach (d, helper_add_property_to_env, &ienvp);
-	i = num_properties;
-	envp[i++] = g_strdup_printf ("UDI=%s", hal_device_get_udi (d));
-	if (hald_is_verbose)
-		envp[i++] = g_strdup ("HALD_VERBOSE=1");
-	if (hald_is_initialising)
-		envp[i++] = g_strdup ("HALD_STARTUP=1");
-	if (local_addr != NULL)
-		envp[i++] = g_strdup_printf ("HALD_DIRECT_ADDR=%s", local_addr);
-	for (j = 0; j < num_extras; j++) {
-		envp[i++] = g_strdup (extra_env[j]);
-	}
-	envp[i++] = NULL;
-
-	err = NULL;
-	if (!g_shell_parse_argv (command_line, &argc, &argv, &err)) {
-		HAL_ERROR (("Error parsing commandline '%s': %s", command_line, err->message));
-		g_error_free (err);
-		g_free (ed);
-		ed = NULL;
-	} else {
-		err = NULL;
-		if (!g_spawn_async_with_pipes (NULL, 
-					       argv, 
-					       envp, 
-					       G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
-					       NULL,
-					       NULL,
-					       &ed->pid,
-					       standard_input,
-					       standard_output,
-					       standard_error,
-					       &err)) {
-			HAL_ERROR (("Couldn't spawn '%s' err=%s!", command_line, err->message));
-			g_error_free (err);
-
-			/* move ahead in list */
-			callout_failed(ed);
-
-			g_free (ed);
-			ed = NULL;
-		} else {
-			ed->child_watch_id = g_child_watch_add (ed->pid, helper_child_exited, (gpointer) ed);
-			if (timeout > 0)
-				ed->timeout_watch_id = g_timeout_add (timeout, helper_child_timeout, (gpointer) ed);
-			else
-				ed->timeout_watch_id = (guint) -1;
-
-			running_helpers = g_slist_prepend (running_helpers, ed);
-			/* device object may disappear from underneath us - this is
-			 * used to terminate the helper and pass d=NULL in the
-			 * HalHelperTerminatedCB callback
-			 */
-			g_object_weak_ref (G_OBJECT (d), helper_device_object_finalized, ed);
-		}
-	}
-
-	g_strfreev (envp);
-	g_free (argv);
-
-	return ed;
-}
 
 gboolean
 hal_util_path_ascend (gchar *path)
@@ -1127,21 +899,10 @@
 
 static void callout_do_next (Callout *c);
 
-static void
-callout_failed (HalHelperData *ed)
-{
-	if (ed->data1 != NULL) {
-		Callout *c;
-		c = (Callout *) ed->data1;
-
-		c->next_program++;
-		callout_do_next(c);
-	}
-}
-
 static void 
-callout_terminated (HalDevice *d, gboolean timed_out, gint return_code, 
-		    gpointer data1, gpointer data2, HalHelperData *helper_data)
+callout_terminated (HalDevice *d, guint32 exit_type, 
+                   gint return_code, gchar **error, 
+                   gpointer data1, gpointer data2)
 {
 	Callout *c;
 
@@ -1172,8 +933,9 @@
 		callback (d, userdata1, userdata2);
 
 	} else {
-		hal_util_helper_invoke (c->programs[c->next_program], c->extra_env, c->d, 
-					(gpointer) c, NULL, callout_terminated, HAL_HELPER_TIMEOUT);
+    hald_runner_run(c->d, c->programs[c->next_program], c->extra_env,
+                    HAL_HELPER_TIMEOUT, callout_terminated,
+                    (gpointer)c, NULL);
 		c->next_program++;
 	}
 }
@@ -1250,29 +1012,6 @@
 	;
 }
 
-/** Kill all helpers we have running; useful when exiting hald.
- *
- *  @return                     Number of childs killed
- */
-unsigned int 
-hal_util_kill_all_helpers (void)
-{
-	unsigned int n;
-	GSList *i;
-
-	n = 0;
-	for (i = running_helpers; i != NULL; i = i->next) {
-		HalHelperData *ed;
-
-		ed = i->data;
-		HAL_INFO (("Killing helper with pid %d", ed->pid));
-		kill (ed->pid, SIGTERM);
-		n++;
-	}
-
-	return n;
-}
-
 void
 hal_util_hexdump (const void *mem, unsigned int size)
 {

Index: util.h
===================================================================
RCS file: /cvs/hal/hal/hald/util.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- util.h	9 Nov 2005 20:45:44 -0000	1.15
+++ util.h	21 Jan 2006 02:45:27 -0000	1.16
@@ -81,38 +81,6 @@
 					   const gchar *linestart, guint elem, const gchar *expected, 
 					   gboolean reuse_file);
 
-struct HalHelperData_s;
-typedef struct HalHelperData_s HalHelperData;
-
-typedef void (*HalHelperTerminatedCB) (HalDevice *d, gboolean timed_out, gint return_code, 
-				       gpointer data1, gpointer data2, HalHelperData *helper_data);
-
-struct HalHelperData_s
-{
-	GPid pid;
-	guint timeout_watch_id;
-	guint child_watch_id;
-	HalHelperTerminatedCB cb;
-	gpointer data1;
-	gpointer data2;
-	HalDevice *d;
-
-	gboolean already_issued_callback;
-	gboolean already_issued_kill;
-};
-
-unsigned int hal_util_kill_all_helpers (void);
-
-HalHelperData  *hal_util_helper_invoke (const gchar *command_line, gchar **extra_env, HalDevice *d, 
-					gpointer data1, gpointer data2, HalHelperTerminatedCB cb, guint timeout);
-
-HalHelperData  *hal_util_helper_invoke_with_pipes (const gchar *command_line, gchar **extra_env, HalDevice *d, 
-						   gpointer data1, gpointer data2, HalHelperTerminatedCB cb, 
-						   guint timeout,
-						   int *standard_input, int *standard_output, int *standard_error);
-
-void hal_util_terminate_helper (HalHelperData *helper_data);
-
 gchar **hal_util_dup_strv_from_g_slist (GSList *strlist);
 
 typedef void (*HalCalloutsDone) (HalDevice *d, gpointer userdata1, gpointer userdata2);

Index: valgrind-hald.sh
===================================================================
RCS file: /cvs/hal/hal/hald/valgrind-hald.sh,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- valgrind-hald.sh	28 Feb 2005 04:53:15 -0000	1.1
+++ valgrind-hald.sh	21 Jan 2006 02:45:27 -0000	1.2
@@ -4,4 +4,4 @@
 export HAL_FDI_SOURCE_PREPROBE=../fdi/preprobe
 export HAL_FDI_SOURCE_INFORMATION=../fdi/information
 export HAL_FDI_SOURCE_POLICY=../fdi/policy
-valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./hald --daemon=no --verbose=yes --retain-privileges
+valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./hald --daemon=no --verbose=yes --with-runner=../hald-runner/hald-runner




More information about the hal-commit mailing list