1*2912Sartem /***************************************************************************
2*2912Sartem  * CVSID: $Id$
3*2912Sartem  *
4*2912Sartem  * hald_runner.c - Interface to the hal runner helper daemon
5*2912Sartem  *
6*2912Sartem  * Copyright (C) 2006 Sjoerd Simons, <sjoerd@luon.net>
7*2912Sartem  *
8*2912Sartem  * Licensed under the Academic Free License version 2.1
9*2912Sartem  *
10*2912Sartem  * This program is free software; you can redistribute it and/or modify
11*2912Sartem  * it under the terms of the GNU General Public License as published by
12*2912Sartem  * the Free Software Foundation; either version 2 of the License, or
13*2912Sartem  * (at your option) any later version.
14*2912Sartem  *
15*2912Sartem  * This program is distributed in the hope that it will be useful,
16*2912Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*2912Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*2912Sartem  * GNU General Public License for more details.
19*2912Sartem  *
20*2912Sartem  * You should have received a copy of the GNU General Public License
21*2912Sartem  * along with this program; if not, write to the Free Software
22*2912Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23*2912Sartem  *
24*2912Sartem  **************************************************************************/
25*2912Sartem 
26*2912Sartem #ifdef HAVE_CONFIG_H
27*2912Sartem #  include <config.h>
28*2912Sartem #endif
29*2912Sartem 
30*2912Sartem #include <sys/utsname.h>
31*2912Sartem #include <stdio.h>
32*2912Sartem 
33*2912Sartem #include <glib.h>
34*2912Sartem #include <dbus/dbus.h>
35*2912Sartem #include <dbus/dbus-glib-lowlevel.h>
36*2912Sartem 
37*2912Sartem #include "hald.h"
38*2912Sartem #include "util.h"
39*2912Sartem #include "logger.h"
40*2912Sartem #include "hald_dbus.h"
41*2912Sartem #include "hald_runner.h"
42*2912Sartem 
43*2912Sartem typedef struct {
44*2912Sartem   HalDevice *d;
45*2912Sartem   HalRunTerminatedCB cb;
46*2912Sartem   gpointer data1;
47*2912Sartem   gpointer data2;
48*2912Sartem } HelperData;
49*2912Sartem 
50*2912Sartem #define DBUS_SERVER_ADDRESS "unix:tmpdir=" HALD_SOCKET_DIR
51*2912Sartem 
52*2912Sartem static DBusConnection *runner_connection = NULL;
53*2912Sartem 
54*2912Sartem typedef struct
55*2912Sartem {
56*2912Sartem 	GPid pid;
57*2912Sartem 	HalDevice *device;
58*2912Sartem 	HalRunTerminatedCB cb;
59*2912Sartem 	gpointer data1;
60*2912Sartem 	gpointer data2;
61*2912Sartem } RunningProcess;
62*2912Sartem 
63*2912Sartem /* mapping from PID to RunningProcess */
64*2912Sartem static GHashTable *running_processes;
65*2912Sartem 
66*2912Sartem static gboolean
67*2912Sartem rprd_foreach (gpointer key,
68*2912Sartem 	      gpointer value,
69*2912Sartem 	      gpointer user_data)
70*2912Sartem {
71*2912Sartem 	gboolean remove = FALSE;
72*2912Sartem 	RunningProcess *rp = value;
73*2912Sartem 	HalDevice *device = user_data;
74*2912Sartem 
75*2912Sartem 	if (rp->device == device) {
76*2912Sartem 		remove = TRUE;
77*2912Sartem 		g_free (rp);
78*2912Sartem 	}
79*2912Sartem 
80*2912Sartem 	return remove;
81*2912Sartem }
82*2912Sartem 
83*2912Sartem static void
84*2912Sartem running_processes_remove_device (HalDevice *device)
85*2912Sartem {
86*2912Sartem 	g_hash_table_foreach_remove (running_processes, rprd_foreach, device);
87*2912Sartem }
88*2912Sartem 
89*2912Sartem void
90*2912Sartem runner_device_finalized (HalDevice *device)
91*2912Sartem {
92*2912Sartem 	running_processes_remove_device (device);
93*2912Sartem }
94*2912Sartem 
95*2912Sartem 
96*2912Sartem static DBusHandlerResult
97*2912Sartem runner_server_message_handler (DBusConnection *connection,
98*2912Sartem 			       DBusMessage *message,
99*2912Sartem 			       void *user_data)
100*2912Sartem {
101*2912Sartem 
102*2912Sartem 	/*HAL_INFO (("runner_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
103*2912Sartem 		   dbus_message_get_destination (message),
104*2912Sartem 		   dbus_message_get_path (message),
105*2912Sartem 		   dbus_message_get_interface (message),
106*2912Sartem 		   dbus_message_get_member (message)));*/
107*2912Sartem 	if (dbus_message_is_signal (message,
108*2912Sartem 				    "org.freedesktop.HalRunner",
109*2912Sartem 				    "StartedProcessExited")) {
110*2912Sartem 		dbus_uint64_t dpid;
111*2912Sartem 		DBusError error;
112*2912Sartem 		dbus_error_init (&error);
113*2912Sartem 		if (dbus_message_get_args (message, &error,
114*2912Sartem 					   DBUS_TYPE_INT64, &dpid,
115*2912Sartem 					   DBUS_TYPE_INVALID)) {
116*2912Sartem 			RunningProcess *rp;
117*2912Sartem 			GPid pid;
118*2912Sartem 
119*2912Sartem 			pid = (GPid) dpid;
120*2912Sartem 
121*2912Sartem 			/*HAL_INFO (("Previously started process with pid %d exited", pid));*/
122*2912Sartem 			rp = g_hash_table_lookup (running_processes, (gpointer) pid);
123*2912Sartem 			if (rp != NULL) {
124*2912Sartem 				rp->cb (rp->device, 0, 0, NULL, rp->data1, rp->data2);
125*2912Sartem 				g_hash_table_remove (running_processes, (gpointer) pid);
126*2912Sartem 				g_free (rp);
127*2912Sartem 			}
128*2912Sartem 		}
129*2912Sartem 	}
130*2912Sartem 	return DBUS_HANDLER_RESULT_HANDLED;
131*2912Sartem }
132*2912Sartem 
133*2912Sartem static void
134*2912Sartem runner_server_unregister_handler (DBusConnection *connection, void *user_data)
135*2912Sartem {
136*2912Sartem 	HAL_INFO (("unregistered"));
137*2912Sartem }
138*2912Sartem 
139*2912Sartem 
140*2912Sartem static void
141*2912Sartem handle_connection(DBusServer *server,
142*2912Sartem                   DBusConnection *new_connection,
143*2912Sartem                   void *data)
144*2912Sartem {
145*2912Sartem 
146*2912Sartem 	if (runner_connection == NULL) {
147*2912Sartem 		DBusObjectPathVTable vtable = { &runner_server_unregister_handler,
148*2912Sartem 						&runner_server_message_handler,
149*2912Sartem 						NULL, NULL, NULL, NULL};
150*2912Sartem 
151*2912Sartem 		runner_connection = new_connection;
152*2912Sartem 		dbus_connection_ref (new_connection);
153*2912Sartem 		dbus_connection_setup_with_g_main (new_connection, NULL);
154*2912Sartem 
155*2912Sartem 		dbus_connection_register_fallback (new_connection,
156*2912Sartem 						   "/org/freedesktop",
157*2912Sartem 						   &vtable,
158*2912Sartem 						   NULL);
159*2912Sartem 
160*2912Sartem 		/* dbus_server_unref(server); */
161*2912Sartem 
162*2912Sartem 	}
163*2912Sartem }
164*2912Sartem 
165*2912Sartem static void
166*2912Sartem runner_died(GPid pid, gint status, gpointer data) {
167*2912Sartem   g_spawn_close_pid (pid);
168*2912Sartem   DIE (("Runner died"));
169*2912Sartem }
170*2912Sartem 
171*2912Sartem gboolean
172*2912Sartem hald_runner_start_runner(void)
173*2912Sartem {
174*2912Sartem   DBusServer *server = NULL;
175*2912Sartem   DBusError err;
176*2912Sartem   GError *error = NULL;
177*2912Sartem   GPid pid;
178*2912Sartem   char *argv[] = { NULL, NULL};
179*2912Sartem   char *env[] =  { NULL, NULL, NULL, NULL};
180*2912Sartem   const char *hald_runner_path;
181*2912Sartem   char *server_addr;
182*2912Sartem 
183*2912Sartem   running_processes = g_hash_table_new (g_direct_hash, g_direct_equal);
184*2912Sartem 
185*2912Sartem   dbus_error_init(&err);
186*2912Sartem   server = dbus_server_listen(DBUS_SERVER_ADDRESS, &err);
187*2912Sartem   if (server == NULL) {
188*2912Sartem     HAL_ERROR (("Cannot create D-BUS server for the runner"));
189*2912Sartem     goto error;
190*2912Sartem   }
191*2912Sartem 
192*2912Sartem   dbus_server_setup_with_g_main(server, NULL);
193*2912Sartem   dbus_server_set_new_connection_function(server, handle_connection,
194*2912Sartem                                           NULL, NULL);
195*2912Sartem 
196*2912Sartem 
197*2912Sartem   argv[0] = "hald-runner";
198*2912Sartem   server_addr = dbus_server_get_address (server);
199*2912Sartem   env[0] = g_strdup_printf("HALD_RUNNER_DBUS_ADDRESS=%s", server_addr);
200*2912Sartem   dbus_free (server_addr);
201*2912Sartem   hald_runner_path = g_getenv("HALD_RUNNER_PATH");
202*2912Sartem   if (hald_runner_path != NULL) {
203*2912Sartem 	  env[1] = g_strdup_printf ("PATH=%s:" PACKAGE_LIBEXEC_DIR ":" PACKAGE_SCRIPT_DIR ":" PACKAGE_BIN_DIR, hald_runner_path);
204*2912Sartem   } else {
205*2912Sartem 	  env[1] = g_strdup_printf ("PATH=" PACKAGE_LIBEXEC_DIR ":" PACKAGE_SCRIPT_DIR ":" PACKAGE_BIN_DIR);
206*2912Sartem   }
207*2912Sartem 
208*2912Sartem   /*env[2] = "DBUS_VERBOSE=1";*/
209*2912Sartem 
210*2912Sartem 
211*2912Sartem   if (!g_spawn_async(NULL, argv, env, G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
212*2912Sartem         NULL, NULL, &pid, &error)) {
213*2912Sartem     HAL_ERROR (("Could not spawn runner : '%s'", error->message));
214*2912Sartem     g_error_free (error);
215*2912Sartem     goto error;
216*2912Sartem   }
217*2912Sartem   g_free(env[0]);
218*2912Sartem   g_free(env[1]);
219*2912Sartem 
220*2912Sartem   HAL_INFO (("Runner has pid %d", pid));
221*2912Sartem 
222*2912Sartem   g_child_watch_add(pid, runner_died, NULL);
223*2912Sartem   while (runner_connection == NULL) {
224*2912Sartem     /* Wait for the runner */
225*2912Sartem     g_main_context_iteration(NULL, TRUE);
226*2912Sartem   }
227*2912Sartem   return TRUE;
228*2912Sartem 
229*2912Sartem error:
230*2912Sartem   if (server != NULL)
231*2912Sartem     dbus_server_unref(server);
232*2912Sartem   return FALSE;
233*2912Sartem }
234*2912Sartem 
235*2912Sartem static gboolean
236*2912Sartem add_property_to_msg (HalDevice *device, HalProperty *property,
237*2912Sartem                                      gpointer user_data)
238*2912Sartem {
239*2912Sartem   char *prop_upper, *value;
240*2912Sartem   char *c;
241*2912Sartem   gchar *env;
242*2912Sartem   DBusMessageIter *iter = (DBusMessageIter *)user_data;
243*2912Sartem 
244*2912Sartem   prop_upper = g_ascii_strup (hal_property_get_key (property), -1);
245*2912Sartem 
246*2912Sartem   /* periods aren't valid in the environment, so replace them with
247*2912Sartem    * underscores. */
248*2912Sartem   for (c = prop_upper; *c; c++) {
249*2912Sartem     if (*c == '.')
250*2912Sartem       *c = '_';
251*2912Sartem   }
252*2912Sartem 
253*2912Sartem   value = hal_property_to_string (property);
254*2912Sartem   env = g_strdup_printf ("HAL_PROP_%s=%s", prop_upper, value);
255*2912Sartem   dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env);
256*2912Sartem 
257*2912Sartem   g_free (env);
258*2912Sartem   g_free (value);
259*2912Sartem   g_free (prop_upper);
260*2912Sartem 
261*2912Sartem   return TRUE;
262*2912Sartem }
263*2912Sartem 
264*2912Sartem static void
265*2912Sartem add_env(DBusMessageIter *iter, const gchar *key, const gchar *value) {
266*2912Sartem   gchar *env;
267*2912Sartem   env = g_strdup_printf ("%s=%s", key, value);
268*2912Sartem   dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env);
269*2912Sartem   g_free(env);
270*2912Sartem }
271*2912Sartem 
272*2912Sartem static void
273*2912Sartem add_basic_env(DBusMessageIter *iter, const gchar *udi) {
274*2912Sartem   struct utsname un;
275*2912Sartem   char *server_addr;
276*2912Sartem 
277*2912Sartem   if (hald_is_verbose) {
278*2912Sartem     add_env(iter, "HALD_VERBOSE", "1");
279*2912Sartem   }
280*2912Sartem   if (hald_is_initialising) {
281*2912Sartem     add_env(iter, "HALD_STARTUP", "1");
282*2912Sartem   }
283*2912Sartem   if (hald_use_syslog) {
284*2912Sartem     add_env(iter, "HALD_USE_SYSLOG", "1");
285*2912Sartem   }
286*2912Sartem   add_env(iter, "UDI", udi);
287*2912Sartem   server_addr = hald_dbus_local_server_addr();
288*2912Sartem   add_env(iter, "HALD_DIRECT_ADDR", server_addr);
289*2912Sartem   dbus_free (server_addr);
290*2912Sartem #ifdef HAVE_POLKIT
291*2912Sartem   add_env(iter, "HAVE_POLKIT", "1");
292*2912Sartem #endif
293*2912Sartem 
294*2912Sartem   if (uname(&un) == 0) {
295*2912Sartem     char *sysname;
296*2912Sartem 
297*2912Sartem     sysname = g_ascii_strdown(un.sysname, -1);
298*2912Sartem     add_env(iter, "HALD_UNAME_S", sysname);
299*2912Sartem     g_free(sysname);
300*2912Sartem   }
301*2912Sartem }
302*2912Sartem 
303*2912Sartem static void
304*2912Sartem add_extra_env(DBusMessageIter *iter, gchar **env) {
305*2912Sartem   int i;
306*2912Sartem   if (env != NULL) for (i = 0; env[i] != NULL; i++) {
307*2912Sartem     dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &env[i]);
308*2912Sartem   }
309*2912Sartem }
310*2912Sartem 
311*2912Sartem static gboolean
312*2912Sartem add_command(DBusMessageIter *iter, const gchar *command_line) {
313*2912Sartem   gint argc;
314*2912Sartem   gint x;
315*2912Sartem   char **argv;
316*2912Sartem   GError *err = NULL;
317*2912Sartem   DBusMessageIter array_iter;
318*2912Sartem 
319*2912Sartem   if (!g_shell_parse_argv(command_line, &argc, &argv, &err)) {
320*2912Sartem     HAL_ERROR (("Error parsing commandline '%s': %s",
321*2912Sartem                  command_line, err->message));
322*2912Sartem     g_error_free (err);
323*2912Sartem     return FALSE;
324*2912Sartem   }
325*2912Sartem   if (!dbus_message_iter_open_container(iter,
326*2912Sartem                                    DBUS_TYPE_ARRAY,
327*2912Sartem                                    DBUS_TYPE_STRING_AS_STRING,
328*2912Sartem                                    &array_iter))
329*2912Sartem     DIE (("No memory"));
330*2912Sartem   for (x = 0 ; argv[x] != NULL; x++) {
331*2912Sartem     dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &argv[x]);
332*2912Sartem   }
333*2912Sartem   dbus_message_iter_close_container(iter, &array_iter);
334*2912Sartem 
335*2912Sartem   g_strfreev(argv);
336*2912Sartem   return TRUE;
337*2912Sartem }
338*2912Sartem 
339*2912Sartem static gboolean
340*2912Sartem add_first_part(DBusMessageIter *iter, HalDevice *device,
341*2912Sartem                    const gchar *command_line, char **extra_env) {
342*2912Sartem   DBusMessageIter array_iter;
343*2912Sartem   const char *udi;
344*2912Sartem 
345*2912Sartem   udi = hal_device_get_udi(device);
346*2912Sartem   dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &udi);
347*2912Sartem 
348*2912Sartem   dbus_message_iter_open_container(iter,
349*2912Sartem                                    DBUS_TYPE_ARRAY,
350*2912Sartem                                    DBUS_TYPE_STRING_AS_STRING,
351*2912Sartem                                    &array_iter);
352*2912Sartem   hal_device_property_foreach (device, add_property_to_msg, &array_iter);
353*2912Sartem   add_basic_env(&array_iter, udi);
354*2912Sartem   add_extra_env(&array_iter, extra_env);
355*2912Sartem   dbus_message_iter_close_container(iter, &array_iter);
356*2912Sartem 
357*2912Sartem   if (!add_command(iter, command_line)) {
358*2912Sartem     return FALSE;
359*2912Sartem   }
360*2912Sartem   return TRUE;
361*2912Sartem }
362*2912Sartem 
363*2912Sartem /* Start a helper, returns true on a successfull start */
364*2912Sartem gboolean
365*2912Sartem hald_runner_start (HalDevice *device, const gchar *command_line, char **extra_env,
366*2912Sartem 		   HalRunTerminatedCB cb, gpointer data1, gpointer data2)
367*2912Sartem {
368*2912Sartem   DBusMessage *msg, *reply;
369*2912Sartem   DBusError err;
370*2912Sartem   DBusMessageIter iter;
371*2912Sartem 
372*2912Sartem   dbus_error_init(&err);
373*2912Sartem   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
374*2912Sartem                                      "/org/freedesktop/HalRunner",
375*2912Sartem                                      "org.freedesktop.HalRunner",
376*2912Sartem                                      "Start");
377*2912Sartem   if (msg == NULL)
378*2912Sartem     DIE(("No memory"));
379*2912Sartem   dbus_message_iter_init_append(msg, &iter);
380*2912Sartem 
381*2912Sartem   if (!add_first_part(&iter, device, command_line, extra_env))
382*2912Sartem     goto error;
383*2912Sartem 
384*2912Sartem   /* Wait for the reply, should be almost instantanious */
385*2912Sartem   reply =
386*2912Sartem     dbus_connection_send_with_reply_and_block(runner_connection,
387*2912Sartem                                               msg, -1, &err);
388*2912Sartem   if (reply) {
389*2912Sartem     gboolean ret =
390*2912Sartem       (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN);
391*2912Sartem 
392*2912Sartem     if (ret) {
393*2912Sartem 	dbus_int64_t pid_from_runner;
394*2912Sartem 	if (dbus_message_get_args (reply, &err,
395*2912Sartem 				   DBUS_TYPE_INT64, &pid_from_runner,
396*2912Sartem 				   DBUS_TYPE_INVALID)) {
397*2912Sartem 		if (cb != NULL) {
398*2912Sartem 			RunningProcess *rp;
399*2912Sartem 			rp = g_new0 (RunningProcess, 1);
400*2912Sartem 			rp->pid = (GPid) pid_from_runner;
401*2912Sartem 			rp->cb = cb;
402*2912Sartem 			rp->device = device;
403*2912Sartem 			rp->data1 = data1;
404*2912Sartem 			rp->data2 = data2;
405*2912Sartem 
406*2912Sartem 			g_hash_table_insert (running_processes, (gpointer) rp->pid, rp);
407*2912Sartem 		}
408*2912Sartem 	} else {
409*2912Sartem 	  HAL_ERROR (("Error extracting out_pid from runner's Start()"));
410*2912Sartem 	}
411*2912Sartem     }
412*2912Sartem 
413*2912Sartem     dbus_message_unref(reply);
414*2912Sartem     dbus_message_unref(msg);
415*2912Sartem     return ret;
416*2912Sartem   }
417*2912Sartem 
418*2912Sartem error:
419*2912Sartem   dbus_message_unref(msg);
420*2912Sartem   return FALSE;
421*2912Sartem }
422*2912Sartem 
423*2912Sartem static void
424*2912Sartem call_notify(DBusPendingCall *pending, void *user_data)
425*2912Sartem {
426*2912Sartem   HelperData *hb = (HelperData *)user_data;
427*2912Sartem   dbus_uint32_t exitt = HALD_RUN_SUCCESS;
428*2912Sartem   dbus_int32_t return_code = 0;
429*2912Sartem   DBusMessage *m;
430*2912Sartem   GArray *error = NULL;
431*2912Sartem   DBusMessageIter iter;
432*2912Sartem 
433*2912Sartem   error = g_array_new(TRUE, FALSE, sizeof(char *));
434*2912Sartem 
435*2912Sartem   m = dbus_pending_call_steal_reply(pending);
436*2912Sartem   if (dbus_message_get_type(m) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
437*2912Sartem     goto malformed;
438*2912Sartem 
439*2912Sartem   if (!dbus_message_iter_init(m, &iter) ||
440*2912Sartem        dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
441*2912Sartem     goto malformed;
442*2912Sartem   dbus_message_iter_get_basic(&iter, &exitt);
443*2912Sartem 
444*2912Sartem   if (!dbus_message_iter_next(&iter) ||
445*2912Sartem         dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
446*2912Sartem     goto malformed;
447*2912Sartem   dbus_message_iter_get_basic(&iter, &return_code);
448*2912Sartem 
449*2912Sartem   while (dbus_message_iter_next(&iter) &&
450*2912Sartem     dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
451*2912Sartem     const char *value;
452*2912Sartem     dbus_message_iter_get_basic(&iter, &value);
453*2912Sartem     g_array_append_vals(error, &value, 1);
454*2912Sartem   }
455*2912Sartem 
456*2912Sartem   hb->cb(hb->d, exitt, return_code,
457*2912Sartem       (gchar **)error->data, hb->data1, hb->data2);
458*2912Sartem 
459*2912Sartem   g_object_unref (hb->d);
460*2912Sartem 
461*2912Sartem   dbus_message_unref(m);
462*2912Sartem   dbus_pending_call_unref (pending);
463*2912Sartem   g_array_free(error, TRUE);
464*2912Sartem 
465*2912Sartem   return;
466*2912Sartem malformed:
467*2912Sartem   /* Send a Fail callback on malformed messages */
468*2912Sartem   HAL_ERROR (("Malformed or unexpected reply message"));
469*2912Sartem   hb->cb(hb->d, HALD_RUN_FAILED, return_code, NULL, hb->data1, hb->data2);
470*2912Sartem 
471*2912Sartem   g_object_unref (hb->d);
472*2912Sartem 
473*2912Sartem   dbus_message_unref(m);
474*2912Sartem   dbus_pending_call_unref (pending);
475*2912Sartem   g_array_free(error, TRUE);
476*2912Sartem }
477*2912Sartem 
478*2912Sartem /* Run a helper program using the commandline, with input as infomation on
479*2912Sartem  * stdin */
480*2912Sartem void
481*2912Sartem hald_runner_run_method(HalDevice *device,
482*2912Sartem                            const gchar *command_line, char **extra_env,
483*2912Sartem                            gchar *input, gboolean error_on_stderr,
484*2912Sartem                            guint32 timeout,
485*2912Sartem                            HalRunTerminatedCB  cb,
486*2912Sartem                            gpointer data1, gpointer data2) {
487*2912Sartem   DBusMessage *msg;
488*2912Sartem   DBusMessageIter iter;
489*2912Sartem   DBusPendingCall *call;
490*2912Sartem   HelperData *hd = NULL;
491*2912Sartem   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
492*2912Sartem                              "/org/freedesktop/HalRunner",
493*2912Sartem                              "org.freedesktop.HalRunner",
494*2912Sartem                              "Run");
495*2912Sartem   if (msg == NULL)
496*2912Sartem     DIE(("No memory"));
497*2912Sartem   dbus_message_iter_init_append(msg, &iter);
498*2912Sartem 
499*2912Sartem   if (!add_first_part(&iter, device, command_line, extra_env))
500*2912Sartem     goto error;
501*2912Sartem 
502*2912Sartem   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &input);
503*2912Sartem   dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &error_on_stderr);
504*2912Sartem   dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &timeout);
505*2912Sartem 
506*2912Sartem   if (!dbus_connection_send_with_reply(runner_connection,
507*2912Sartem                                               msg, &call, INT_MAX))
508*2912Sartem     DIE (("No memory"));
509*2912Sartem 
510*2912Sartem   hd = malloc(sizeof(HelperData));
511*2912Sartem   hd->d = device;
512*2912Sartem   hd->cb = cb;
513*2912Sartem   hd->data1 = data1;
514*2912Sartem   hd->data2 = data2;
515*2912Sartem 
516*2912Sartem   g_object_ref (device);
517*2912Sartem 
518*2912Sartem   dbus_pending_call_set_notify(call, call_notify, hd, free);
519*2912Sartem   dbus_message_unref(msg);
520*2912Sartem   return;
521*2912Sartem error:
522*2912Sartem   dbus_message_unref(msg);
523*2912Sartem   free(hd);
524*2912Sartem   cb(device, HALD_RUN_FAILED, 0, NULL, data1, data2);
525*2912Sartem }
526*2912Sartem 
527*2912Sartem void
528*2912Sartem hald_runner_run(HalDevice *device,
529*2912Sartem                     const gchar *command_line, char **extra_env,
530*2912Sartem                     guint timeout,
531*2912Sartem                     HalRunTerminatedCB  cb,
532*2912Sartem                     gpointer data1, gpointer data2) {
533*2912Sartem   hald_runner_run_method(device, command_line, extra_env,
534*2912Sartem                              "", FALSE, timeout, cb, data1, data2);
535*2912Sartem }
536*2912Sartem 
537*2912Sartem 
538*2912Sartem 
539*2912Sartem void
540*2912Sartem hald_runner_kill_device(HalDevice *device) {
541*2912Sartem   DBusMessage *msg, *reply;
542*2912Sartem   DBusError err;
543*2912Sartem   DBusMessageIter iter;
544*2912Sartem   const char *udi;
545*2912Sartem 
546*2912Sartem   running_processes_remove_device (device);
547*2912Sartem 
548*2912Sartem   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
549*2912Sartem                              "/org/freedesktop/HalRunner",
550*2912Sartem                              "org.freedesktop.HalRunner",
551*2912Sartem                              "Kill");
552*2912Sartem   if (msg == NULL)
553*2912Sartem     DIE(("No memory"));
554*2912Sartem   dbus_message_iter_init_append(msg, &iter);
555*2912Sartem   udi = hal_device_get_udi(device);
556*2912Sartem   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &udi);
557*2912Sartem 
558*2912Sartem   /* Wait for the reply, should be almost instantanious */
559*2912Sartem   dbus_error_init(&err);
560*2912Sartem   reply =
561*2912Sartem     dbus_connection_send_with_reply_and_block(runner_connection, msg, -1, &err);
562*2912Sartem   if (reply) {
563*2912Sartem     dbus_message_unref(reply);
564*2912Sartem   }
565*2912Sartem 
566*2912Sartem   dbus_message_unref(msg);
567*2912Sartem }
568*2912Sartem 
569*2912Sartem void
570*2912Sartem hald_runner_kill_all(HalDevice *device) {
571*2912Sartem   DBusMessage *msg, *reply;
572*2912Sartem   DBusError err;
573*2912Sartem 
574*2912Sartem   running_processes_remove_device (device);
575*2912Sartem 
576*2912Sartem   msg = dbus_message_new_method_call("org.freedesktop.HalRunner",
577*2912Sartem                              "/org/freedesktop/HalRunner",
578*2912Sartem                              "org.freedesktop.HalRunner",
579*2912Sartem                              "KillAll");
580*2912Sartem   if (msg == NULL)
581*2912Sartem     DIE(("No memory"));
582*2912Sartem 
583*2912Sartem   /* Wait for the reply, should be almost instantanious */
584*2912Sartem   dbus_error_init(&err);
585*2912Sartem   reply =
586*2912Sartem     dbus_connection_send_with_reply_and_block(runner_connection,
587*2912Sartem                                               msg, -1, &err);
588*2912Sartem   if (reply) {
589*2912Sartem     dbus_message_unref(reply);
590*2912Sartem   }
591*2912Sartem 
592*2912Sartem   dbus_message_unref(msg);
593*2912Sartem }
594