xref: /illumos-gate/usr/src/cmd/hal/hald/hald_dbus.c (revision d2ec54f7)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * dbus.c : D-BUS interface of HAL daemon
5  *
6  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  **************************************************************************/
25 
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <stdint.h>
36 #include <sys/time.h>
37 
38 #include <dbus/dbus.h>
39 #include <dbus/dbus-glib-lowlevel.h>
40 
41 #include "hald.h"
42 #include "hald_dbus.h"
43 #include "device.h"
44 #include "device_store.h"
45 #include "device_info.h"
46 #include "logger.h"
47 #include "osspec.h"
48 #include "util.h"
49 #include "hald_runner.h"
50 
51 #define HALD_DBUS_ADDRESS "unix:tmpdir=" HALD_SOCKET_DIR
52 
53 static DBusConnection *dbus_connection = NULL;
54 
55 static void
56 raise_error (DBusConnection *connection,
57 	     DBusMessage *in_reply_to,
58 	     const char *error_name,
59 	     char *format, ...) __attribute__((format (printf, 4, 5)));
60 
61 /**
62  * @defgroup DaemonErrors Error conditions
63  * @ingroup HalDaemon
64  * @brief Various error messages the HAL daemon can raise
65  * @{
66  */
67 
68 /** Raise HAL error
69  *
70  *  @param  connection          D-Bus connection
71  *  @param  in_reply_to         message to report error on
72  *  @param  error_name          D-Bus error name
73  *  @param  format              printf-style format for error message
74  */
75 static void
76 raise_error (DBusConnection *connection,
77 	     DBusMessage *in_reply_to,
78 	     const char *error_name,
79 	     char *format, ...)
80 {
81 	char buf[512];
82 	DBusMessage *reply;
83 
84 	va_list args;
85 	va_start(args, format);
86 	vsnprintf(buf, sizeof buf, format, args);
87 	va_end(args);
88 
89 	HAL_WARNING ((buf));
90 	reply = dbus_message_new_error (in_reply_to, error_name, buf);
91 	if (reply == NULL)
92 		DIE (("No memory"));
93 	if (!dbus_connection_send (connection, reply, NULL))
94 		DIE (("No memory"));
95 	dbus_message_unref (reply);
96 }
97 
98 /** Raise the org.freedesktop.Hal.NoSuchDevice error
99  *
100  *  @param  connection          D-Bus connection
101  *  @param  in_reply_to         message to report error on
102  *  @param  udi                 Unique device id given
103  */
104 static void
105 raise_no_such_device (DBusConnection *connection,
106 		      DBusMessage *in_reply_to, const char *udi)
107 {
108 	raise_error (
109 		connection, in_reply_to,
110 		"org.freedesktop.Hal.NoSuchDevice",
111 		"No device with id %s",
112 		udi
113 	);
114 }
115 
116 /** Raise the org.freedesktop.Hal.NoSuchProperty error
117  *
118  *  @param  connection          D-Bus connection
119  *  @param  in_reply_to         message to report error on
120  *  @param  device_id           Id of the device
121  *  @param  key                 Key of the property that didn't exist
122  */
123 static void
124 raise_no_such_property (DBusConnection *connection,
125 			DBusMessage *in_reply_to,
126 			const char *device_id, const char *key)
127 {
128 	raise_error (
129 		connection, in_reply_to,
130 		"org.freedesktop.Hal.NoSuchProperty",
131 		"No property %s on device with id %s",
132 		key, device_id
133 	);
134 }
135 
136 /** Raise the org.freedesktop.Hal.TypeMismatch error
137  *
138  *  @param  connection          D-Bus connection
139  *  @param  in_reply_to         message to report error on
140  *  @param  device_id           Id of the device
141  *  @param  key                 Key of the property
142  */
143 static void
144 raise_property_type_error (DBusConnection *connection,
145 			   DBusMessage *in_reply_to,
146 			   const char *device_id, const char *key)
147 {
148 	raise_error (
149 		connection, in_reply_to,
150 		"org.freedesktop.Hal.TypeMismatch",
151 		"Type mismatch setting property %s on device with id %s",
152 		key, device_id
153 	);
154 }
155 
156 /** Raise the org.freedesktop.Hal.SyntaxError error
157  *
158  *  @param  connection          D-Bus connection
159  *  @param  in_reply_to         message to report error on
160  *  @param  method_name         Name of the method that was invoked with
161  *                              the wrong signature
162  */
163 static void
164 raise_syntax (DBusConnection *connection,
165 	      DBusMessage *in_reply_to, const char *method_name)
166 {
167 	raise_error (
168 		connection, in_reply_to,
169 		"org.freedesktop.Hal.SyntaxError",
170 		"There is a syntax error in the invocation of the method %s",
171 		method_name
172 	);
173 }
174 
175 /** Raise the org.freedesktop.Hal.DeviceNotLocked error
176  *
177  *  @param  connection          D-Bus connection
178  *  @param  in_reply_to         message to report error on
179  *  @param  device              device which isn't locked
180  */
181 static void
182 raise_device_not_locked (DBusConnection *connection,
183 			 DBusMessage    *in_reply_to,
184 			 HalDevice      *device)
185 {
186 	raise_error (
187 		connection, in_reply_to,
188 		"org.freedesktop.Hal.DeviceNotLocked",
189 		"The device %s is not locked",
190 		 hal_device_get_udi (device)
191 	);
192 }
193 
194 /** Raise the org.freedesktop.Hal.DeviceAlreadyLocked error
195  *
196  *  @param  connection          D-Bus connection
197  *  @param  in_reply_to         message to report error on
198  *  @param  device              device which isn't locked
199  */
200 static void
201 raise_device_already_locked (DBusConnection *connection,
202 			     DBusMessage    *in_reply_to,
203 			     HalDevice      *device)
204 {
205 	DBusMessage *reply;
206 	const char *reason;
207 
208 	reason = hal_device_property_get_string (device, "info.locked.reason");
209 	HAL_WARNING (("Device %s is already locked: %s",
210 		      hal_device_get_udi (device), reason));
211 
212 
213 	reply = dbus_message_new_error (in_reply_to,
214 					"org.freedesktop.Hal.DeviceAlreadyLocked",
215 					reason);
216 
217 	if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
218 		DIE (("No memory"));
219 
220 	dbus_message_unref (reply);
221 }
222 
223 /** Raise the org.freedesktop.Hal.BranchAlreadyClaimed error
224  *
225  *  @param  connection          D-Bus connection
226  *  @param  in_reply_to         message to report error on
227  *  @param  udi                 branch which isn't claimed
228  */
229 static void
230 raise_branch_already_claimed (DBusConnection *connection,
231 			     DBusMessage    *in_reply_to,
232 			     HalDevice      *device)
233 {
234 	DBusMessage *reply;
235 	const char *claim_service;
236 
237 	claim_service = hal_device_property_get_string (device, "info.claimed.service");
238 	HAL_WARNING (("Branch %s is already claimed by: %s",
239 		      hal_device_get_udi (device), claim_service));
240 
241 
242 	reply = dbus_message_new_error (in_reply_to,
243 					"org.freedesktop.Hal.BranchAlreadyClaimed",
244 					claim_service);
245 
246 	if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
247 		DIE (("No memory"));
248 
249 	dbus_message_unref (reply);
250 }
251 
252 /** Raise the org.freedesktop.Hal.BranchNotClaimed error
253  *
254  *  @param  connection          D-Bus connection
255  *  @param  in_reply_to         message to report error on
256  *  @param  udi                 branch which isn't claimed
257  */
258 static void
259 raise_branch_not_claimed (DBusConnection *connection,
260 			     DBusMessage    *in_reply_to,
261 			     HalDevice      *device)
262 {
263 	raise_error (
264 		connection, in_reply_to,
265 		"org.freedesktop.Hal.BranchNotClaimed",
266 		"The branch %s is not claimed",
267 		 hal_device_get_udi (device)
268 	);
269 }
270 
271 /** Raise the org.freedesktop.Hal.PermissionDenied error
272  *
273  *  @param  connection          D-Bus connection
274  *  @param  in_reply_to         message to report error on
275  *  @param  message             what you're not allowed to do
276  */
277 static void
278 raise_permission_denied (DBusConnection *connection,
279 			 DBusMessage    *in_reply_to,
280 			 const char     *reason)
281 {
282 	raise_error (
283 		connection, in_reply_to,
284 		"org.freedesktop.Hal.PermissionDenied",
285 		"Permission denied: %s",
286 		 reason
287 	);
288 }
289 
290 /** @} */
291 
292 /**
293  * @defgroup ManagerInterface D-BUS interface org.freedesktop.Hal.Manager
294  * @ingroup HalDaemon
295  * @brief D-BUS interface for querying device objects
296  *
297  * @{
298  */
299 
300 static gboolean
301 foreach_device_get_udi (HalDeviceStore *store, HalDevice *device,
302 			gpointer user_data)
303 {
304 	DBusMessageIter *iter = user_data;
305 	const char *udi;
306 
307 	udi = hal_device_get_udi (device);
308 	dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &udi);
309 
310 	return TRUE;
311 }
312 
313 /** Get all devices.
314  *
315  *  <pre>
316  *  array{object_reference} Manager.GetAllDevices()
317  *  </pre>
318  *
319  *  @param  connection          D-BUS connection
320  *  @param  message             Message
321  *  @return                     What to do with the message
322  */
323 DBusHandlerResult
324 manager_get_all_devices (DBusConnection * connection,
325 			 DBusMessage * message)
326 {
327 	DBusMessage *reply;
328 	DBusMessageIter iter;
329 	DBusMessageIter iter_array;
330 
331 	reply = dbus_message_new_method_return (message);
332 	if (reply == NULL)
333 		DIE (("No memory"));
334 
335 	dbus_message_iter_init_append (reply, &iter);
336 	dbus_message_iter_open_container (&iter,
337 					  DBUS_TYPE_ARRAY,
338 					  DBUS_TYPE_STRING_AS_STRING,
339 					  &iter_array);
340 
341 	hal_device_store_foreach (hald_get_gdl (),
342 				  foreach_device_get_udi,
343 				  &iter_array);
344 
345 	dbus_message_iter_close_container (&iter, &iter_array);
346 
347 	if (!dbus_connection_send (connection, reply, NULL))
348 		DIE (("No memory"));
349 
350 	dbus_message_unref (reply);
351 
352 	return DBUS_HANDLER_RESULT_HANDLED;
353 }
354 
355 typedef struct {
356 	const char *key;
357 	const char *value;
358 	DBusMessageIter *iter;
359 } DeviceMatchInfo;
360 
361 static gboolean
362 foreach_device_match_get_udi (HalDeviceStore *store, HalDevice *device,
363 			      gpointer user_data)
364 {
365 	DeviceMatchInfo *info = user_data;
366 	const char *dev_value;
367 
368 	if (hal_device_property_get_type (device,
369 					  info->key) != DBUS_TYPE_STRING)
370 		return TRUE;
371 
372 	dev_value = hal_device_property_get_string (device, info->key);
373 
374 	if (dev_value != NULL && strcmp (dev_value, info->value) == 0) {
375 		const char *udi;
376 		udi =  hal_device_get_udi (device);
377 		dbus_message_iter_append_basic  (info->iter,
378 						 DBUS_TYPE_STRING,
379 						 &udi);
380 	}
381 
382 	return TRUE;
383 }
384 
385 static gboolean
386 foreach_device_match_get_udi_tdl (HalDeviceStore *store, HalDevice *device,
387 				  gpointer user_data)
388 {
389 	DeviceMatchInfo *info = user_data;
390 	const char *dev_value;
391 
392 	/* skip devices in the TDL that hasn't got a real UDI yet */
393 	if (strncmp (device->udi, "/org/freedesktop/Hal/devices/temp",
394 		     sizeof ("/org/freedesktop/Hal/devices/temp")) == 0)
395 		return TRUE;
396 
397 	if (hal_device_property_get_type (device,
398 					  info->key) != DBUS_TYPE_STRING)
399 		return TRUE;
400 
401 	dev_value = hal_device_property_get_string (device, info->key);
402 
403 	if (dev_value != NULL && strcmp (dev_value, info->value) == 0) {
404 		const char *udi;
405 		udi = hal_device_get_udi (device);
406 
407 		dbus_message_iter_append_basic (info->iter,
408 						DBUS_TYPE_STRING,
409 						&udi);
410 	}
411 
412 	return TRUE;
413 }
414 
415 /** Find devices in the GDL where a single string property matches a given
416  *  value. Also returns devices in the TDL that has a non-tmp UDI.
417  *
418  *  <pre>
419  *  array{object_reference} Manager.FindDeviceStringMatch(string key,
420  *                                                        string value)
421  *  </pre>
422  *
423  *  @param  connection          D-BUS connection
424  *  @param  message             Message
425  *  @return                     What to do with the message
426  */
427 DBusHandlerResult
428 manager_find_device_string_match (DBusConnection * connection,
429 				  DBusMessage * message)
430 {
431 	DBusMessage *reply;
432 	DBusMessageIter iter;
433 	DBusMessageIter iter_array;
434 	DBusError error;
435 	const char *key;
436 	const char *value;
437 	DeviceMatchInfo info;
438 
439 	HAL_TRACE (("entering"));
440 
441 	dbus_error_init (&error);
442 	if (!dbus_message_get_args (message, &error,
443 				    DBUS_TYPE_STRING, &key,
444 				    DBUS_TYPE_STRING, &value,
445 				    DBUS_TYPE_INVALID)) {
446 		raise_syntax (connection, message,
447 			      "Manager.FindDeviceStringMatch");
448 		return DBUS_HANDLER_RESULT_HANDLED;
449 	}
450 
451 	reply = dbus_message_new_method_return (message);
452 	if (reply == NULL)
453 		DIE (("No memory"));
454 
455 	dbus_message_iter_init_append (reply, &iter);
456 	dbus_message_iter_open_container (&iter,
457 					  DBUS_TYPE_ARRAY,
458 					  DBUS_TYPE_STRING_AS_STRING,
459 					  &iter_array);
460 
461 	info.key = key;
462 	info.value = value;
463 	info.iter = &iter_array;
464 
465 	hal_device_store_foreach (hald_get_gdl (),
466 				  foreach_device_match_get_udi,
467 				  &info);
468 
469 	/* Also returns devices in the TDL that has a non-tmp UDI */
470 	hal_device_store_foreach (hald_get_tdl (),
471 				  foreach_device_match_get_udi_tdl,
472 				  &info);
473 
474 	dbus_message_iter_close_container (&iter, &iter_array);
475 
476 	if (!dbus_connection_send (connection, reply, NULL))
477 		DIE (("No memory"));
478 
479 	dbus_message_unref (reply);
480 
481 	return DBUS_HANDLER_RESULT_HANDLED;
482 }
483 
484 typedef struct {
485 	const char *capability;
486 	DBusMessageIter *iter;
487 } DeviceCapabilityInfo;
488 
489 static gboolean
490 foreach_device_by_capability (HalDeviceStore *store, HalDevice *device, gpointer user_data)
491 {
492 	DeviceCapabilityInfo *info = (DeviceCapabilityInfo *) user_data;
493 
494 	if (hal_device_has_capability (device, info->capability)) {
495 		dbus_message_iter_append_basic (info->iter,
496 						DBUS_TYPE_STRING,
497 						&(device->udi));
498 	}
499 
500 	return TRUE;
501 }
502 
503 /** Find devices in the GDL with a given capability.
504  *
505  *  <pre>
506  *  array{object_reference} Manager.FindDeviceByCapability(string capability)
507  *  </pre>
508  *
509  *  @param  connection          D-BUS connection
510  *  @param  message             Message
511  *  @return                     What to do with the message
512  */
513 DBusHandlerResult
514 manager_find_device_by_capability (DBusConnection * connection,
515 				   DBusMessage * message)
516 {
517 	DBusMessage *reply;
518 	DBusMessageIter iter;
519 	DBusMessageIter iter_array;
520 	DBusError error;
521 	const char *capability;
522 	DeviceCapabilityInfo info;
523 
524 	HAL_TRACE (("entering"));
525 
526 	dbus_error_init (&error);
527 	if (!dbus_message_get_args (message, &error,
528 				    DBUS_TYPE_STRING, &capability,
529 				    DBUS_TYPE_INVALID)) {
530 		raise_syntax (connection, message,
531 			      "Manager.FindDeviceByCapability");
532 		return DBUS_HANDLER_RESULT_HANDLED;
533 	}
534 
535 	reply = dbus_message_new_method_return (message);
536 	if (reply == NULL)
537 		DIE (("No memory"));
538 
539 	dbus_message_iter_init_append (reply, &iter);
540 	dbus_message_iter_open_container (&iter,
541 					  DBUS_TYPE_ARRAY,
542 					  DBUS_TYPE_STRING_AS_STRING,
543 					  &iter_array);
544 
545 	info.capability = capability;
546 	info.iter = &iter_array;
547 
548 	hal_device_store_foreach (hald_get_gdl (),
549 				  foreach_device_by_capability,
550 				  &info);
551 
552 	dbus_message_iter_close_container (&iter, &iter_array);
553 
554 	if (!dbus_connection_send (connection, reply, NULL))
555 		DIE (("No memory"));
556 
557 	dbus_message_unref (reply);
558 
559 	return DBUS_HANDLER_RESULT_HANDLED;
560 }
561 
562 
563 /** Determine if a device exists.
564  *
565  *  <pre>
566  *  bool Manager.DeviceExists(string udi)
567  *  </pre>
568  *
569  *  @param  connection          D-BUS connection
570  *  @param  message             Message
571  *  @return                     What to do with the message
572  */
573 DBusHandlerResult
574 manager_device_exists (DBusConnection * connection, DBusMessage * message)
575 {
576 	DBusMessage *reply;
577 	DBusMessageIter iter;
578 	DBusError error;
579 	HalDevice *d;
580 	const char *udi;
581 	dbus_bool_t b;
582 
583 	dbus_error_init (&error);
584 	if (!dbus_message_get_args (message, &error,
585 				    DBUS_TYPE_STRING, &udi,
586 				    DBUS_TYPE_INVALID)) {
587 		raise_syntax (connection, message, "Manager.DeviceExists");
588 		return DBUS_HANDLER_RESULT_HANDLED;
589 	}
590 
591 	HAL_TRACE (("entering, udi=%s", udi));
592 
593 	d = hal_device_store_find (hald_get_gdl (), udi);
594 
595 	if (d == NULL)
596 		d = hal_device_store_find (hald_get_tdl (), udi);
597 
598 	reply = dbus_message_new_method_return (message);
599 	dbus_message_iter_init_append (reply, &iter);
600 	b = d != NULL;
601 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
602 
603 	if (reply == NULL)
604 		DIE (("No memory"));
605 
606 	if (!dbus_connection_send (connection, reply, NULL))
607 		DIE (("No memory"));
608 
609 	dbus_message_unref (reply);
610 	return DBUS_HANDLER_RESULT_HANDLED;
611 }
612 
613 /** Send signal DeviceAdded(string udi) on the org.freedesktop.Hal.Manager
614  *  interface on the object /org/freedesktop/Hal/Manager.
615  *
616  *  @param  device              The HalDevice added
617  */
618 void
619 manager_send_signal_device_added (HalDevice *device)
620 {
621 	const char *udi = hal_device_get_udi (device);
622 	DBusMessage *message;
623 	DBusMessageIter iter;
624 
625 	if (dbus_connection == NULL)
626 		goto out;
627 
628 	HAL_TRACE (("entering, udi=%s", udi));
629 
630 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
631 					   "org.freedesktop.Hal.Manager",
632 					   "DeviceAdded");
633 
634 	dbus_message_iter_init_append (message, &iter);
635 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
636 
637 	if (!dbus_connection_send (dbus_connection, message, NULL))
638 		DIE (("error broadcasting message"));
639 
640 	dbus_message_unref (message);
641 
642 out:
643 	;
644 }
645 
646 /** Send signal DeviceRemoved(string udi) on the org.freedesktop.Hal.Manager
647  *  interface on the object /org/freedesktop/Hal/Manager.
648  *
649  *  @param  device              The HalDevice removed
650  */
651 void
652 manager_send_signal_device_removed (HalDevice *device)
653 {
654 	const char *udi = hal_device_get_udi (device);
655 	DBusMessage *message;
656 	DBusMessageIter iter;
657 
658 	if (dbus_connection == NULL)
659 		goto out;
660 
661 	HAL_TRACE (("entering, udi=%s", udi));
662 
663 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
664 					   "org.freedesktop.Hal.Manager",
665 					   "DeviceRemoved");
666 
667 	dbus_message_iter_init_append (message, &iter);
668 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
669 
670 	if (!dbus_connection_send (dbus_connection, message, NULL))
671 		DIE (("error broadcasting message"));
672 
673 	dbus_message_unref (message);
674 out:
675 	;
676 }
677 
678 /** Send signal NewCapability(string udi, string capability) on the
679  *  org.freedesktop.Hal.Manager interface on the object
680  *  /org/freedesktop/Hal/Manager.
681  *
682  *  @param  udi                 Unique Device Id
683  *  @param  capability          Capability
684  */
685 void
686 manager_send_signal_new_capability (HalDevice *device,
687 				    const char *capability)
688 {
689 	const char *udi = hal_device_get_udi (device);
690 	DBusMessage *message;
691 	DBusMessageIter iter;
692 
693 	if (dbus_connection == NULL)
694 		goto out;
695 
696 	HAL_TRACE (("entering, udi=%s, cap=%s", udi, capability));
697 
698 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
699 					   "org.freedesktop.Hal.Manager",
700 					   "NewCapability");
701 
702 	dbus_message_iter_init_append (message, &iter);
703 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
704 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
705 
706 	if (!dbus_connection_send (dbus_connection, message, NULL))
707 		DIE (("error broadcasting message"));
708 
709 	dbus_message_unref (message);
710 out:
711 	;
712 }
713 
714 /** @} */
715 
716 /**
717  * @defgroup DeviceInterface D-BUS interface org.freedesktop.Hal.Device
718  * @ingroup HalDaemon
719  * @brief D-BUS interface for generic device operations
720  * @{
721  */
722 
723 static gboolean
724 foreach_property_append (HalDevice *device, HalProperty *p,
725 			 gpointer user_data)
726 {
727 	DBusMessageIter *iter;
728 	DBusMessageIter iter_dict_entry;
729 	const char *key;
730 	int type;
731 
732 	iter = (DBusMessageIter *)user_data;
733 
734 	dbus_message_iter_open_container (iter,
735 					  DBUS_TYPE_DICT_ENTRY,
736 					  NULL,
737 					  &iter_dict_entry);
738 
739 	key = hal_property_get_key (p);
740 	type = hal_property_get_type (p);
741 
742 	dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &key);
743 
744 	switch (type) {
745 	case HAL_PROPERTY_TYPE_STRING:
746 	{
747 		DBusMessageIter iter_var;
748 		const char *v;
749 
750 		v = hal_property_get_string (p);
751 
752 		dbus_message_iter_open_container (&iter_dict_entry,
753 						  DBUS_TYPE_VARIANT,
754 						  DBUS_TYPE_STRING_AS_STRING,
755 						  &iter_var);
756 
757 		dbus_message_iter_append_basic (&iter_var,
758 						DBUS_TYPE_STRING,
759 						&v);
760 
761 		dbus_message_iter_close_container (&iter_dict_entry,
762 						   &iter_var);
763 		break;
764 	}
765 	case HAL_PROPERTY_TYPE_INT32:
766 	{
767 		DBusMessageIter iter_var;
768 		dbus_int32_t v;
769 
770 		v = hal_property_get_int (p);
771 
772 		dbus_message_iter_open_container (&iter_dict_entry,
773 						  DBUS_TYPE_VARIANT,
774 						  DBUS_TYPE_INT32_AS_STRING,
775 						  &iter_var);
776 
777 		dbus_message_iter_append_basic (&iter_var,
778 						DBUS_TYPE_INT32,
779 						&v);
780 
781 		dbus_message_iter_close_container (&iter_dict_entry,
782 						   &iter_var);
783 		break;
784 	}
785 	case HAL_PROPERTY_TYPE_UINT64:
786 	{
787 		DBusMessageIter iter_var;
788 		dbus_uint64_t v;
789 
790 		v = hal_property_get_uint64 (p);
791 
792 		dbus_message_iter_open_container (&iter_dict_entry,
793 						  DBUS_TYPE_VARIANT,
794 						  DBUS_TYPE_UINT64_AS_STRING,
795 						  &iter_var);
796 
797 		dbus_message_iter_append_basic (&iter_var,
798 						DBUS_TYPE_UINT64,
799 						&v);
800 
801 		dbus_message_iter_close_container (&iter_dict_entry,
802 						   &iter_var);
803 		break;
804 	}
805 	case HAL_PROPERTY_TYPE_DOUBLE:
806 	{
807 		DBusMessageIter iter_var;
808 		double v;
809 
810 		v = hal_property_get_double (p);
811 
812 		dbus_message_iter_open_container (&iter_dict_entry,
813 						  DBUS_TYPE_VARIANT,
814 						  DBUS_TYPE_DOUBLE_AS_STRING,
815 						  &iter_var);
816 
817 		dbus_message_iter_append_basic (&iter_var,
818 						DBUS_TYPE_DOUBLE,
819 						&v);
820 
821 		dbus_message_iter_close_container (&iter_dict_entry,
822 						   &iter_var);
823 		break;
824 	}
825 	case HAL_PROPERTY_TYPE_BOOLEAN:
826 	{
827 		DBusMessageIter iter_var;
828 		dbus_bool_t v;
829 
830 		v = hal_property_get_bool (p);
831 
832 		dbus_message_iter_open_container (&iter_dict_entry,
833 						  DBUS_TYPE_VARIANT,
834 						  DBUS_TYPE_BOOLEAN_AS_STRING,
835 						  &iter_var);
836 
837 		dbus_message_iter_append_basic (&iter_var,
838 						DBUS_TYPE_BOOLEAN,
839 						&v);
840 
841 		dbus_message_iter_close_container (&iter_dict_entry,
842 						   &iter_var);
843 		break;
844 	}
845 	case HAL_PROPERTY_TYPE_STRLIST:
846 	{
847 		DBusMessageIter iter_var, iter_array;
848 		GSList *iter;
849 
850 		dbus_message_iter_open_container (&iter_dict_entry,
851 						  DBUS_TYPE_VARIANT,
852 						  DBUS_TYPE_ARRAY_AS_STRING
853 						  DBUS_TYPE_STRING_AS_STRING,
854 						  &iter_var);
855 
856 		dbus_message_iter_open_container (&iter_var,
857 						  DBUS_TYPE_ARRAY,
858 						  DBUS_TYPE_STRING_AS_STRING,
859 						  &iter_array);
860 
861 		for (iter = hal_property_get_strlist (p); iter != NULL; iter = iter->next) {
862 
863 			const char *v;
864 			v = (const char *) iter->data;
865 
866 			dbus_message_iter_append_basic (&iter_array,
867 							DBUS_TYPE_STRING,
868 							&v);
869 		}
870 
871 		dbus_message_iter_close_container (&iter_var,
872 						   &iter_array);
873 
874 		dbus_message_iter_close_container (&iter_dict_entry,
875 						   &iter_var);
876 		break;
877 	}
878 
879 	default:
880 		HAL_WARNING (("Unknown property type 0x%04x", type));
881 		break;
882 	}
883 
884 	dbus_message_iter_close_container (iter, &iter_dict_entry);
885 
886 
887 	return TRUE;
888 }
889 
890 
891 
892 /** Get all properties on a device.
893  *
894  *  <pre>
895  *  map{string, any} Device.GetAllProperties()
896  *
897  *    raises org.freedesktop.Hal.NoSuchDevice
898  *  </pre>
899  *
900  *  @param  connection          D-BUS connection
901  *  @param  message             Message
902  *  @return                     What to do with the message
903  */
904 DBusHandlerResult
905 device_get_all_properties (DBusConnection * connection,
906 			   DBusMessage * message)
907 {
908 	DBusMessage *reply;
909 	DBusMessageIter iter;
910 	DBusMessageIter iter_dict;
911 	HalDevice *d;
912 	const char *udi;
913 
914 	udi = dbus_message_get_path (message);
915 
916 	HAL_TRACE (("entering, udi=%s", udi));
917 
918 	d = hal_device_store_find (hald_get_gdl (), udi);
919 	if (d == NULL)
920 		d = hal_device_store_find (hald_get_tdl (), udi);
921 
922 	if (d == NULL) {
923 		raise_no_such_device (connection, message, udi);
924 		return DBUS_HANDLER_RESULT_HANDLED;
925 	}
926 
927 	reply = dbus_message_new_method_return (message);
928 	if (reply == NULL)
929 		DIE (("No memory"));
930 
931 	dbus_message_iter_init_append (reply, &iter);
932 
933 	dbus_message_iter_open_container (&iter,
934 					  DBUS_TYPE_ARRAY,
935 					  DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
936 					  DBUS_TYPE_STRING_AS_STRING
937 					  DBUS_TYPE_VARIANT_AS_STRING
938 					  DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
939 					  &iter_dict);
940 
941 	hal_device_property_foreach (d,
942 				     foreach_property_append,
943 				     &iter_dict);
944 
945 	dbus_message_iter_close_container (&iter, &iter_dict);
946 
947 	if (!dbus_connection_send (connection, reply, NULL))
948 		DIE (("No memory"));
949 
950 	dbus_message_unref (reply);
951 
952 	return DBUS_HANDLER_RESULT_HANDLED;
953 }
954 
955 #ifdef sun
956 #include <sys/stat.h>
957 static dbus_bool_t
958 user_at_console(unsigned long uid)
959 {
960 	struct stat st;
961 
962 	return ((stat("/dev/console", &st) == 0) && (st.st_uid == uid));
963 }
964 #endif /* sun */
965 
966 static dbus_bool_t
967 sender_has_privileges (DBusConnection *connection, DBusMessage *message)
968 {
969 	DBusError error;
970 	unsigned long user_uid;
971 	const char *user_base_svc;
972 	dbus_bool_t ret;
973 
974 	ret = FALSE;
975 
976 	user_base_svc = dbus_message_get_sender (message);
977 	if (user_base_svc == NULL) {
978 		HAL_WARNING (("Cannot determine base service of caller"));
979 		goto out;
980 	}
981 
982 	HAL_DEBUG (("base_svc = %s", user_base_svc));
983 
984 	dbus_error_init (&error);
985 	user_uid = dbus_bus_get_unix_user (connection, user_base_svc, &error);
986 	if (user_uid == (unsigned long) -1 || dbus_error_is_set (&error)) {
987 		HAL_WARNING (("Could not get uid for connection: %s %s", error.name, error.message));
988 		dbus_error_free (&error);
989 		goto out;
990 	}
991 
992 	HAL_INFO (("uid for caller is %ld", user_uid));
993 
994 	if (user_uid != 0 && user_uid != geteuid()) {
995 #ifdef sun
996 		if (dbus_message_is_method_call (message,
997 						"org.freedesktop.Hal.Device",
998 						"Rescan")) {
999 			if (user_at_console(user_uid)) {
1000 				ret = TRUE;
1001 				goto out;
1002 			}
1003 		}
1004 #endif
1005 		HAL_WARNING (("uid %d is not privileged", user_uid));
1006 		goto out;
1007 	}
1008 
1009 	ret = TRUE;
1010 
1011 out:
1012 	return ret;
1013 }
1014 
1015 
1016 /** Set multiple properties on a device in an atomic fashion.
1017  *
1018  *  <pre>
1019  *  Device.GetAllProperties(map{string, any} properties)
1020  *
1021  *    raises org.freedesktop.Hal.NoSuchDevice
1022  *  </pre>
1023  *
1024  *  @param  connection          D-BUS connection
1025  *  @param  message             Message
1026  *  @return                     What to do with the message
1027  */
1028 static DBusHandlerResult
1029 device_set_multiple_properties (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
1030 {
1031 	DBusMessage *reply;
1032 	DBusMessageIter iter;
1033 	DBusMessageIter dict_iter;
1034 	HalDevice *d;
1035 	const char *udi;
1036 
1037 	udi = dbus_message_get_path (message);
1038 
1039 	HAL_TRACE (("entering, udi=%s", udi));
1040 
1041 	d = hal_device_store_find (hald_get_gdl (), udi);
1042 	if (d == NULL)
1043 		d = hal_device_store_find (hald_get_tdl (), udi);
1044 
1045 	if (d == NULL) {
1046 		raise_no_such_device (connection, message, udi);
1047 		return DBUS_HANDLER_RESULT_HANDLED;
1048 	}
1049 
1050 	if (!local_interface && !sender_has_privileges (connection, message)) {
1051 		raise_permission_denied (connection, message, "SetProperty: not privileged");
1052 		return DBUS_HANDLER_RESULT_HANDLED;
1053 	}
1054 
1055 	dbus_message_iter_init (message, &iter);
1056 
1057 	if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY  &&
1058 	    dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DICT_ENTRY) {
1059 		HAL_ERROR (("error, expecting an array of dict entries", __FILE__, __LINE__));
1060 		raise_syntax (connection, message, udi);
1061 		return DBUS_HANDLER_RESULT_HANDLED;
1062 	}
1063 
1064 	dbus_message_iter_recurse (&iter, &dict_iter);
1065 
1066 	/* update atomically */
1067 	device_property_atomic_update_begin ();
1068 
1069 	while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY)
1070 	{
1071 		DBusMessageIter dict_entry_iter, var_iter, array_iter;
1072 		const char *key;
1073 		int change_type;
1074 		dbus_bool_t rc;
1075 
1076 		dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
1077 		dbus_message_iter_get_basic (&dict_entry_iter, &key);
1078 
1079 		dbus_message_iter_next (&dict_entry_iter);
1080 		dbus_message_iter_recurse (&dict_entry_iter, &var_iter);
1081 		change_type = dbus_message_iter_get_arg_type (&var_iter);
1082 
1083 		rc = FALSE;
1084 
1085 		switch (change_type) {
1086 		case DBUS_TYPE_ARRAY:
1087 			if (dbus_message_iter_get_element_type (&var_iter) != DBUS_TYPE_STRING) {
1088 				/* TODO: error */
1089 			}
1090 			dbus_message_iter_recurse (&var_iter, &array_iter);
1091 
1092 			hal_device_property_strlist_clear (d, key);
1093 
1094 			while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) {
1095 				const char *v;
1096 				dbus_message_iter_get_basic (&array_iter, &v);
1097 				HAL_INFO ((" strlist elem %s -> %s", key, v));
1098 				rc = hal_device_property_strlist_append (d, key, v);
1099 				dbus_message_iter_next (&array_iter);
1100 			}
1101 
1102 			break;
1103 		case DBUS_TYPE_STRING:
1104 		{
1105 			const char *v;
1106 			dbus_message_iter_get_basic (&var_iter, &v);
1107 			HAL_INFO (("%s -> %s", key, v));
1108 			rc = hal_device_property_set_string (d, key, v);
1109 			break;
1110 		}
1111 		case DBUS_TYPE_INT32:
1112 		{
1113 			dbus_int32_t v;
1114 			dbus_message_iter_get_basic (&var_iter, &v);
1115 			HAL_INFO (("%s -> %d", key, v));
1116 			rc = hal_device_property_set_int (d, key, v);
1117 			break;
1118 		}
1119 		case DBUS_TYPE_UINT64:
1120 		{
1121 			dbus_uint64_t v;
1122 			dbus_message_iter_get_basic (&var_iter, &v);
1123 			HAL_INFO (("%s -> %lld", key, v));
1124 			rc = hal_device_property_set_uint64 (d, key, v);
1125 			break;
1126 		}
1127 		case DBUS_TYPE_DOUBLE:
1128 		{
1129 			double v;
1130 			dbus_message_iter_get_basic (&var_iter, &v);
1131 			HAL_INFO (("%s -> %g", key, v));
1132 			rc = hal_device_property_set_double (d, key, v);
1133 			break;
1134 		}
1135 		case DBUS_TYPE_BOOLEAN:
1136 		{
1137 			gboolean v;
1138 			dbus_message_iter_get_basic (&var_iter, &v);
1139 			HAL_INFO (("%s -> %s", key, v ? "True" : "False"));
1140 			rc = hal_device_property_set_bool (d, key, v);
1141 			break;
1142 		}
1143 		default:
1144 			/* TODO: error */
1145 			break;
1146 		}
1147 
1148 		/* TODO: error out on rc==FALSE? */
1149 
1150 		dbus_message_iter_next (&dict_iter);
1151 	}
1152 
1153 	device_property_atomic_update_end ();
1154 
1155 
1156 	reply = dbus_message_new_method_return (message);
1157 	if (reply == NULL)
1158 		DIE (("No memory"));
1159 
1160 	if (!dbus_connection_send (connection, reply, NULL))
1161 		DIE (("No memory"));
1162 
1163 	dbus_message_unref (reply);
1164 	return DBUS_HANDLER_RESULT_HANDLED;
1165 }
1166 
1167 
1168 /** Get a property on a device.
1169  *
1170  *  <pre>
1171  *  any Device.GetProperty(string key)
1172  *  string Device.GetPropertyString(string key)
1173  *  int Device.GetPropertyInteger(string key)
1174  *  bool Device.GetPropertyBoolean(string key)
1175  *  double Device.GetPropertyDouble(string key)
1176  *
1177  *    raises org.freedesktop.Hal.NoSuchDevice,
1178  *           org.freedesktop.Hal.NoSuchProperty
1179  *  </pre>
1180  *
1181  *  @param  connection          D-BUS connection
1182  *  @param  message             Message
1183  *  @return                     What to do with the message
1184  */
1185 DBusHandlerResult
1186 device_get_property (DBusConnection * connection, DBusMessage * message)
1187 {
1188 	DBusMessage *reply;
1189 	DBusMessageIter iter;
1190 	DBusError error;
1191 	HalDevice *d;
1192 	const char *udi;
1193 	char *key;
1194 	int type;
1195 	HalProperty *p;
1196 
1197 	udi = dbus_message_get_path (message);
1198 
1199 	HAL_TRACE (("entering, udi=%s", udi));
1200 
1201 	d = hal_device_store_find (hald_get_gdl (), udi);
1202 	if (d == NULL)
1203 		d = hal_device_store_find (hald_get_tdl (), udi);
1204 
1205 	if (d == NULL) {
1206 		raise_no_such_device (connection, message, udi);
1207 		return DBUS_HANDLER_RESULT_HANDLED;
1208 	}
1209 
1210 	dbus_error_init (&error);
1211 	if (!dbus_message_get_args (message, &error,
1212 				    DBUS_TYPE_STRING, &key,
1213 				    DBUS_TYPE_INVALID)) {
1214 		raise_syntax (connection, message, "GetProperty");
1215 		return DBUS_HANDLER_RESULT_HANDLED;
1216 	}
1217 
1218 	p = hal_device_property_find (d, key);
1219 	if (p == NULL) {
1220 		raise_no_such_property (connection, message, udi, key);
1221 		return DBUS_HANDLER_RESULT_HANDLED;
1222 	}
1223 
1224 	reply = dbus_message_new_method_return (message);
1225 	if (reply == NULL)
1226 		DIE (("No memory"));
1227 
1228 	dbus_message_iter_init_append (reply, &iter);
1229 
1230 	type = hal_property_get_type (p);
1231 	switch (type) {
1232 	case HAL_PROPERTY_TYPE_STRING:
1233 	{
1234 		const char *s;
1235 		s = hal_property_get_string (p);
1236 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &s);
1237 		break;
1238 	}
1239 	case HAL_PROPERTY_TYPE_INT32:
1240 	{
1241 		dbus_int32_t i;
1242 		i = hal_property_get_int (p);
1243 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
1244 		break;
1245 	}
1246 	case HAL_PROPERTY_TYPE_UINT64:
1247 	{
1248 		dbus_uint64_t ul;
1249 		ul = hal_property_get_uint64 (p);
1250 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &ul);
1251 		break;
1252 	}
1253 	case HAL_PROPERTY_TYPE_DOUBLE:
1254 	{
1255 		double d;
1256 		d = hal_property_get_double (p);
1257 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &d);
1258 		break;
1259 	}
1260 	case HAL_PROPERTY_TYPE_BOOLEAN:
1261 	{
1262 		dbus_bool_t b;
1263 		b = hal_property_get_bool (p);
1264 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
1265 		break;
1266 	}
1267 	case HAL_PROPERTY_TYPE_STRLIST:
1268 	{
1269 		GSList *l;
1270 		DBusMessageIter iter_array;
1271 
1272 		dbus_message_iter_open_container (&iter,
1273 						  DBUS_TYPE_ARRAY,
1274 						  DBUS_TYPE_STRING_AS_STRING,
1275 						  &iter_array);
1276 
1277 		for (l = hal_property_get_strlist (p); l != NULL; l = g_slist_next (l)) {
1278 			dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &(l->data));
1279 		}
1280 
1281 		dbus_message_iter_close_container (&iter, &iter_array);
1282 	}
1283 		break;
1284 
1285 	default:
1286 		HAL_WARNING (("Unknown property type %d", type));
1287 		break;
1288 	}
1289 
1290 	if (!dbus_connection_send (connection, reply, NULL))
1291 		DIE (("No memory"));
1292 
1293 	dbus_message_unref (reply);
1294 
1295 	return DBUS_HANDLER_RESULT_HANDLED;
1296 }
1297 
1298 
1299 /** Get the type of a property on a device.
1300  *
1301  *  <pre>
1302  *  int Device.GetPropertyType(string key)
1303  *
1304  *    raises org.freedesktop.Hal.NoSuchDevice,
1305  *           org.freedesktop.Hal.NoSuchProperty
1306  *  </pre>
1307  *
1308  *  @param  connection          D-BUS connection
1309  *  @param  message             Message
1310  *  @return                     What to do with the message
1311  */
1312 DBusHandlerResult
1313 device_get_property_type (DBusConnection * connection,
1314 			  DBusMessage * message)
1315 {
1316 	DBusMessage *reply;
1317 	DBusMessageIter iter;
1318 	DBusError error;
1319 	HalDevice *d;
1320 	const char *udi;
1321 	char *key;
1322 	HalProperty *p;
1323 	dbus_int32_t i;
1324 
1325 	udi = dbus_message_get_path (message);
1326 
1327 	HAL_TRACE (("entering, udi=%s", udi));
1328 
1329 	d = hal_device_store_find (hald_get_gdl (), udi);
1330 	if (d == NULL)
1331 		d = hal_device_store_find (hald_get_tdl (), udi);
1332 
1333 	if (d == NULL) {
1334 		raise_no_such_device (connection, message, udi);
1335 		return DBUS_HANDLER_RESULT_HANDLED;
1336 	}
1337 
1338 	dbus_error_init (&error);
1339 	if (!dbus_message_get_args (message, &error,
1340 				    DBUS_TYPE_STRING, &key,
1341 				    DBUS_TYPE_INVALID)) {
1342 		raise_syntax (connection, message, "GetPropertyType");
1343 		return DBUS_HANDLER_RESULT_HANDLED;
1344 	}
1345 
1346 	p = hal_device_property_find (d, key);
1347 	if (p == NULL) {
1348 		raise_no_such_property (connection, message, udi, key);
1349 		return DBUS_HANDLER_RESULT_HANDLED;
1350 	}
1351 
1352 	reply = dbus_message_new_method_return (message);
1353 	if (reply == NULL)
1354 		DIE (("No memory"));
1355 
1356 	i = hal_property_get_type (p);
1357 	dbus_message_iter_init_append (reply, &iter);
1358 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
1359 
1360 	if (!dbus_connection_send (connection, reply, NULL))
1361 		DIE (("No memory"));
1362 
1363 	dbus_message_unref (reply);
1364 
1365 	return DBUS_HANDLER_RESULT_HANDLED;
1366 }
1367 
1368 /** Set a property on a device.
1369  *
1370  *  <pre>
1371  *  void Device.SetProperty(string key, any value)
1372  *  void Device.SetPropertyString(string key, string value)
1373  *  void Device.SetPropertyInteger(string key, int value)
1374  *  void Device.SetPropertyBoolean(string key, bool value)
1375  *  void Device.SetPropertyDouble(string key, double value)
1376  *
1377  *    raises org.freedesktop.Hal.NoSuchDevice,
1378  *           org.freedesktop.Hal.NoSuchProperty
1379  *           org.freedesktop.Hal.TypeMismatch
1380  *  </pre>
1381  *
1382  *  @param  connection          D-BUS connection
1383  *  @param  message             Message
1384  *  @return                     What to do with the message
1385  */
1386 DBusHandlerResult
1387 device_set_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1388 {
1389 	const char *udi;
1390 	char *key;
1391 	int type;
1392 	dbus_bool_t rc;
1393 	HalDevice *device;
1394 	DBusMessageIter iter;
1395 	DBusMessage *reply;
1396 
1397 	HAL_TRACE (("entering"));
1398 
1399 	udi = dbus_message_get_path (message);
1400 
1401 	dbus_message_iter_init (message, &iter);
1402 	type = dbus_message_iter_get_arg_type (&iter);
1403 	if (type != DBUS_TYPE_STRING) {
1404 		raise_syntax (connection, message, "SetProperty");
1405 		return DBUS_HANDLER_RESULT_HANDLED;
1406 	}
1407 	dbus_message_iter_get_basic (&iter, &key);
1408 
1409 	if (!local_interface && !sender_has_privileges (connection, message)) {
1410 		raise_permission_denied (connection, message, "SetProperty: not privileged");
1411 		return DBUS_HANDLER_RESULT_HANDLED;
1412 	}
1413 
1414 	HAL_DEBUG (("udi=%s, key=%s", udi, key));
1415 
1416 	device = hal_device_store_find (hald_get_gdl (), udi);
1417 	if (device == NULL)
1418 		device = hal_device_store_find (hald_get_tdl (), udi);
1419 
1420 	if (device == NULL) {
1421 		raise_no_such_device (connection, message, udi);
1422 		return DBUS_HANDLER_RESULT_HANDLED;
1423 	}
1424 	dbus_message_iter_next (&iter);
1425 
1426 	/** @todo check permissions of the sender vs property to be modified */
1427 
1428 	type = dbus_message_iter_get_arg_type (&iter);
1429 	rc = FALSE;
1430 
1431 	switch (type) {
1432 	case DBUS_TYPE_STRING:
1433 	{
1434 		const char *v;
1435 		dbus_message_iter_get_basic (&iter, &v);
1436 		rc = hal_device_property_set_string (device, key, v);
1437 		break;
1438 	}
1439 	case DBUS_TYPE_INT32:
1440 	{
1441 		dbus_int32_t v;
1442 		dbus_message_iter_get_basic (&iter, &v);
1443 		rc = hal_device_property_set_int (device, key, v);
1444 		break;
1445 	}
1446 	case DBUS_TYPE_UINT64:
1447 	{
1448 		dbus_uint64_t v;
1449 		dbus_message_iter_get_basic (&iter, &v);
1450 		rc = hal_device_property_set_uint64 (device, key, v);
1451 		break;
1452 	}
1453 	case DBUS_TYPE_DOUBLE:
1454 	{
1455 		double v;
1456 		dbus_message_iter_get_basic (&iter, &v);
1457 		rc = hal_device_property_set_double (device, key, v);
1458 		break;
1459 	}
1460 	case DBUS_TYPE_BOOLEAN:
1461 	{
1462 		dbus_bool_t v;
1463 		dbus_message_iter_get_basic (&iter, &v);
1464 		rc = hal_device_property_set_bool (device, key, v);
1465 		break;
1466 	}
1467 	default:
1468 		HAL_WARNING (("Unsupported property type %d", type));
1469 		break;
1470 	}
1471 
1472 	if (!rc) {
1473 		raise_property_type_error (connection, message, udi, key);
1474 		return DBUS_HANDLER_RESULT_HANDLED;
1475 	}
1476 
1477 	reply = dbus_message_new_method_return (message);
1478 	if (reply == NULL)
1479 		DIE (("No memory"));
1480 
1481 	if (!dbus_connection_send (connection, reply, NULL))
1482 		DIE (("No memory"));
1483 
1484 	dbus_message_unref (reply);
1485 	return DBUS_HANDLER_RESULT_HANDLED;
1486 }
1487 
1488 /** This function is used to modify the Capabilities property. The reason
1489  *  for having a dedicated function is that the HAL daemon will broadcast
1490  *  a signal on the Manager interface to tell applications that the device
1491  *  have got a new capability.
1492  *
1493  *  This is useful as capabilities can be merged after the device is created.
1494  *  One example of this is networking cards under Linux 2.6; the net.ethernet
1495  *  capability is not merged when the device is initially found by looking in
1496  *  /sys/devices; it is merged when the /sys/classes tree is searched.
1497  *
1498  *  Note that the signal is emitted every time this method is invoked even
1499  *  though the capability already existed. This is useful in the above
1500  *  scenario when the PCI class says ethernet networking card but we yet
1501  *  don't have enough information to fill in the net.* and net.ethernet.*
1502  *  fields since this only happens when we visit the /sys/classes tree.
1503  *
1504  *  <pre>
1505  *  void Device.AddCapability(string capability)
1506  *
1507  *    raises org.freedesktop.Hal.NoSuchDevice,
1508  *    raises org.freedesktop.Hal.PermissionDenied,
1509  *  </pre>
1510  *
1511  *  @param  connection          D-BUS connection
1512  *  @param  message             Message
1513  *  @return                     What to do with the message
1514  */
1515 DBusHandlerResult
1516 device_add_capability (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1517 {
1518 	const char *udi;
1519 	const char *capability;
1520 	HalDevice *d;
1521 	DBusMessage *reply;
1522 	DBusError error;
1523 
1524 	HAL_TRACE (("entering"));
1525 
1526 	if (!local_interface && !sender_has_privileges (connection, message)) {
1527 		raise_permission_denied (connection, message, "AddCapability: not privileged");
1528 		return DBUS_HANDLER_RESULT_HANDLED;
1529 	}
1530 
1531 	udi = dbus_message_get_path (message);
1532 
1533 	d = hal_device_store_find (hald_get_gdl (), udi);
1534 	if (d == NULL)
1535 		d = hal_device_store_find (hald_get_tdl (), udi);
1536 
1537 	if (d == NULL) {
1538 		raise_no_such_device (connection, message, udi);
1539 		return DBUS_HANDLER_RESULT_HANDLED;
1540 	}
1541 
1542 	dbus_error_init (&error);
1543 	if (!dbus_message_get_args (message, &error,
1544 				    DBUS_TYPE_STRING, &capability,
1545 				    DBUS_TYPE_INVALID)) {
1546 		raise_syntax (connection, message, "AddCapability");
1547 		return DBUS_HANDLER_RESULT_HANDLED;
1548 	}
1549 
1550 
1551 	hal_device_add_capability (d, capability);
1552 
1553 	reply = dbus_message_new_method_return (message);
1554 	if (reply == NULL)
1555 		DIE (("No memory"));
1556 
1557 	if (!dbus_connection_send (connection, reply, NULL))
1558 		DIE (("No memory"));
1559 
1560 	dbus_message_unref (reply);
1561 	return DBUS_HANDLER_RESULT_HANDLED;
1562 }
1563 
1564 
1565 /* TODO: docs */
1566 static DBusHandlerResult
1567 device_string_list_append_prepend (DBusConnection * connection, DBusMessage * message, dbus_bool_t do_prepend)
1568 {
1569 	const char *udi;
1570 	const char *key;
1571 	const char *value;
1572 	HalDevice *d;
1573 	DBusMessage *reply;
1574 	DBusError error;
1575 	gboolean ret;
1576 
1577 	HAL_TRACE (("entering"));
1578 
1579 	udi = dbus_message_get_path (message);
1580 
1581 	d = hal_device_store_find (hald_get_gdl (), udi);
1582 	if (d == NULL)
1583 		d = hal_device_store_find (hald_get_tdl (), udi);
1584 
1585 	if (d == NULL) {
1586 		raise_no_such_device (connection, message, udi);
1587 		return DBUS_HANDLER_RESULT_HANDLED;
1588 	}
1589 
1590 	dbus_error_init (&error);
1591 	if (!dbus_message_get_args (message, &error,
1592 				    DBUS_TYPE_STRING, &key,
1593 				    DBUS_TYPE_STRING, &value,
1594 				    DBUS_TYPE_INVALID)) {
1595 		raise_syntax (connection, message, do_prepend ? "StringListPrepend" : "StringListAppend");
1596 		return DBUS_HANDLER_RESULT_HANDLED;
1597 	}
1598 
1599 	if (do_prepend)
1600 		ret = hal_device_property_strlist_prepend (d, key, value);
1601 	else
1602 		ret = hal_device_property_strlist_append (d, key, value);
1603 	if (!ret) {
1604 		raise_property_type_error (connection, message, udi, key);
1605 		return DBUS_HANDLER_RESULT_HANDLED;
1606 	}
1607 
1608 	reply = dbus_message_new_method_return (message);
1609 	if (reply == NULL)
1610 		DIE (("No memory"));
1611 
1612 	if (!dbus_connection_send (connection, reply, NULL))
1613 		DIE (("No memory"));
1614 
1615 	dbus_message_unref (reply);
1616 	return DBUS_HANDLER_RESULT_HANDLED;
1617 }
1618 
1619 /* TODO: docs */
1620 static DBusHandlerResult
1621 device_string_list_remove (DBusConnection * connection, DBusMessage * message)
1622 {
1623 	const char *udi;
1624 	const char *key;
1625 	const char *value;
1626 	HalDevice *d;
1627 	DBusMessage *reply;
1628 	DBusError error;
1629 	gboolean ret;
1630 
1631 	HAL_TRACE (("entering"));
1632 
1633 	udi = dbus_message_get_path (message);
1634 
1635 	d = hal_device_store_find (hald_get_gdl (), udi);
1636 	if (d == NULL)
1637 		d = hal_device_store_find (hald_get_tdl (), udi);
1638 
1639 	if (d == NULL) {
1640 		raise_no_such_device (connection, message, udi);
1641 		return DBUS_HANDLER_RESULT_HANDLED;
1642 	}
1643 
1644 	dbus_error_init (&error);
1645 	if (!dbus_message_get_args (message, &error,
1646 				    DBUS_TYPE_STRING, &key,
1647 				    DBUS_TYPE_STRING, &value,
1648 				    DBUS_TYPE_INVALID)) {
1649 		raise_syntax (connection, message, "StringListRemove");
1650 		return DBUS_HANDLER_RESULT_HANDLED;
1651 	}
1652 
1653 	ret = hal_device_property_strlist_remove (d, key, value);
1654 	if (!ret) {
1655 		raise_property_type_error (connection, message, udi, key);
1656 		return DBUS_HANDLER_RESULT_HANDLED;
1657 	}
1658 
1659 	reply = dbus_message_new_method_return (message);
1660 	if (reply == NULL)
1661 		DIE (("No memory"));
1662 
1663 	if (!dbus_connection_send (connection, reply, NULL))
1664 		DIE (("No memory"));
1665 
1666 	dbus_message_unref (reply);
1667 	return DBUS_HANDLER_RESULT_HANDLED;
1668 }
1669 
1670 
1671 
1672 /** Remove a property on a device.
1673  *
1674  *  <pre>
1675  *  void Device.RemoveProperty(string key)
1676  *
1677  *    raises org.freedesktop.Hal.NoSuchDevice,
1678  *           org.freedesktop.Hal.NoSuchProperty
1679  *           org.freedesktop.Hal.PermissionDenied
1680  *  </pre>
1681  *
1682  *  @param  connection          D-BUS connection
1683  *  @param  message             Message
1684  *  @return                     What to do with the message
1685  */
1686 DBusHandlerResult
1687 device_remove_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1688 {
1689 	const char *udi;
1690 	char *key;
1691 	HalDevice *d;
1692 	DBusMessage *reply;
1693 	DBusError error;
1694 
1695 	HAL_TRACE (("entering"));
1696 
1697 	udi = dbus_message_get_path (message);
1698 
1699 	if (!local_interface && !sender_has_privileges (connection, message)) {
1700 		raise_permission_denied (connection, message, "RemoveProperty: not privileged");
1701 		return DBUS_HANDLER_RESULT_HANDLED;
1702 	}
1703 
1704 	d = hal_device_store_find (hald_get_gdl (), udi);
1705 	if (d == NULL)
1706 		d = hal_device_store_find (hald_get_tdl (), udi);
1707 
1708 	if (d == NULL) {
1709 		raise_no_such_device (connection, message, udi);
1710 		return DBUS_HANDLER_RESULT_HANDLED;
1711 	}
1712 
1713 	dbus_error_init (&error);
1714 	if (!dbus_message_get_args (message, &error,
1715 				    DBUS_TYPE_STRING, &key,
1716 				    DBUS_TYPE_INVALID)) {
1717 		raise_syntax (connection, message, "RemoveProperty");
1718 		return DBUS_HANDLER_RESULT_HANDLED;
1719 	}
1720 
1721 	if (!hal_device_property_remove (d, key)) {
1722 		raise_no_such_property (connection, message, udi, key);
1723 		return DBUS_HANDLER_RESULT_HANDLED;
1724 	}
1725 
1726 
1727 	reply = dbus_message_new_method_return (message);
1728 	if (reply == NULL)
1729 		DIE (("No memory"));
1730 
1731 	if (!dbus_connection_send (connection, reply, NULL))
1732 		DIE (("No memory"));
1733 
1734 	dbus_message_unref (reply);
1735 	return DBUS_HANDLER_RESULT_HANDLED;
1736 }
1737 
1738 
1739 /** Determine if a property exists
1740  *
1741  *  <pre>
1742  *  bool Device.PropertyExists(string key)
1743  *
1744  *    raises org.freedesktop.Hal.NoSuchDevice,
1745  *  </pre>
1746  *
1747  *  @param  connection          D-BUS connection
1748  *  @param  message             Message
1749  *  @return                     What to do with the message
1750  */
1751 DBusHandlerResult
1752 device_property_exists (DBusConnection * connection, DBusMessage * message)
1753 {
1754 	const char *udi;
1755 	char *key;
1756 	HalDevice *d;
1757 	DBusMessage *reply;
1758 	DBusError error;
1759 	DBusMessageIter iter;
1760 	dbus_bool_t b;
1761 
1762 	HAL_TRACE (("entering"));
1763 
1764 	udi = dbus_message_get_path (message);
1765 
1766 	d = hal_device_store_find (hald_get_gdl (), udi);
1767 	if (d == NULL)
1768 		d = hal_device_store_find (hald_get_tdl (), udi);
1769 
1770 	if (d == NULL) {
1771 		raise_no_such_device (connection, message, udi);
1772 		return DBUS_HANDLER_RESULT_HANDLED;
1773 	}
1774 
1775 	dbus_error_init (&error);
1776 	if (!dbus_message_get_args (message, &error,
1777 				    DBUS_TYPE_STRING, &key,
1778 				    DBUS_TYPE_INVALID)) {
1779 		raise_syntax (connection, message, "RemoveProperty");
1780 		return DBUS_HANDLER_RESULT_HANDLED;
1781 	}
1782 
1783 	reply = dbus_message_new_method_return (message);
1784 	if (reply == NULL)
1785 		DIE (("No memory"));
1786 
1787 	b =  hal_device_has_property (d, key);
1788 	dbus_message_iter_init_append (reply, &iter);
1789 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
1790 
1791 	if (!dbus_connection_send (connection, reply, NULL))
1792 		DIE (("No memory"));
1793 
1794 	dbus_message_unref (reply);
1795 	return DBUS_HANDLER_RESULT_HANDLED;
1796 }
1797 
1798 
1799 /** Determine if a device has a capability
1800  *
1801  *  <pre>
1802  *  bool Device.QueryCapability(string capability_name)
1803  *
1804  *    raises org.freedesktop.Hal.NoSuchDevice,
1805  *  </pre>
1806  *
1807  *  @param  connection          D-BUS connection
1808  *  @param  message             Message
1809  *  @return                     What to do with the message
1810  */
1811 DBusHandlerResult
1812 device_query_capability (DBusConnection * connection,
1813 			 DBusMessage * message)
1814 {
1815 	dbus_bool_t rc;
1816 	const char *udi;
1817 	GSList *caps;
1818 	char *capability;
1819 	HalDevice *d;
1820 	DBusMessage *reply;
1821 	DBusError error;
1822 	DBusMessageIter iter;
1823 
1824 	HAL_TRACE (("entering"));
1825 
1826 	udi = dbus_message_get_path (message);
1827 
1828 	d = hal_device_store_find (hald_get_gdl (), udi);
1829 	if (d == NULL)
1830 		d = hal_device_store_find (hald_get_tdl (), udi);
1831 
1832 	if (d == NULL) {
1833 		raise_no_such_device (connection, message, udi);
1834 		return DBUS_HANDLER_RESULT_HANDLED;
1835 	}
1836 
1837 	dbus_error_init (&error);
1838 	if (!dbus_message_get_args (message, &error,
1839 				    DBUS_TYPE_STRING, &capability,
1840 				    DBUS_TYPE_INVALID)) {
1841 		raise_syntax (connection, message, "QueryCapability");
1842 		return DBUS_HANDLER_RESULT_HANDLED;
1843 	}
1844 
1845 	reply = dbus_message_new_method_return (message);
1846 	if (reply == NULL)
1847 		DIE (("No memory"));
1848 
1849 	rc = FALSE;
1850 	caps = hal_device_property_get_strlist (d, "info.capabilities");
1851 	if (caps != NULL) {
1852 		GSList *iter;
1853 
1854 		for (iter = caps; iter != NULL; iter=g_slist_next(iter)) {
1855 			if (strcmp (iter->data, capability) == 0) {
1856 				rc = TRUE;
1857 				break;
1858 			}
1859 		}
1860 	}
1861 
1862 	dbus_message_iter_init_append (reply, &iter);
1863 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rc);
1864 
1865 	if (!dbus_connection_send (connection, reply, NULL))
1866 		DIE (("No memory"));
1867 
1868 	dbus_message_unref (reply);
1869 	return DBUS_HANDLER_RESULT_HANDLED;
1870 }
1871 
1872 static GHashTable *services_with_locks = NULL;
1873 
1874 /** Grab an advisory lock on a device.
1875  *
1876  *  <pre>
1877  *  bool Device.Lock(string reason)
1878  *
1879  *    raises org.freedesktop.Hal.NoSuchDevice,
1880  *           org.freedesktop.Hal.DeviceAlreadyLocked
1881  *  </pre>
1882  *
1883  *  @param  connection          D-BUS connection
1884  *  @param  message             Message
1885  *  @return                     What to do with the message
1886  */
1887 DBusHandlerResult
1888 device_lock (DBusConnection * connection,
1889 	     DBusMessage * message)
1890 {
1891 	const char *udi;
1892 	HalDevice *d;
1893 	DBusMessage *reply;
1894 	dbus_bool_t already_locked;
1895 	DBusError error;
1896 	char *reason;
1897 	const char *sender;
1898 
1899 	HAL_TRACE (("entering"));
1900 
1901 	udi = dbus_message_get_path (message);
1902 
1903 	d = hal_device_store_find (hald_get_gdl (), udi);
1904 	if (d == NULL)
1905 		d = hal_device_store_find (hald_get_tdl (), udi);
1906 
1907 	if (d == NULL) {
1908 		raise_no_such_device (connection, message, udi);
1909 		return DBUS_HANDLER_RESULT_HANDLED;
1910 	}
1911 
1912 	already_locked = hal_device_property_get_bool (d, "info.locked");
1913 
1914 	if (already_locked) {
1915 		raise_device_already_locked (connection, message, d);
1916 		return DBUS_HANDLER_RESULT_HANDLED;
1917 	}
1918 
1919 	dbus_error_init (&error);
1920 	if (!dbus_message_get_args (message, &error,
1921 				    DBUS_TYPE_STRING, &reason,
1922 				    DBUS_TYPE_INVALID)) {
1923 		raise_syntax (connection, message, "Lock");
1924 		return DBUS_HANDLER_RESULT_HANDLED;
1925 	}
1926 
1927 	reply = dbus_message_new_method_return (message);
1928 	if (reply == NULL)
1929 		DIE (("No memory"));
1930 
1931 	sender = dbus_message_get_sender (message);
1932 
1933 	hal_device_property_set_bool (d, "info.locked", TRUE);
1934 	hal_device_property_set_string (d, "info.locked.reason", reason);
1935 	hal_device_property_set_string (d, "info.locked.dbus_name",
1936 					sender);
1937 
1938 	if (services_with_locks == NULL) {
1939 		services_with_locks =
1940 			g_hash_table_new_full (g_str_hash,
1941 					       g_str_equal,
1942 					       g_free,
1943 					       g_object_unref);
1944 	}
1945 
1946 	g_hash_table_insert (services_with_locks, g_strdup (sender),
1947 			     g_object_ref (d));
1948 
1949 	if (!dbus_connection_send (connection, reply, NULL))
1950 		DIE (("No memory"));
1951 
1952 	dbus_message_unref (reply);
1953 	return DBUS_HANDLER_RESULT_HANDLED;
1954 }
1955 
1956 /** Release an advisory lock on a device.
1957  *
1958  *  <pre>
1959  *  bool Device.Unlock()
1960  *
1961  *    raises org.freedesktop.Hal.NoSuchDevice,
1962  *           org.freedesktop.Hal.DeviceNotLocked,
1963  *           org.freedesktop.Hal.PermissionDenied
1964  *  </pre>
1965  *
1966  *  @param  connection          D-BUS connection
1967  *  @param  message             Message
1968  *  @return                     What to do with the message
1969  */
1970 DBusHandlerResult
1971 device_unlock (DBusConnection * connection,
1972 	       DBusMessage * message)
1973 {
1974 	dbus_bool_t rc;
1975 	const char *udi;
1976 	HalDevice *d;
1977 	DBusMessage *reply;
1978 	DBusError error;
1979 	const char *sender;
1980 
1981 	HAL_TRACE (("entering"));
1982 
1983 	udi = dbus_message_get_path (message);
1984 
1985 	d = hal_device_store_find (hald_get_gdl (), udi);
1986 	if (d == NULL)
1987 		d = hal_device_store_find (hald_get_tdl (), udi);
1988 
1989 	if (d == NULL) {
1990 		raise_no_such_device (connection, message, udi);
1991 		return DBUS_HANDLER_RESULT_HANDLED;
1992 	}
1993 
1994 	dbus_error_init (&error);
1995 	if (!dbus_message_get_args (message, &error,
1996 				    DBUS_TYPE_INVALID)) {
1997 		raise_syntax (connection, message, "Unlock");
1998 		return DBUS_HANDLER_RESULT_HANDLED;
1999 	}
2000 
2001 	reply = dbus_message_new_method_return (message);
2002 	if (reply == NULL)
2003 		DIE (("No memory"));
2004 
2005 	rc = hal_device_property_get_bool (d, "info.locked");
2006 
2007 	if (!rc) {
2008 		raise_device_not_locked (connection, message, d);
2009 		return DBUS_HANDLER_RESULT_HANDLED;
2010 	}
2011 
2012 	sender = dbus_message_get_sender (message);
2013 
2014 	if (strcmp (sender, hal_device_property_get_string (
2015 			    d, "info.locked.dbus_name")) != 0) {
2016 		char *reason;
2017 
2018 		reason = g_strdup_printf ("Service '%s' does not own the "
2019 					  "lock on %s", sender,
2020 					  hal_device_get_udi (d));
2021 
2022 		raise_permission_denied (connection, message, reason);
2023 
2024 		g_free (reason);
2025 
2026 		return DBUS_HANDLER_RESULT_HANDLED;
2027 	}
2028 
2029 	if (g_hash_table_lookup (services_with_locks, sender))
2030 		g_hash_table_remove (services_with_locks, sender);
2031 	else {
2032 		HAL_WARNING (("Service '%s' was not in the list of services "
2033 			      "with locks!", sender));
2034 	}
2035 
2036 	hal_device_property_remove (d, "info.locked");
2037 	hal_device_property_remove (d, "info.locked.reason");
2038 	hal_device_property_remove (d, "info.locked.dbus_name");
2039 
2040 	/* FIXME?  Pointless? */
2041 	if (!dbus_connection_send (connection, reply, NULL))
2042 		DIE (("No memory"));
2043 
2044 	dbus_message_unref (reply);
2045 	return DBUS_HANDLER_RESULT_HANDLED;
2046 }
2047 
2048 static GHashTable *services_with_claims = NULL;
2049 
2050 /** Claim a branch.
2051  *
2052  *  <pre>
2053  *  bool Manager.ClaimBranch(string udi, string claim_service)
2054  *  </pre>
2055  *
2056  *  @param  connection          D-BUS connection
2057  *  @param  message             Message
2058  *  @return                     What to do with the message
2059  */
2060 DBusHandlerResult
2061 manager_claim_branch (DBusConnection * connection, DBusMessage * message)
2062 {
2063 	DBusMessage *reply;
2064 	DBusMessageIter iter;
2065 	DBusError error;
2066 	HalDevice *d;
2067 	const char *udi;
2068 	const char *claim_service;
2069 	const char *sender;
2070 	dbus_bool_t already_claimed;
2071 	unsigned long uid;
2072 
2073 	dbus_error_init (&error);
2074 	if (!dbus_message_get_args (message, &error,
2075 				    DBUS_TYPE_STRING, &udi,
2076 				    DBUS_TYPE_STRING, &claim_service,
2077 				    DBUS_TYPE_INVALID)) {
2078 		raise_syntax (connection, message, "Manager.ClaimBranch");
2079 		return DBUS_HANDLER_RESULT_HANDLED;
2080 	}
2081 
2082 	HAL_TRACE (("entering, udi=%s", udi));
2083 
2084 	d = hal_device_store_find (hald_get_gdl (), udi);
2085 
2086 	if (d == NULL) {
2087 		raise_no_such_device (connection, message, udi);
2088 		return DBUS_HANDLER_RESULT_HANDLED;
2089 	}
2090 
2091 	already_claimed = hal_device_property_get_bool (d, "info.claimed");
2092 	if (already_claimed) {
2093 		raise_branch_already_claimed (connection, message, d);
2094 		return DBUS_HANDLER_RESULT_HANDLED;
2095 	}
2096 
2097 	reply = dbus_message_new_method_return (message);
2098 	if (reply == NULL)
2099 		DIE (("No memory"));
2100 
2101 	sender = dbus_message_get_sender (message);
2102 
2103 	dbus_error_init (&error);
2104 	uid = dbus_bus_get_unix_user (connection, sender, &error);
2105 	if (uid == (unsigned long) -1 || dbus_error_is_set (&error)) {
2106 		HAL_WARNING (("Could not get uid for connection: %s %s", error.name, error.message));
2107 		dbus_error_free (&error);
2108 		dbus_message_unref (reply);
2109 		raise_no_such_device (connection, message, udi);
2110 		return DBUS_HANDLER_RESULT_HANDLED;
2111 	}
2112 
2113 	hal_util_branch_claim (hald_get_gdl (), d, TRUE, claim_service, uid);
2114 	hal_device_property_set_string (d, "info.claimed.dbus_name", sender);
2115 
2116 	if (services_with_claims == NULL) {
2117 		services_with_claims =
2118 			g_hash_table_new_full (g_str_hash,
2119 					       g_str_equal,
2120 					       g_free,
2121 					       g_object_unref);
2122 	}
2123 
2124 	g_hash_table_insert (services_with_claims, g_strdup (sender),
2125 			     g_object_ref (d));
2126 
2127 	if (!dbus_connection_send (connection, reply, NULL))
2128 		DIE (("No memory"));
2129 
2130 	dbus_message_unref (reply);
2131 	return DBUS_HANDLER_RESULT_HANDLED;
2132 }
2133 
2134 /** Unclaim a branch.
2135  *
2136  *  <pre>
2137  *  bool Manager.UnclaimBranch(string udi)
2138  *  </pre>
2139  *
2140  *  @param  connection          D-BUS connection
2141  *  @param  message             Message
2142  *  @return                     What to do with the message
2143  */
2144 DBusHandlerResult
2145 manager_unclaim_branch (DBusConnection * connection, DBusMessage * message)
2146 {
2147 	DBusMessage *reply;
2148 	DBusMessageIter iter;
2149 	DBusError error;
2150 	HalDevice *d;
2151 	const char *udi;
2152 	const char *claim_service;
2153 	const char *sender;
2154 	dbus_bool_t already_claimed;
2155 
2156 	dbus_error_init (&error);
2157 	if (!dbus_message_get_args (message, &error,
2158 				    DBUS_TYPE_STRING, &udi,
2159 				    DBUS_TYPE_INVALID)) {
2160 		raise_syntax (connection, message, "Manager.UnclaimBranch");
2161 		return DBUS_HANDLER_RESULT_HANDLED;
2162 	}
2163 
2164 	HAL_TRACE (("entering, udi=%s", udi));
2165 
2166 	d = hal_device_store_find (hald_get_gdl (), udi);
2167 
2168 	if (d == NULL) {
2169 		raise_no_such_device (connection, message, udi);
2170 		return DBUS_HANDLER_RESULT_HANDLED;
2171 	}
2172 
2173 	already_claimed = hal_device_property_get_bool (d, "info.claimed");
2174 	if (!already_claimed) {
2175 		raise_branch_not_claimed (connection, message, d);
2176 		return DBUS_HANDLER_RESULT_HANDLED;
2177 	}
2178 
2179 	reply = dbus_message_new_method_return (message);
2180 	if (reply == NULL)
2181 		DIE (("No memory"));
2182 
2183 	if (strcmp (sender, hal_device_property_get_string (
2184 			    d, "info.claimed.dbus_name")) != 0) {
2185 		char *reason;
2186 
2187 		reason = g_strdup_printf ("Service '%s' does not own the "
2188 					  "claim on %s", sender,
2189 					  hal_device_get_udi (d));
2190 
2191 		raise_permission_denied (connection, message, reason);
2192 
2193 		g_free (reason);
2194 
2195 		return DBUS_HANDLER_RESULT_HANDLED;
2196 	}
2197 
2198 	if (g_hash_table_lookup (services_with_claims, sender))
2199 		g_hash_table_remove (services_with_claims, sender);
2200 	else {
2201 		HAL_WARNING (("Service '%s' was not in the list of services "
2202 			      "with claims!", sender));
2203 	}
2204 
2205 	hal_util_branch_claim (hald_get_gdl (), d, FALSE, NULL, 0);
2206 	hal_device_property_remove (d, "info.claimed.dbus_name");
2207 
2208 	if (!dbus_connection_send (connection, reply, NULL))
2209 		DIE (("No memory"));
2210 
2211 	dbus_message_unref (reply);
2212 	return DBUS_HANDLER_RESULT_HANDLED;
2213 }
2214 
2215 
2216 /** Counter for atomic updating */
2217 static int atomic_count = 0;
2218 
2219 /** Number of updates pending */
2220 static int num_pending_updates = 0;
2221 
2222 /** Structure for queing updates */
2223 typedef struct PendingUpdate_s {
2224 	char *udi;                    /**< udi of device */
2225 	char *key;                    /**< key of property; free when done */
2226 	dbus_bool_t removed;          /**< true iff property was removed */
2227 	dbus_bool_t added;            /**< true iff property was added */
2228 	struct PendingUpdate_s *next; /**< next update or #NULL */
2229 } PendingUpdate;
2230 
2231 static PendingUpdate *pending_updates_head = NULL;
2232 
2233 /** Begin an atomic update - this is useful for updating several properties
2234  *  in one go.
2235  *
2236  *  Note that an atomic update is recursive - use with caution!
2237  */
2238 void
2239 device_property_atomic_update_begin (void)
2240 {
2241 	atomic_count++;
2242 }
2243 
2244 /** End an atomic update.
2245  *
2246  *  Note that an atomic update is recursive - use with caution!
2247  */
2248 void
2249 device_property_atomic_update_end (void)
2250 {
2251 	PendingUpdate *pu_iter = NULL;
2252 	PendingUpdate *pu_iter_next = NULL;
2253 	PendingUpdate *pu_iter2 = NULL;
2254 
2255 	--atomic_count;
2256 
2257 	if (atomic_count < 0) {
2258 		HAL_WARNING (("*** atomic_count = %d < 0 !!", atomic_count));
2259 		atomic_count = 0;
2260 	}
2261 
2262 	if (atomic_count == 0 && num_pending_updates > 0) {
2263 		DBusMessage *message;
2264 		DBusMessageIter iter;
2265 		DBusMessageIter iter_array;
2266 
2267 		for (pu_iter = pending_updates_head;
2268 		     pu_iter != NULL; pu_iter = pu_iter_next) {
2269 			int num_updates_this;
2270 
2271 			pu_iter_next = pu_iter->next;
2272 
2273 			/* see if we've already processed this */
2274 			if (pu_iter->udi == NULL)
2275 				goto already_processed;
2276 
2277 			/* count number of updates for this device */
2278 			num_updates_this = 0;
2279 			for (pu_iter2 = pu_iter; pu_iter2 != NULL; pu_iter2 = pu_iter2->next) {
2280 				if (strcmp (pu_iter2->udi, pu_iter->udi) == 0)
2281 					num_updates_this++;
2282 			}
2283 
2284 			/* prepare message */
2285 			message = dbus_message_new_signal (pu_iter->udi,
2286 							   "org.freedesktop.Hal.Device",
2287 							   "PropertyModified");
2288 			dbus_message_iter_init_append (message, &iter);
2289 			dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32,
2290 							&num_updates_this);
2291 
2292 			dbus_message_iter_open_container (&iter,
2293 							  DBUS_TYPE_ARRAY,
2294 							  DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2295 							  DBUS_TYPE_STRING_AS_STRING
2296 							  DBUS_TYPE_BOOLEAN_AS_STRING
2297 							  DBUS_TYPE_BOOLEAN_AS_STRING
2298 							  DBUS_STRUCT_END_CHAR_AS_STRING,
2299 							  &iter_array);
2300 
2301 			for (pu_iter2 = pu_iter; pu_iter2 != NULL;
2302 			     pu_iter2 = pu_iter2->next) {
2303 				if (strcmp (pu_iter2->udi, pu_iter->udi) == 0) {
2304 					DBusMessageIter iter_struct;
2305 					dbus_message_iter_open_container (&iter_array,
2306 									  DBUS_TYPE_STRUCT,
2307 									  NULL,
2308 									  &iter_struct);
2309 					dbus_message_iter_append_basic
2310 					    (&iter_struct,
2311 					     DBUS_TYPE_STRING,
2312 					     &(pu_iter2->key));
2313 					dbus_message_iter_append_basic
2314 					    (&iter_struct,
2315 					     DBUS_TYPE_BOOLEAN,
2316 					     &(pu_iter2->removed));
2317 					dbus_message_iter_append_basic
2318 					    (&iter_struct,
2319 					     DBUS_TYPE_BOOLEAN,
2320 					     &(pu_iter2->added));
2321 
2322 					dbus_message_iter_close_container (&iter_array, &iter_struct);
2323 
2324 					/* signal this is already processed */
2325 					g_free (pu_iter2->key);
2326 					if (pu_iter2 != pu_iter) {
2327 						g_free (pu_iter2->udi);
2328 						pu_iter2->udi = NULL;
2329 					}
2330 				}
2331 			}
2332 
2333 			g_free (pu_iter->udi);
2334 			dbus_message_iter_close_container (&iter, &iter_array);
2335 
2336 			if (dbus_connection != NULL) {
2337 				if (!dbus_connection_send (dbus_connection, message, NULL))
2338 					DIE (("error broadcasting message"));
2339 			}
2340 
2341 			dbus_message_unref (message);
2342 
2343 		already_processed:
2344 			g_free (pu_iter);
2345 
2346 		} /* for all updates */
2347 
2348 		num_pending_updates = 0;
2349 		pending_updates_head = NULL;
2350 	}
2351 }
2352 
2353 
2354 
2355 void
2356 device_send_signal_property_modified (HalDevice *device, const char *key,
2357 				      dbus_bool_t added, dbus_bool_t removed)
2358 {
2359 	const char *udi = hal_device_get_udi (device);
2360 	DBusMessage *message;
2361 	DBusMessageIter iter;
2362 
2363 /*
2364     HAL_INFO(("Entering, udi=%s, key=%s, in_gdl=%s, removed=%s added=%s",
2365               device->udi, key,
2366               in_gdl ? "true" : "false",
2367               removed ? "true" : "false",
2368               added ? "true" : "false"));
2369 */
2370 
2371 	if (atomic_count > 0) {
2372 		PendingUpdate *pu;
2373 
2374 		pu = g_new0 (PendingUpdate, 1);
2375 		pu->udi = g_strdup (udi);
2376 		pu->key = g_strdup (key);
2377 		pu->removed = removed;
2378 		pu->added = added;
2379 		pu->next = pending_updates_head;
2380 
2381 		pending_updates_head = pu;
2382 		num_pending_updates++;
2383 	} else {
2384 		dbus_int32_t i;
2385 		DBusMessageIter iter_struct;
2386 		DBusMessageIter iter_array;
2387 
2388 		if (dbus_connection == NULL)
2389 			goto out;
2390 
2391 		message = dbus_message_new_signal (udi,
2392 						  "org.freedesktop.Hal.Device",
2393 						   "PropertyModified");
2394 
2395 		dbus_message_iter_init_append (message, &iter);
2396 		i = 1;
2397 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
2398 
2399 		dbus_message_iter_open_container (&iter,
2400 						  DBUS_TYPE_ARRAY,
2401 						  DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2402 						  DBUS_TYPE_STRING_AS_STRING
2403 						  DBUS_TYPE_BOOLEAN_AS_STRING
2404 						  DBUS_TYPE_BOOLEAN_AS_STRING
2405 						  DBUS_STRUCT_END_CHAR_AS_STRING,
2406 						  &iter_array);
2407 
2408 		dbus_message_iter_open_container (&iter_array,
2409 						  DBUS_TYPE_STRUCT,
2410 						  NULL,
2411 						  &iter_struct);
2412 
2413 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &key);
2414 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &removed);
2415 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &added);
2416 
2417 		dbus_message_iter_close_container (&iter_array, &iter_struct);
2418 		dbus_message_iter_close_container (&iter, &iter_array);
2419 
2420 		if (!dbus_connection_send (dbus_connection, message, NULL))
2421 			DIE (("error broadcasting message"));
2422 
2423 		dbus_message_unref (message);
2424 	}
2425 out:
2426 	;
2427 }
2428 
2429 /** Emits a condition on a device; the device has to be in the GDL for
2430  *  this function to have effect.
2431  *
2432  *  Is intended for non-continuous events on the device like
2433  *  ProcesserOverheating, BlockDeviceGotDevice, e.g. conditions that
2434  *  are exceptional and may not be inferred by looking at properties
2435  *  (though some may).
2436  *
2437  *  This function accepts a number of parameters that are passed along
2438  *  in the D-BUS message. The recipient is supposed to extract the parameters
2439  *  himself, by looking at the HAL specification.
2440  *
2441  * @param  udi                  The UDI for this device
2442  * @param  condition_name       Name of condition
2443  * @param  first_arg_type       Type of the first argument
2444  * @param  ...                  value of first argument, list of additional
2445  *                              type-value pairs. Must be terminated with
2446  *                              DBUS_TYPE_INVALID
2447  */
2448 void
2449 device_send_signal_condition (HalDevice *device, const char *condition_name, const char *condition_details)
2450 {
2451 	const char *udi = hal_device_get_udi (device);
2452 	DBusMessage *message;
2453 	DBusMessageIter iter;
2454 
2455 	if (dbus_connection == NULL)
2456 		goto out;
2457 
2458 	message = dbus_message_new_signal (udi,
2459 					   "org.freedesktop.Hal.Device",
2460 					   "Condition");
2461 	dbus_message_iter_init_append (message, &iter);
2462 	dbus_message_iter_append_basic (&iter,
2463 					DBUS_TYPE_STRING,
2464 					&condition_name);
2465 	dbus_message_iter_append_basic (&iter,
2466 					DBUS_TYPE_STRING,
2467 					&condition_details);
2468 
2469 	if (!dbus_connection_send (dbus_connection, message, NULL))
2470 		DIE (("error broadcasting message"));
2471 
2472 	dbus_message_unref (message);
2473 out:
2474 	return;
2475 }
2476 
2477 
2478 
2479 static gboolean
2480 reinit_dbus (gpointer user_data)
2481 {
2482 	HAL_INFO (("entering!"));
2483 	if (hald_dbus_init ())
2484 		return FALSE;
2485 	else
2486 		return TRUE;
2487 }
2488 
2489 static void
2490 service_deleted (DBusMessage *message)
2491 {
2492 	char *old_service_name;
2493 	char *new_service_name;
2494 	HalDevice *d;
2495 
2496 	if (!dbus_message_get_args (message, NULL,
2497 				    DBUS_TYPE_STRING, &old_service_name,
2498 				    DBUS_TYPE_STRING, &new_service_name,
2499 				    DBUS_TYPE_INVALID)) {
2500 		HAL_ERROR (("Invalid NameOwnerChanged signal from bus!"));
2501 		return;
2502 	}
2503 
2504 	if (services_with_locks != NULL) {
2505 		d = g_hash_table_lookup (services_with_locks, new_service_name);
2506 
2507 		if (d != NULL) {
2508 			hal_device_property_remove (d, "info.locked");
2509 			hal_device_property_remove (d, "info.locked.reason");
2510 			hal_device_property_remove (d, "info.locked.dbus_name");
2511 
2512 			g_hash_table_remove (services_with_locks, new_service_name);
2513 		}
2514 	}
2515 
2516 	if (services_with_claims != NULL) {
2517 		d = g_hash_table_lookup (services_with_claims, new_service_name);
2518 
2519 		if (d != NULL) {
2520 			hal_util_branch_claim (hald_get_gdl (), d, FALSE, NULL, 0);
2521 			hal_device_property_remove (d, "info.claimed.dbus_name");
2522 
2523 			g_hash_table_remove (services_with_claims, new_service_name);
2524 		}
2525 	}
2526 }
2527 
2528 static DBusHandlerResult
2529 device_rescan (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2530 {
2531 	const char *udi;
2532 	HalDevice *device;
2533 	DBusMessage *reply;
2534 	DBusMessageIter iter;
2535 	gboolean res;
2536 
2537 	HAL_INFO (("entering, local_interface=%d", local_interface));
2538 
2539 	udi = dbus_message_get_path (message);
2540 
2541 	if (!local_interface && !sender_has_privileges (connection, message)) {
2542 		raise_permission_denied (connection, message, "Rescan: not privileged");
2543 		return DBUS_HANDLER_RESULT_HANDLED;
2544 	}
2545 
2546 	HAL_DEBUG (("udi=%s", udi));
2547 
2548 	device = hal_device_store_find (hald_get_gdl (), udi);
2549 	if (device == NULL)
2550 		device = hal_device_store_find (hald_get_tdl (), udi);
2551 
2552 	if (device == NULL) {
2553 		raise_no_such_device (connection, message, udi);
2554 		return DBUS_HANDLER_RESULT_HANDLED;
2555 	}
2556 
2557 	res = osspec_device_rescan (device);
2558 
2559 	reply = dbus_message_new_method_return (message);
2560 	if (reply == NULL)
2561 		DIE (("No memory"));
2562 	dbus_message_iter_init_append (reply, &iter);
2563 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2564 
2565 	if (!dbus_connection_send (connection, reply, NULL))
2566 		DIE (("No memory"));
2567 
2568 	dbus_message_unref (reply);
2569 	return DBUS_HANDLER_RESULT_HANDLED;
2570 }
2571 
2572 static DBusHandlerResult
2573 device_reprobe (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2574 {
2575 	const char *udi;
2576 	HalDevice *device;
2577 	DBusMessageIter iter;
2578 	DBusMessage *reply;
2579 	gboolean res;
2580 
2581 	HAL_TRACE (("entering"));
2582 
2583 	udi = dbus_message_get_path (message);
2584 
2585 	if (!local_interface && !sender_has_privileges (connection, message)) {
2586 		raise_permission_denied (connection, message, "Reprobe: not privileged");
2587 		return DBUS_HANDLER_RESULT_HANDLED;
2588 	}
2589 
2590 	HAL_DEBUG (("udi=%s", udi));
2591 
2592 	device = hal_device_store_find (hald_get_gdl (), udi);
2593 	if (device == NULL)
2594 		device = hal_device_store_find (hald_get_tdl (), udi);
2595 
2596 	if (device == NULL) {
2597 		raise_no_such_device (connection, message, udi);
2598 		return DBUS_HANDLER_RESULT_HANDLED;
2599 	}
2600 
2601 	res = osspec_device_reprobe (device);
2602 
2603 	reply = dbus_message_new_method_return (message);
2604 	if (reply == NULL)
2605 		DIE (("No memory"));
2606 	dbus_message_iter_init_append (reply, &iter);
2607 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2608 
2609 	if (!dbus_connection_send (connection, reply, NULL))
2610 		DIE (("No memory"));
2611 
2612 	dbus_message_unref (reply);
2613 	return DBUS_HANDLER_RESULT_HANDLED;
2614 }
2615 
2616 
2617 static DBusHandlerResult
2618 device_emit_condition (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2619 {
2620 	const char *udi;
2621 	HalDevice *device;
2622 	DBusMessageIter iter;
2623 	DBusMessage *reply;
2624 	DBusError error;
2625 	const char *condition_name;
2626 	const char *condition_details;
2627 	dbus_bool_t res;
2628 
2629 	HAL_TRACE (("entering"));
2630 
2631 	udi = dbus_message_get_path (message);
2632 
2633 	if (!local_interface) {
2634 		raise_permission_denied (connection, message, "EmitCondition: only allowed for helpers");
2635 		return DBUS_HANDLER_RESULT_HANDLED;
2636 	}
2637 
2638 	HAL_DEBUG (("udi=%s", udi));
2639 
2640 	dbus_error_init (&error);
2641 	if (!dbus_message_get_args (message, &error,
2642 				    DBUS_TYPE_STRING, &condition_name,
2643 				    DBUS_TYPE_STRING, &condition_details,
2644 				    DBUS_TYPE_INVALID)) {
2645 		raise_syntax (connection, message, "EmitCondition");
2646 		return DBUS_HANDLER_RESULT_HANDLED;
2647 	}
2648 
2649 
2650 	device = hal_device_store_find (hald_get_gdl (), udi);
2651 	if (device == NULL)
2652 		device = hal_device_store_find (hald_get_tdl (), udi);
2653 
2654 	if (device == NULL) {
2655 		raise_no_such_device (connection, message, udi);
2656 		return DBUS_HANDLER_RESULT_HANDLED;
2657 	}
2658 
2659 	device_send_signal_condition (device, condition_name, condition_details);
2660 
2661 	res = TRUE;
2662 
2663 	reply = dbus_message_new_method_return (message);
2664 	if (reply == NULL)
2665 		DIE (("No memory"));
2666 	dbus_message_iter_init_append (reply, &iter);
2667 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2668 
2669 	if (!dbus_connection_send (connection, reply, NULL))
2670 		DIE (("No memory"));
2671 
2672 	dbus_message_unref (reply);
2673 	return DBUS_HANDLER_RESULT_HANDLED;
2674 }
2675 
2676 typedef struct
2677 {
2678 	DBusConnection  *connection;
2679 	char            *interface_name;
2680 	char            *introspection_xml;
2681 	char            *udi;
2682 } HelperInterfaceHandler;
2683 
2684 static GSList *helper_interface_handlers = NULL;
2685 
2686 static DBusHandlerResult
2687 device_claim_interface (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2688 {
2689 	const char *udi;
2690 	HalDevice *device;
2691 	DBusMessageIter iter;
2692 	DBusMessage *reply;
2693 	DBusError error;
2694 	const char *interface_name;
2695 	const char *introspection_xml;
2696 	dbus_bool_t res;
2697 
2698 	HAL_TRACE (("entering"));
2699 
2700 	udi = dbus_message_get_path (message);
2701 
2702 	if (!local_interface) {
2703 		raise_permission_denied (connection, message, "ClaimInterface: only allowed for helpers");
2704 		return DBUS_HANDLER_RESULT_HANDLED;
2705 	}
2706 
2707 	HAL_DEBUG (("udi=%s", udi));
2708 
2709 	dbus_error_init (&error);
2710 	if (!dbus_message_get_args (message, &error,
2711 				    DBUS_TYPE_STRING, &interface_name,
2712 				    DBUS_TYPE_STRING, &introspection_xml,
2713 				    DBUS_TYPE_INVALID)) {
2714 		raise_syntax (connection, message, "ClaimInterface");
2715 		return DBUS_HANDLER_RESULT_HANDLED;
2716 	}
2717 
2718 	device = hal_device_store_find (hald_get_gdl (), udi);
2719 	if (device == NULL)
2720 		device = hal_device_store_find (hald_get_tdl (), udi);
2721 
2722 	if (device == NULL) {
2723 		raise_no_such_device (connection, message, udi);
2724 		return DBUS_HANDLER_RESULT_HANDLED;
2725 	}
2726 
2727 	res = TRUE;
2728 
2729 	HAL_INFO (("Local connection 0x%x to handle interface '%s' on udi '%s'",
2730 		   connection,
2731 		   interface_name,
2732 		   udi));
2733 
2734 	hal_device_property_strlist_add (device, "info.interfaces", interface_name);
2735 
2736 	HelperInterfaceHandler *hih = g_new0 (HelperInterfaceHandler, 1);
2737 	hih->connection = connection;
2738 	hih->interface_name = g_strdup (interface_name);
2739 	hih->introspection_xml = g_strdup (introspection_xml);
2740 	hih->udi = g_strdup (udi);
2741 	helper_interface_handlers = g_slist_append (helper_interface_handlers, hih);
2742 
2743 
2744 	reply = dbus_message_new_method_return (message);
2745 	if (reply == NULL)
2746 		DIE (("No memory"));
2747 	dbus_message_iter_init_append (reply, &iter);
2748 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2749 
2750 	if (!dbus_connection_send (connection, reply, NULL))
2751 		DIE (("No memory"));
2752 
2753 	dbus_message_unref (reply);
2754 	return DBUS_HANDLER_RESULT_HANDLED;
2755 }
2756 
2757 
2758 
2759 static DBusHandlerResult
2760 addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2761 {
2762 	const char *udi;
2763 	HalDevice *device;
2764 	DBusMessageIter iter;
2765 	DBusMessage *reply;
2766 	DBusError error;
2767 	dbus_bool_t res;
2768 
2769 	HAL_TRACE (("entering"));
2770 
2771 	udi = dbus_message_get_path (message);
2772 
2773 	if (!local_interface) {
2774 		raise_permission_denied (connection, message, "AddonIsReady: only allowed for helpers");
2775 		return DBUS_HANDLER_RESULT_HANDLED;
2776 	}
2777 
2778 	HAL_DEBUG (("udi=%s", udi));
2779 
2780 	dbus_error_init (&error);
2781 	if (!dbus_message_get_args (message, &error,
2782 				    DBUS_TYPE_INVALID)) {
2783 		raise_syntax (connection, message, "AddonIsReady");
2784 		return DBUS_HANDLER_RESULT_HANDLED;
2785 	}
2786 
2787 	device = hal_device_store_find (hald_get_gdl (), udi);
2788 	if (device == NULL)
2789 		device = hal_device_store_find (hald_get_tdl (), udi);
2790 
2791 	if (device == NULL) {
2792 		raise_no_such_device (connection, message, udi);
2793 		return DBUS_HANDLER_RESULT_HANDLED;
2794 	}
2795 
2796 	if (hal_device_inc_num_ready_addons (device)) {
2797 		if (hal_device_are_all_addons_ready (device)) {
2798 			manager_send_signal_device_added (device);
2799 		}
2800 	}
2801 
2802 	res = TRUE;
2803 
2804 	HAL_INFO (("AddonIsReady on udi '%s'", udi));
2805 
2806 	reply = dbus_message_new_method_return (message);
2807 	if (reply == NULL)
2808 		DIE (("No memory"));
2809 	dbus_message_iter_init_append (reply, &iter);
2810 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2811 
2812 	if (!dbus_connection_send (connection, reply, NULL))
2813 		DIE (("No memory"));
2814 
2815 	dbus_message_unref (reply);
2816 	return DBUS_HANDLER_RESULT_HANDLED;
2817 }
2818 
2819 
2820 /*
2821  * Create new device in tdl. Return temporary udi.
2822  */
2823 DBusHandlerResult
2824 manager_new_device (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2825 {
2826 	DBusMessage *reply;
2827 	DBusMessageIter iter;
2828 	DBusError error;
2829 	HalDevice *d;
2830 	gchar *udi;
2831 	int i;
2832 	struct timeval tv;
2833 
2834 	dbus_error_init (&error);
2835 
2836 	if (!local_interface && !sender_has_privileges (connection, message)) {
2837 		raise_permission_denied (connection, message, "NewDevice: not privileged");
2838 		return DBUS_HANDLER_RESULT_HANDLED;
2839 	}
2840 
2841 	reply = dbus_message_new_method_return (message);
2842 	if (reply == NULL)
2843 		DIE (("No memory"));
2844 
2845 	dbus_message_iter_init_append (reply, &iter);
2846 	d = hal_device_new ();
2847 
2848 	gettimeofday(&tv, NULL);
2849 	for (i = 0; i < 1000000 ; i++) {
2850 		udi = g_strdup_printf ("/org/freedesktop/Hal/devices/tmp%05x", ((unsigned) tv.tv_usec & 0xfffff)) + i;
2851 		if (!hal_device_store_find (hald_get_tdl (), udi)) break;
2852 		g_free (udi);
2853 		udi = NULL;
2854 	}
2855 
2856 	if (!udi) {
2857 		raise_error (connection, message, "org.freedesktop.Hal.NoSpace", "NewDevice: no space for device");
2858 		return DBUS_HANDLER_RESULT_HANDLED;
2859 	}
2860 
2861 	hal_device_set_udi (d, udi);
2862 	hal_device_property_set_string (d, "info.udi", udi);
2863 	hal_device_store_add (hald_get_tdl (), d);
2864 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
2865 	g_free (udi);
2866 
2867 	if (!dbus_connection_send (connection, reply, NULL))
2868 		DIE (("No memory"));
2869 
2870 	dbus_message_unref (reply);
2871 
2872 	return DBUS_HANDLER_RESULT_HANDLED;
2873 }
2874 
2875 
2876 /*
2877  * Callout helper.
2878  */
2879 static void
2880 manager_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2881 {
2882 	HAL_INFO (("Remove callouts completed udi=%s", d->udi));
2883 
2884 	if (!hal_device_store_remove (hald_get_gdl (), d)) {
2885 		HAL_WARNING (("Error removing device"));
2886 	}
2887 }
2888 
2889 
2890 /*
2891  * Remove device. Looks in gdl and tdl.
2892  */
2893 DBusHandlerResult
2894 manager_remove (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2895 {
2896 	DBusMessage *reply;
2897 	DBusMessageIter iter;
2898 	DBusError error;
2899 	HalDevice *d;
2900 	char *udi;
2901 	int in_tdl = 0;
2902 
2903 	dbus_error_init (&error);
2904 
2905 	if (!local_interface && !sender_has_privileges (connection, message)) {
2906 		raise_permission_denied (connection, message, "Remove: not privileged");
2907 		return DBUS_HANDLER_RESULT_HANDLED;
2908 	}
2909 
2910 	if (!dbus_message_get_args (message, &error,
2911 				    DBUS_TYPE_STRING, &udi,
2912 				    DBUS_TYPE_INVALID)) {
2913 		raise_syntax (connection, message, "Remove");
2914 		return DBUS_HANDLER_RESULT_HANDLED;
2915 	}
2916 
2917 	reply = dbus_message_new_method_return (message);
2918 	if (reply == NULL)
2919 		DIE (("No memory"));
2920 
2921 	dbus_message_iter_init_append (reply, &iter);
2922 
2923 	d = hal_device_store_find (hald_get_gdl (), udi);
2924 	if (d == NULL) {
2925 		hal_device_store_find (hald_get_tdl (), udi);
2926 		in_tdl = 1;
2927 	}
2928 	if (d == NULL) {
2929 		raise_no_such_device (connection, message, udi);
2930 		return DBUS_HANDLER_RESULT_HANDLED;
2931 	}
2932 
2933 	/* FIXME:
2934 	 * run "info.callouts.remove" ?
2935 	 * delete in gdl ?
2936 	 * (auto) stop "info.addons" ?
2937 	 */
2938 
2939 	if (!in_tdl) {
2940 		hal_util_callout_device_remove (d, manager_remove_done, NULL, NULL);
2941 	}
2942 
2943 	hal_device_store_remove (in_tdl ? hald_get_tdl () : hald_get_gdl (), d);
2944 	g_object_unref (d);
2945 
2946 	if (!dbus_connection_send (connection, reply, NULL))
2947 		DIE (("No memory"));
2948 
2949 	dbus_message_unref (reply);
2950 
2951 	return DBUS_HANDLER_RESULT_HANDLED;
2952 }
2953 
2954 
2955 /*
2956  * Callout helper.
2957  */
2958 static void
2959 manager_commit_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2960 {
2961 	HAL_INFO (("Add callouts completed udi=%s", d->udi));
2962 }
2963 
2964 /*
2965  * Preprobing helper.
2966  */
2967 static void
2968 manager_commit_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2969 {
2970 	if (hal_device_property_get_bool (d, "info.ignore")) {
2971 		/* Leave the device here with info.ignore==TRUE so we won't pick up children
2972 		 * Also remove category and all capabilities
2973 		 */
2974 		hal_device_property_remove (d, "info.category");
2975 		hal_device_property_remove (d, "info.capabilities");
2976 		hal_device_property_set_string (d, "info.udi", "/org/freedesktop/Hal/devices/ignored-device");
2977 		hal_device_property_set_string (d, "info.product", "Ignored Device");
2978 
2979 		HAL_INFO (("Preprobing merged info.ignore==TRUE"));
2980 
2981 		return;
2982 	}
2983 
2984 	/* Merge properties from .fdi files */
2985 	di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
2986 	di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
2987 
2988 	hal_util_callout_device_add (d, manager_commit_done, NULL, NULL);
2989 }
2990 
2991 
2992 /*
2993  * Move device from tdl to gdl. Runs helpers and callouts.
2994  */
2995 DBusHandlerResult
2996 manager_commit_to_gdl (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2997 {
2998 	DBusMessage *reply;
2999 	DBusMessageIter iter;
3000 	DBusError error;
3001 	HalDevice *d;
3002 	char udi[256], *udi0, *tmp_udi;
3003 
3004 	dbus_error_init (&error);
3005 
3006 	if (!local_interface && !sender_has_privileges (connection, message)) {
3007 		raise_permission_denied (connection, message, "CommitToGdl: not privileged");
3008 		return DBUS_HANDLER_RESULT_HANDLED;
3009 	}
3010 
3011 	if (!dbus_message_get_args (message, &error,
3012 				    DBUS_TYPE_STRING, &tmp_udi,
3013 				    DBUS_TYPE_STRING, &udi0,
3014 				    DBUS_TYPE_INVALID)) {
3015 		raise_syntax (connection, message, "CommitToGdl");
3016 		return DBUS_HANDLER_RESULT_HANDLED;
3017 	}
3018 
3019 	reply = dbus_message_new_method_return (message);
3020 	if (reply == NULL)
3021 		DIE (("No memory"));
3022 
3023 	dbus_message_iter_init_append (reply, &iter);
3024 
3025 	/* look it up in tdl */
3026 
3027 	d = hal_device_store_find (hald_get_tdl (), tmp_udi);
3028 	if (d == NULL) {
3029 		raise_no_such_device (connection, message, tmp_udi);
3030 		return DBUS_HANDLER_RESULT_HANDLED;
3031 	}
3032 
3033 	/* sanity check & avoid races */
3034 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof udi, "%s", udi0);
3035 
3036 	if (hal_device_store_find (hald_get_gdl (), udi)) {
3037 		/* loose it */
3038 		hal_device_store_remove (hald_get_tdl (), d);
3039 		g_object_unref (d);
3040 		raise_error (connection, message, "org.freedesktop.Hal.DeviceExists", "CommitToGdl: Device exists: %s", udi);
3041 		return DBUS_HANDLER_RESULT_HANDLED;
3042 	}
3043 
3044 	/* set new udi */
3045 	hal_device_property_remove (d, "info.udi");
3046 	hal_device_set_udi (d, udi);
3047 	hal_device_property_set_string (d, "info.udi", udi);
3048 
3049 	/* FIXME:
3050 	 * 'RequireEnable' property?
3051 	 * fdi "preprobe"?
3052 	 * run "info.callouts.preprobe"?
3053 	 * remove "info.ignore" devices?
3054 	 * fdi "information"?
3055 	 * fdi "policy"?
3056 	 * run "info.callouts.add"?
3057 	 * tdl -> gdl?
3058 	 * (auto) start "info.addons"?
3059 	 */
3060 
3061 	/* Process preprobe fdi files */
3062 	di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
3063 	hal_util_callout_device_preprobe (d, manager_commit_preprobing_done, NULL, NULL);
3064 
3065 	/* move from tdl to gdl */
3066 	hal_device_store_remove (hald_get_tdl (), d);
3067 	hal_device_store_add (hald_get_gdl (), d);
3068 
3069 	if (!dbus_connection_send (connection, reply, NULL))
3070 		DIE (("No memory"));
3071 
3072 	dbus_message_unref (reply);
3073 
3074 	return DBUS_HANDLER_RESULT_HANDLED;
3075 }
3076 
3077 typedef struct {
3078 	char *udi;
3079 	char *execpath;
3080 	char **extra_env;
3081 	char *mstdin;
3082 	char *member;
3083 	char *interface;
3084 	DBusMessage *message;
3085 	DBusConnection *connection;
3086 } MethodInvocation;
3087 
3088 static void
3089 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3090 		     gint return_code, gchar **error,
3091 		     gpointer data1, gpointer data2);
3092 
3093 
3094 static void
3095 hald_exec_method_free_mi (MethodInvocation *mi)
3096 {
3097 	/* hald_runner_run_method() assumes ownership of mi->message.. so we don't free it here */
3098 	g_free (mi->udi);
3099 	g_free (mi->execpath);
3100 	g_strfreev (mi->extra_env);
3101 	g_free (mi->mstdin);
3102 	g_free (mi->member);
3103 	g_free (mi->interface);
3104 	g_free (mi);
3105 }
3106 
3107 /* returns FALSE if we don't actually invoke anything */
3108 static gboolean
3109 hald_exec_method_do_invocation (MethodInvocation *mi)
3110 {
3111 	gboolean ret;
3112 	HalDevice *d;
3113 
3114 	ret = FALSE;
3115 
3116 	d = hal_device_store_find (hald_get_gdl (), mi->udi);
3117 	if (d == NULL)
3118 		d = hal_device_store_find (hald_get_tdl (), mi->udi);
3119 
3120 	if (d != NULL) {
3121 		/* no timeout */
3122 		hald_runner_run_method(d,
3123 				       mi->execpath,
3124 				       mi->extra_env,
3125 				       mi->mstdin,
3126 				       TRUE,
3127 				       0,
3128 				       hald_exec_method_cb,
3129 				       (gpointer) mi->message,
3130 				       (gpointer) mi->connection);
3131 
3132 		ret = TRUE;
3133 	} else {
3134 		HAL_WARNING (("In-queue method call on non-existant device"));
3135 
3136 		raise_no_such_device (mi->connection, mi->message, mi->udi);
3137 	}
3138 
3139 	return ret;
3140 }
3141 
3142 
3143 static GHashTable *udi_to_method_queue = NULL;
3144 
3145 
3146 gboolean
3147 device_is_executing_method (HalDevice *d, const char *interface_name, const char *method_name)
3148 {
3149 	gpointer origkey;
3150 	gboolean ret;
3151 	GList *queue;
3152 
3153 	ret = FALSE;
3154 
3155 	if (g_hash_table_lookup_extended (udi_to_method_queue, d->udi, &origkey, (gpointer) &queue)) {
3156 
3157 		if (queue != NULL) {
3158 			MethodInvocation *mi;
3159 			mi = (MethodInvocation *) queue->data;
3160 			if ((strcmp (mi->interface, interface_name) == 0) &&
3161 			    (strcmp (mi->member, method_name) == 0)) {
3162 				ret = TRUE;
3163 			}
3164 		}
3165 
3166 		ret = TRUE;
3167 	}
3168 	return ret;
3169 }
3170 
3171 static void
3172 hald_exec_method_process_queue (const char *udi);
3173 
3174 static void
3175 hald_exec_method_enqueue (MethodInvocation *mi)
3176 {
3177 	gpointer origkey;
3178 	GList *queue;
3179 
3180 	if (udi_to_method_queue == NULL) {
3181 		udi_to_method_queue = g_hash_table_new_full (g_str_hash,
3182 							     g_str_equal,
3183 							     g_free,
3184 							     NULL);
3185 	}
3186 
3187 	if (g_hash_table_lookup_extended (udi_to_method_queue, mi->udi, &origkey, (gpointer) &queue)) {
3188 		HAL_INFO (("enqueue"));
3189 		queue = g_list_append (queue, mi);
3190 		g_hash_table_replace (udi_to_method_queue, g_strdup (mi->udi), queue);
3191 	} else {
3192 		HAL_INFO (("no need to enqueue"));
3193 		queue = g_list_append (NULL, mi);
3194 		g_hash_table_insert (udi_to_method_queue, g_strdup (mi->udi), queue);
3195 
3196 		hald_exec_method_do_invocation (mi);
3197 	}
3198 }
3199 
3200 
3201 static void
3202 hald_exec_method_process_queue (const char *udi)
3203 {
3204 	gpointer origkey;
3205 	GList *queue;
3206 	MethodInvocation *mi;
3207 
3208 	if (g_hash_table_lookup_extended (udi_to_method_queue, udi, &origkey, (gpointer) &queue)) {
3209 
3210 		/* clean the top of the list */
3211 		if (queue != NULL) {
3212 			mi = (MethodInvocation *) queue->data;
3213 			queue = g_list_delete_link (queue, queue);
3214 			if (queue == NULL) {
3215 				g_hash_table_remove (udi_to_method_queue, udi);
3216 				HAL_INFO (("No more methods in queue"));
3217 			}
3218 
3219 			/* if method was Volume.Unmount() then refresh mount state */
3220 			if (strcmp (mi->interface, "org.freedesktop.Hal.Device.Volume") == 0 &&
3221 			    strcmp (mi->member, "Unmount") == 0) {
3222 				HalDevice *d;
3223 
3224 				HAL_INFO (("Refreshing mount state for %s since Unmount() completed", mi->udi));
3225 
3226 				d = hal_device_store_find (hald_get_gdl (), mi->udi);
3227 				if (d == NULL) {
3228 					d = hal_device_store_find (hald_get_tdl (), mi->udi);
3229 				}
3230 
3231 				if (d != NULL) {
3232 					osspec_refresh_mount_state_for_block_device (d);
3233 				} else {
3234 					HAL_WARNING ((" Cannot find device object for %s", mi->udi));
3235 				}
3236 			}
3237 
3238 			hald_exec_method_free_mi (mi);
3239 		}
3240 
3241 		/* process the rest of the list */
3242 		if (queue != NULL) {
3243 			HAL_INFO (("Execing next method in queue"));
3244 			g_hash_table_replace (udi_to_method_queue, g_strdup (udi), queue);
3245 
3246 			mi = (MethodInvocation *) queue->data;
3247 			if (!hald_exec_method_do_invocation (mi)) {
3248 				/* the device went away before we got to it... */
3249 				hald_exec_method_process_queue (mi->udi);
3250 			}
3251 		}
3252 	}
3253 }
3254 
3255 static void
3256 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3257 		     gint return_code, gchar **error,
3258 		     gpointer data1, gpointer data2)
3259 {
3260 	dbus_int32_t result;
3261 	DBusMessage *reply = NULL;
3262 	DBusMessage *message;
3263 	DBusMessageIter iter;
3264 	DBusConnection *conn;
3265 	gchar *exp_name = NULL;
3266 	gchar *exp_detail = NULL;
3267 
3268 	hald_exec_method_process_queue (d->udi);
3269 
3270 	message = (DBusMessage *) data1;
3271 	conn = (DBusConnection *) data2;
3272 
3273 	if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
3274 	    error[0] != NULL && error[1] != NULL) {
3275 		exp_name = error[0];
3276 		if (error[0] != NULL) {
3277 			exp_detail = error[1];
3278 		}
3279 		HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
3280 	}
3281 
3282 	if (exit_type != HALD_RUN_SUCCESS) {
3283 		reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3284 		if (conn != NULL) {
3285 			if (!dbus_connection_send (conn, reply, NULL))
3286 				DIE (("No memory"));
3287 		}
3288 		dbus_message_unref (reply);
3289 	} else if (exp_name != NULL && exp_detail != NULL) {
3290 		reply = dbus_message_new_error (message, exp_name, exp_detail);
3291 		if (reply == NULL) {
3292 			/* error name may be invalid - assume caller fucked up and use a generic HAL error name */
3293 			reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3294 			if (reply == NULL) {
3295 				DIE (("No memory"));
3296 			}
3297 		}
3298 		if (conn != NULL) {
3299 			if (!dbus_connection_send (conn, reply, NULL))
3300 				DIE (("No memory"));
3301 		}
3302 		dbus_message_unref (reply);
3303 
3304 	} else {
3305 		result = (dbus_int32_t) return_code;
3306 
3307 		reply = dbus_message_new_method_return (message);
3308 		if (reply == NULL)
3309 			DIE (("No memory"));
3310 
3311 		dbus_message_iter_init_append (reply, &iter);
3312 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &result);
3313 
3314 		if (conn != NULL) {
3315 			if (!dbus_connection_send (conn, reply, NULL))
3316 				DIE (("No memory"));
3317 		}
3318 
3319 		dbus_message_unref (reply);
3320 	}
3321 
3322 	dbus_message_unref (message);
3323 }
3324 
3325 static DBusHandlerResult
3326 hald_exec_method (HalDevice *d, DBusConnection *connection, dbus_bool_t local_interface,
3327 		  DBusMessage *message, const char *execpath)
3328 {
3329 	int type;
3330 	GString *stdin_str;
3331 	DBusMessageIter iter;
3332 	char *extra_env[3];
3333 	char uid_export[128];
3334 	char sender_export[128];
3335 	MethodInvocation *mi;
3336 
3337 	/* add calling uid */
3338 	extra_env[0] = NULL;
3339 	extra_env[1] = NULL;
3340 	if (local_interface) {
3341 		extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
3342 		extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3343 	} else {
3344 		const char *sender;
3345 
3346 		sender = dbus_message_get_sender (message);
3347 		if (sender != NULL) {
3348 			DBusError error;
3349 			unsigned long uid;
3350 
3351 			dbus_error_init (&error);
3352 			uid = dbus_bus_get_unix_user (connection, sender, &error);
3353 			if (!dbus_error_is_set (&error)) {
3354 				sprintf (uid_export, "HAL_METHOD_INVOKED_BY_UID=%lu", uid);
3355 				extra_env[0] = uid_export;
3356 			}
3357 			snprintf (sender_export, sizeof (sender_export),
3358 				  "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=%s", sender);
3359 			extra_env[1] = sender_export;
3360 		}
3361 	}
3362 
3363 	if (extra_env[0] == NULL)
3364 		extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=nobody";
3365 	if (extra_env[1] == NULL)
3366 		extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3367 
3368 
3369 	extra_env[2] = NULL;
3370 
3371 	/* prepare stdin with parameters */
3372 	stdin_str = g_string_sized_new (256); /* default size for passing params; can grow */
3373 	dbus_message_iter_init (message, &iter);
3374 	while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) {
3375 		switch (type) {
3376 		case DBUS_TYPE_BYTE:
3377 		{
3378 			unsigned char value;
3379 			dbus_message_iter_get_basic (&iter, &value);
3380 			g_string_append_printf (stdin_str, "%u", value);
3381 			break;
3382 		}
3383 		case DBUS_TYPE_INT16:
3384 		{
3385 			dbus_int16_t value;
3386 			dbus_message_iter_get_basic (&iter, &value);
3387 			g_string_append_printf (stdin_str, "%d", value);
3388 			break;
3389 		}
3390 		case DBUS_TYPE_UINT16:
3391 		{
3392 			dbus_uint16_t value;
3393 			dbus_message_iter_get_basic (&iter, &value);
3394 			g_string_append_printf (stdin_str, "%u", value);
3395 			break;
3396 		}
3397 		case DBUS_TYPE_INT32:
3398 		{
3399 			dbus_int32_t value;
3400 			dbus_message_iter_get_basic (&iter, &value);
3401 			g_string_append_printf (stdin_str, "%d", value);
3402 			break;
3403 		}
3404 		case DBUS_TYPE_UINT32:
3405 		{
3406 			dbus_uint32_t value;
3407 			dbus_message_iter_get_basic (&iter, &value);
3408 			g_string_append_printf (stdin_str, "%u", value);
3409 			break;
3410 		}
3411 		case DBUS_TYPE_INT64:
3412 		{
3413 			dbus_int64_t value;
3414 			dbus_message_iter_get_basic (&iter, &value);
3415 			g_string_append_printf (stdin_str, "%lld", (long long int) value);
3416 			break;
3417 		}
3418 		case DBUS_TYPE_UINT64:
3419 		{
3420 			dbus_uint64_t value;
3421 			dbus_message_iter_get_basic (&iter, &value);
3422 			g_string_append_printf (stdin_str, "%llu", (long long unsigned int) value);
3423 			break;
3424 		}
3425 		case DBUS_TYPE_DOUBLE:
3426 		{
3427 			double value;
3428 			dbus_message_iter_get_basic (&iter, &value);
3429 			g_string_append_printf (stdin_str, "%g", value);
3430 			break;
3431 		}
3432 		case DBUS_TYPE_BOOLEAN:
3433 		{
3434 			dbus_bool_t value;
3435 			dbus_message_iter_get_basic (&iter, &value);
3436 			g_string_append (stdin_str, value ? "true" : "false");
3437 			break;
3438 		}
3439 		case DBUS_TYPE_STRING:
3440 		{
3441 			char *value;
3442 			dbus_message_iter_get_basic (&iter, &value);
3443 			g_string_append (stdin_str, value);
3444 			break;
3445 		}
3446 
3447 		case DBUS_TYPE_ARRAY:
3448 		{
3449 			DBusMessageIter iter_strlist;
3450 			if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)
3451 				goto error;
3452 
3453 			dbus_message_iter_recurse (&iter, &iter_strlist);
3454 			while (dbus_message_iter_get_arg_type (&iter_strlist) == DBUS_TYPE_STRING) {
3455 				const char *value;
3456 				dbus_message_iter_get_basic (&iter_strlist, &value);
3457 				g_string_append (stdin_str, value);
3458 				g_string_append (stdin_str, "\t");
3459 				dbus_message_iter_next(&iter_strlist);
3460 			}
3461 			break;
3462 		}
3463 
3464 		default:
3465 			goto error;
3466 		}
3467 
3468 		g_string_append_c (stdin_str, '\n');
3469 		dbus_message_iter_next (&iter);
3470 	}
3471 
3472 	mi = g_new0 (MethodInvocation, 1);
3473 	mi->udi = g_strdup (d->udi);
3474 	mi->execpath = g_strdup (execpath);
3475 	mi->extra_env = g_strdupv (extra_env);
3476 	mi->mstdin = g_strdup (stdin_str->str);
3477 	mi->message = message;
3478 	mi->connection = connection;
3479 	mi->member = g_strdup (dbus_message_get_member (message));
3480 	mi->interface = g_strdup (dbus_message_get_interface (message));
3481 	hald_exec_method_enqueue (mi);
3482 
3483 	dbus_message_ref (message);
3484 	g_string_free (stdin_str, TRUE);
3485 
3486 	return DBUS_HANDLER_RESULT_HANDLED;
3487 
3488 error:
3489 	g_string_free (stdin_str, TRUE);
3490 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3491 }
3492 
3493 static gboolean
3494 foreach_device_get_xml_node (HalDeviceStore *store, HalDevice *device,
3495 			     gpointer user_data)
3496 {
3497 	GString *xml = user_data;
3498 	const char *udi, *name;
3499 
3500 	udi = hal_device_get_udi (device);
3501 	name = strrchr(udi, '/')+1;
3502 
3503 	xml = g_string_append(xml, "  <node name=\"");
3504 	xml = g_string_append(xml, name);
3505 	xml = g_string_append(xml, "\"/>\n");
3506 
3507 	return TRUE;
3508 }
3509 
3510 static DBusHandlerResult
3511 do_introspect (DBusConnection  *connection,
3512 	       DBusMessage     *message,
3513 	       dbus_bool_t      local_interface)
3514 {
3515 	const char *path;
3516 	DBusMessage *reply;
3517 	GString *xml;
3518 	char *xml_string;
3519 
3520 	HAL_TRACE (("entering do_introspect"));
3521 
3522 	path = dbus_message_get_path (message);
3523 
3524 	xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
3525 			    "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
3526 			    "<node>\n"
3527 			    "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
3528 			    "    <method name=\"Introspect\">\n"
3529 			    "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
3530 			    "    </method>\n"
3531 			    "  </interface>\n");
3532 
3533 	if (strcmp (path, "/") == 0) {
3534 
3535 		xml = g_string_append (xml,
3536 				       "  <node name=\"org\"/>\n");
3537 
3538 	} else if (strcmp (path, "/org") == 0) {
3539 
3540 		xml = g_string_append (xml,
3541 				       "  <node name=\"freedesktop\"/>\n");
3542 
3543 	} else if (strcmp (path, "/org/freedesktop") == 0) {
3544 
3545 		xml = g_string_append (xml,
3546 				       "  <node name=\"Hal\"/>\n");
3547 
3548 	} else if (strcmp (path, "/org/freedesktop/Hal") == 0) {
3549 
3550 		xml = g_string_append (xml,
3551 				       "  <node name=\"Manager\"/>\n"
3552 				       "  <node name=\"devices\"/>\n");
3553 
3554 	} else if (strcmp (path, "/org/freedesktop/Hal/devices") == 0) {
3555 
3556 		hal_device_store_foreach (hald_get_gdl (),
3557 					  foreach_device_get_xml_node,
3558 					  xml);
3559 
3560 	} else if (strcmp (path, "/org/freedesktop/Hal/Manager") == 0) {
3561 
3562 		xml = g_string_append (xml,
3563 				       "  <interface name=\"org.freedesktop.Hal.Manager\">\n"
3564 				       "    <method name=\"GetAllDevices\">\n"
3565 				       "      <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3566 				       "    </method>\n"
3567 				       "    <method name=\"DeviceExists\">\n"
3568 				       "      <arg name=\"does_it_exist\" direction=\"out\" type=\"b\"/>\n"
3569 				       "      <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3570 				       "    </method>\n"
3571 				       "    <method name=\"FindDeviceStringMatch\">\n"
3572 				       "      <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3573 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3574 				       "      <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3575 				       "    </method>\n"
3576 				       "    <method name=\"FindDeviceByCapability\">\n"
3577 				       "      <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3578 				       "      <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3579 				       "    </method>\n"
3580 				       "    <method name=\"ClaimBranch\">\n"
3581 				       "      <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3582 				       "      <arg name=\"claim_service\" direction=\"in\" type=\"s\"/>\n"
3583 				       "      <arg name=\"result\" direction=\"out\" type=\"b\"/>\n"
3584 				       "    </method>\n"
3585 				       "    <method name=\"UnclaimBranch\">\n"
3586 				       "      <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3587 				       "      <arg name=\"result\" direction=\"out\" type=\"b\"/>\n"
3588 				       "    </method>\n"
3589 				       "    <method name=\"NewDevice\">\n"
3590 				       "      <arg name=\"temporary_udi\" direction=\"out\" type=\"s\"/>\n"
3591 				       "    </method>\n"
3592 				       "    <method name=\"Remove\">\n"
3593 				       "      <arg name=\"udi\" direction=\"in\" type=\"s\"/>\n"
3594 				       "    </method>\n"
3595 				       "    <method name=\"CommitToGdl\">\n"
3596 				       "      <arg name=\"temporary_udi\" direction=\"in\" type=\"s\"/>\n"
3597 				       "      <arg name=\"global_udi\" direction=\"in\" type=\"s\"/>\n"
3598 				       "    </method>\n"
3599 				       "  </interface>\n");
3600 	} else {
3601 		HalDevice *d;
3602 
3603 		d = hal_device_store_find (hald_get_gdl (), path);
3604 		if (d == NULL)
3605 			d = hal_device_store_find (hald_get_tdl (), path);
3606 
3607 		if (d == NULL) {
3608 			raise_no_such_device (connection, message, path);
3609 			return DBUS_HANDLER_RESULT_HANDLED;
3610 		}
3611 
3612 		xml = g_string_append (xml,
3613 				       "  <interface name=\"org.freedesktop.Hal.Device\">\n"
3614 				       "    <method name=\"GetAllProperties\">\n"
3615 				       "      <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n"
3616 				       "    </method>\n"
3617 				       "    <method name=\"SetMultipleProperties\">\n"
3618 				       "      <arg name=\"properties\" direction=\"in\" type=\"a{sv}\"/>\n"
3619 				       "    </method>\n"
3620 				       "    <method name=\"GetProperty\">\n"
3621 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3622 				       "      <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"
3623 				       "    </method>\n"
3624 				       "    <method name=\"GetPropertyString\">\n"
3625 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3626 				       "      <arg name=\"value\" direction=\"out\" type=\"s\"/>\n"
3627 				       "    </method>\n"
3628 				       "    <method name=\"GetPropertyStringList\">\n"
3629 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3630 				       "      <arg name=\"value\" direction=\"out\" type=\"as\"/>\n"
3631 				       "    </method>\n"
3632 				       "    <method name=\"GetPropertyInteger\">\n"
3633 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3634 				       "      <arg name=\"value\" direction=\"out\" type=\"i\"/>\n"
3635 				       "    </method>\n"
3636 				       "    <method name=\"GetPropertyBoolean\">\n"
3637 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3638 				       "      <arg name=\"value\" direction=\"out\" type=\"b\"/>\n"
3639 				       "    </method>\n"
3640 				       "    <method name=\"GetPropertyDouble\">\n"
3641 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3642 				       "      <arg name=\"value\" direction=\"out\" type=\"d\"/>\n"
3643 				       "    </method>\n"
3644 				       "    <method name=\"SetProperty\">\n"
3645 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3646 				       "      <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"
3647 				       "    </method>\n"
3648 				       "    <method name=\"SetPropertyString\">\n"
3649 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3650 				       "      <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3651 				       "    </method>\n"
3652 				       "    <method name=\"SetPropertyStringList\">\n"
3653 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3654 				       "      <arg name=\"value\" direction=\"in\" type=\"as\"/>\n"
3655 				       "    </method>\n"
3656 				       "    <method name=\"SetPropertyInteger\">\n"
3657 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3658 				       "      <arg name=\"value\" direction=\"in\" type=\"i\"/>\n"
3659 				       "    </method>\n"
3660 				       "    <method name=\"SetPropertyBoolean\">\n"
3661 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3662 				       "      <arg name=\"value\" direction=\"in\" type=\"b\"/>\n"
3663 				       "    </method>\n"
3664 				       "    <method name=\"SetPropertyDouble\">\n"
3665 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3666 				       "      <arg name=\"value\" direction=\"in\" type=\"d\"/>\n"
3667 				       "    </method>\n"
3668 
3669 				       "    <method name=\"RemoveProperty\">\n"
3670 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3671 				       "    </method>\n"
3672 				       "    <method name=\"GetPropertyType\">\n"
3673 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3674 				       "      <arg name=\"type\" direction=\"out\" type=\"i\"/>\n"
3675 				       "    </method>\n"
3676 				       "    <method name=\"PropertyExists\">\n"
3677 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3678 				       "      <arg name=\"does_it_exist\" direction=\"out\" type=\"b\"/>\n"
3679 				       "    </method>\n"
3680 				       "    <method name=\"AddCapability\">\n"
3681 				       "      <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3682 				       "    </method>\n"
3683 				       "    <method name=\"QueryCapability\">\n"
3684 				       "      <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3685 				       "      <arg name=\"does_it_have_capability\" direction=\"out\" type=\"b\"/>\n"
3686 				       "    </method>\n"
3687 				       "    <method name=\"Lock\">\n"
3688 				       "      <arg name=\"reason\" direction=\"in\" type=\"s\"/>\n"
3689 				       "      <arg name=\"acquired_lock\" direction=\"out\" type=\"b\"/>\n"
3690 				       "    </method>\n"
3691 				       "    <method name=\"Unlock\">\n"
3692 				       "      <arg name=\"released_lock\" direction=\"out\" type=\"b\"/>\n"
3693 				       "    </method>\n"
3694 
3695 				       "    <method name=\"StringListAppend\">\n"
3696 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3697 				       "      <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3698 				       "    </method>\n"
3699 				       "    <method name=\"StringListPrepend\">\n"
3700 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3701 				       "      <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3702 				       "    </method>\n"
3703 				       "    <method name=\"StringListRemove\">\n"
3704 				       "      <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3705 				       "      <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3706 				       "    </method>\n"
3707 				       "    <method name=\"EmitCondition\">\n"
3708 				       "      <arg name=\"condition_name\" direction=\"in\" type=\"s\"/>\n"
3709 				       "      <arg name=\"condition_details\" direction=\"in\" type=\"s\"/>\n"
3710 				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3711 				       "    </method>\n"
3712 
3713 				       "    <method name=\"Rescan\">\n"
3714 				       "      <arg name=\"call_had_sideeffect\" direction=\"out\" type=\"b\"/>\n"
3715 				       "    </method>\n"
3716 				       "    <method name=\"Reprobe\">\n"
3717 				       "      <arg name=\"call_had_sideeffect\" direction=\"out\" type=\"b\"/>\n"
3718 				       "    </method>\n"
3719 
3720 				       "    <method name=\"ClaimInterface\">\n"
3721 				       "      <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
3722 				       "      <arg name=\"introspection_xml\" direction=\"in\" type=\"s\"/>\n"
3723 				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3724 				       "    </method>\n"
3725 
3726 				       "    <method name=\"AddonIsReady\">\n"
3727 				       "      <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3728 				       "    </method>\n"
3729 
3730 				       "  </interface>\n");
3731 
3732 			GSList *interfaces;
3733 			GSList *i;
3734 
3735 			interfaces = hal_device_property_get_strlist (d, "info.interfaces");
3736 			for (i = interfaces; i != NULL; i = g_slist_next (i)) {
3737 				const char *ifname = (const char *) i->data;
3738 				char *method_names_prop;
3739 				char *method_signatures_prop;
3740 				char *method_argnames_prop;
3741 				GSList *method_names;
3742 				GSList *method_signatures;
3743 				GSList *method_argnames;
3744 				GSList *j;
3745 				GSList *k;
3746 				GSList *l;
3747 
3748 				g_string_append_printf (xml, "  <interface name=\"%s\">\n", ifname);
3749 
3750 				method_names_prop = g_strdup_printf ("%s.method_names", ifname);
3751 				method_signatures_prop = g_strdup_printf ("%s.method_signatures", ifname);
3752 				method_argnames_prop = g_strdup_printf ("%s.method_argnames", ifname);
3753 
3754 				method_names = hal_device_property_get_strlist (d, method_names_prop);
3755 				method_signatures = hal_device_property_get_strlist (d, method_signatures_prop);
3756 				method_argnames = hal_device_property_get_strlist (d, method_argnames_prop);
3757 
3758 				/* consult local list */
3759 				if (method_names == NULL) {
3760 					GSList *i;
3761 
3762 					for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
3763 						HelperInterfaceHandler *hih = i->data;
3764 						if (strcmp (hih->udi, path) == 0) {
3765 							xml = g_string_append (xml, hih->introspection_xml);
3766 						}
3767 					}
3768 
3769 				}
3770 
3771 				for (j = method_names, k = method_signatures, l = method_argnames;
3772 				     j != NULL && k != NULL && l != NULL;
3773 				     j = g_slist_next (j), k = g_slist_next (k), l = g_slist_next (l)) {
3774 					const char *name;
3775 					const char *sig;
3776 					const char *argnames;
3777 					char **args;
3778 					unsigned int n;
3779 					unsigned int m;
3780 
3781 					name = j->data;
3782 					sig = k->data;
3783 					argnames = l->data;
3784 
3785 					args = g_strsplit (argnames, " ", 0);
3786 
3787 					g_string_append_printf (xml, "    <method name=\"%s\">\n", name);
3788 
3789 					for (n = 0, m = 0; n < strlen (sig) && args[m] != NULL; n++, m++) {
3790 						switch (sig[n]) {
3791 						case 'a':
3792 							if (n == strlen (sig) - 1) {
3793 								HAL_WARNING (("Broken signature for method %s "
3794 									      "on interface %s for object %s",
3795 									      name, ifname, path));
3796 								continue;
3797 							}
3798 							g_string_append_printf (
3799 							  xml,
3800 							  "      <arg name=\"%s\" direction=\"in\" type=\"a%c\"/>\n",
3801 							  args[m], sig[n + 1]);
3802 							n++;
3803 							break;
3804 
3805 						default:
3806 							g_string_append_printf (
3807 							  xml,
3808 							  "      <arg name=\"%s\" direction=\"in\" type=\"%c\"/>\n",
3809 							  args[m], sig[n]);
3810 							break;
3811 						}
3812 					}
3813 					xml = g_string_append (
3814 						xml,
3815 						"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n");
3816 					xml = g_string_append  (
3817 						xml,
3818 						"    </method>\n");
3819 
3820 				}
3821 
3822 
3823 				xml = g_string_append (xml, "  </interface>\n");
3824 
3825 				g_free (method_names_prop);
3826 				g_free (method_signatures_prop);
3827 				g_free (method_argnames_prop);
3828 			}
3829 
3830 	}
3831 
3832 	reply = dbus_message_new_method_return (message);
3833 
3834 	xml = g_string_append (xml, "</node>\n");
3835 	xml_string = g_string_free (xml, FALSE);
3836 
3837 	dbus_message_append_args (reply,
3838 				  DBUS_TYPE_STRING, &xml_string,
3839 				  DBUS_TYPE_INVALID);
3840 
3841 	g_free (xml_string);
3842 
3843 	if (reply == NULL)
3844 		DIE (("No memory"));
3845 
3846 	if (!dbus_connection_send (connection, reply, NULL))
3847 		DIE (("No memory"));
3848 
3849 	dbus_message_unref (reply);
3850 	return DBUS_HANDLER_RESULT_HANDLED;
3851 }
3852 
3853 static void
3854 reply_from_fwd_message (DBusPendingCall *pending_call,
3855 			void            *user_data)
3856 {
3857 	DBusMessage *reply_from_addon;
3858 	DBusMessage *method_from_caller;
3859 	DBusMessage *reply;
3860 
3861 	/*HAL_INFO (("in reply_from_fwd_message : user_data = 0x%x", user_data));*/
3862 
3863 	method_from_caller = (DBusMessage *) user_data;
3864 	reply_from_addon = dbus_pending_call_steal_reply (pending_call);
3865 
3866 	reply = dbus_message_copy (reply_from_addon);
3867 	dbus_message_set_destination (reply, dbus_message_get_sender (method_from_caller));
3868 	dbus_message_set_reply_serial (reply, dbus_message_get_serial (method_from_caller));
3869 
3870 	if (dbus_connection != NULL)
3871 		dbus_connection_send (dbus_connection, reply, NULL);
3872 
3873 	dbus_message_unref (reply_from_addon);
3874 	dbus_message_unref (reply);
3875 	dbus_message_unref (method_from_caller);
3876 	dbus_pending_call_unref (pending_call);
3877 }
3878 
3879 static DBusHandlerResult
3880 hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *message,
3881 				 void *user_data, dbus_bool_t local_interface)
3882 {
3883 	/*HAL_INFO (("connection=0x%x obj_path=%s interface=%s method=%s local_interface=%d",
3884 		   connection,
3885 		   dbus_message_get_path (message),
3886 		   dbus_message_get_interface (message),
3887 		   dbus_message_get_member (message),
3888 		   local_interface));*/
3889 
3890 	if (dbus_message_is_method_call (message,
3891 					 "org.freedesktop.Hal.Manager",
3892 					 "GetAllDevices") &&
3893 		   strcmp (dbus_message_get_path (message),
3894 			   "/org/freedesktop/Hal/Manager") == 0) {
3895 		return manager_get_all_devices (connection, message);
3896 	} else if (dbus_message_is_method_call (message,
3897 						"org.freedesktop.Hal.Manager",
3898 						"DeviceExists") &&
3899 		   strcmp (dbus_message_get_path (message),
3900 			   "/org/freedesktop/Hal/Manager") == 0) {
3901 		return manager_device_exists (connection, message);
3902 	} else if (dbus_message_is_method_call (message,
3903 						"org.freedesktop.Hal.Manager",
3904 						"FindDeviceStringMatch") &&
3905 		   strcmp (dbus_message_get_path (message),
3906 			   "/org/freedesktop/Hal/Manager") == 0) {
3907 		return manager_find_device_string_match (connection,
3908 							 message);
3909 	} else if (dbus_message_is_method_call
3910 		   (message, "org.freedesktop.Hal.Manager",
3911 		    "FindDeviceByCapability")
3912 		   && strcmp (dbus_message_get_path (message),
3913 			      "/org/freedesktop/Hal/Manager") == 0) {
3914 		return manager_find_device_by_capability (connection,
3915 							  message);
3916 	} else if (dbus_message_is_method_call (message,
3917 						"org.freedesktop.Hal.Manager",
3918 						"ClaimBranch") &&
3919 		   strcmp (dbus_message_get_path (message),
3920 			   "/org/freedesktop/Hal/Manager") == 0) {
3921 		return manager_claim_branch (connection, message);
3922 	} else if (dbus_message_is_method_call (message,
3923 						"org.freedesktop.Hal.Manager",
3924 						"UnclaimBranch") &&
3925 		   strcmp (dbus_message_get_path (message),
3926 			   "/org/freedesktop/Hal/Manager") == 0) {
3927 		return manager_unclaim_branch (connection, message);
3928 	} else if (dbus_message_is_method_call (message,
3929 						"org.freedesktop.Hal.Manager",
3930 						"NewDevice") &&
3931 		   strcmp (dbus_message_get_path (message),
3932 			    "/org/freedesktop/Hal/Manager") == 0) {
3933 		return manager_new_device (connection, message, local_interface);
3934 	} else if (dbus_message_is_method_call (message,
3935 						"org.freedesktop.Hal.Manager",
3936 						"Remove") &&
3937 		   strcmp (dbus_message_get_path (message),
3938 			    "/org/freedesktop/Hal/Manager") == 0) {
3939 		return manager_remove (connection, message, local_interface);
3940 	} else if (dbus_message_is_method_call (message,
3941 						"org.freedesktop.Hal.Manager",
3942 						"CommitToGdl") &&
3943 		   strcmp (dbus_message_get_path (message),
3944 			    "/org/freedesktop/Hal/Manager") == 0) {
3945 		return manager_commit_to_gdl (connection, message, local_interface);
3946 	} else if (dbus_message_is_method_call (message,
3947 					      "org.freedesktop.Hal.Device",
3948 					      "GetAllProperties")) {
3949 		return device_get_all_properties (connection, message);
3950 	} else if (dbus_message_is_method_call (message,
3951 					      "org.freedesktop.Hal.Device",
3952 					      "SetMultipleProperties")) {
3953 		return device_set_multiple_properties (connection, message, local_interface);
3954 	} else if (dbus_message_is_method_call (message,
3955 						"org.freedesktop.Hal.Device",
3956 						"GetProperty")) {
3957 		return device_get_property (connection, message);
3958 	} else if (dbus_message_is_method_call (message,
3959 						"org.freedesktop.Hal.Device",
3960 						"GetPropertyString")) {
3961 		return device_get_property (connection, message);
3962 	} else if (dbus_message_is_method_call (message,
3963 						"org.freedesktop.Hal.Device",
3964 						"GetPropertyStringList")) {
3965 		return device_get_property (connection, message);
3966 	} else if (dbus_message_is_method_call (message,
3967 						"org.freedesktop.Hal.Device",
3968 						"GetPropertyInteger")) {
3969 		return device_get_property (connection, message);
3970 	} else if (dbus_message_is_method_call (message,
3971 						"org.freedesktop.Hal.Device",
3972 						"GetPropertyBoolean")) {
3973 		return device_get_property (connection, message);
3974 	} else if (dbus_message_is_method_call (message,
3975 						"org.freedesktop.Hal.Device",
3976 						"GetPropertyDouble")) {
3977 		return device_get_property (connection, message);
3978 	} else if (dbus_message_is_method_call (message,
3979 						"org.freedesktop.Hal.Device",
3980 						"SetProperty")) {
3981 		return device_set_property (connection, message, local_interface);
3982 	} else if (dbus_message_is_method_call (message,
3983 						"org.freedesktop.Hal.Device",
3984 						"SetPropertyString")) {
3985 		return device_set_property (connection, message, local_interface);
3986 	} else if (dbus_message_is_method_call (message,
3987 						"org.freedesktop.Hal.Device",
3988 						"SetPropertyInteger")) {
3989 		return device_set_property (connection, message, local_interface);
3990 	} else if (dbus_message_is_method_call (message,
3991 						"org.freedesktop.Hal.Device",
3992 						"SetPropertyBoolean")) {
3993 		return device_set_property (connection, message, local_interface);
3994 	} else if (dbus_message_is_method_call (message,
3995 						"org.freedesktop.Hal.Device",
3996 						"SetPropertyDouble")) {
3997 		return device_set_property (connection, message, local_interface);
3998 	} else if (dbus_message_is_method_call (message,
3999 						"org.freedesktop.Hal.Device",
4000 						"RemoveProperty")) {
4001 		return device_remove_property (connection, message, local_interface);
4002 	} else if (dbus_message_is_method_call (message,
4003 						"org.freedesktop.Hal.Device",
4004 						"GetPropertyType")) {
4005 		return device_get_property_type (connection, message);
4006 	} else if (dbus_message_is_method_call (message,
4007 						"org.freedesktop.Hal.Device",
4008 						"PropertyExists")) {
4009 		return device_property_exists (connection, message);
4010 	} else if (dbus_message_is_method_call (message,
4011 						"org.freedesktop.Hal.Device",
4012 						"AddCapability")) {
4013 		return device_add_capability (connection, message, local_interface);
4014 	} else if (dbus_message_is_method_call (message,
4015 						"org.freedesktop.Hal.Device",
4016 						"QueryCapability")) {
4017 		return device_query_capability (connection, message);
4018 	} else if (dbus_message_is_method_call (message,
4019 						"org.freedesktop.Hal.Device",
4020 						"Lock")) {
4021 		return device_lock (connection, message);
4022 	} else if (dbus_message_is_method_call (message,
4023 						"org.freedesktop.Hal.Device",
4024 						"Unlock")) {
4025 		return device_unlock (connection, message);
4026 	} else if (dbus_message_is_method_call (message,
4027 						"org.freedesktop.Hal.Device",
4028 						"StringListAppend")) {
4029 		return device_string_list_append_prepend (connection, message, FALSE);
4030 	} else if (dbus_message_is_method_call (message,
4031 						"org.freedesktop.Hal.Device",
4032 						"StringListPrepend")) {
4033 		return device_string_list_append_prepend (connection, message, TRUE);
4034 	} else if (dbus_message_is_method_call (message,
4035 						"org.freedesktop.Hal.Device",
4036 						"StringListRemove")) {
4037 		return device_string_list_remove (connection, message);
4038 	} else if (dbus_message_is_method_call (message,
4039 						"org.freedesktop.Hal.Device",
4040 						"Rescan")) {
4041 		return device_rescan (connection, message, local_interface);
4042 	} else if (dbus_message_is_method_call (message,
4043 						"org.freedesktop.Hal.Device",
4044 						"Reprobe")) {
4045 		return device_reprobe (connection, message, local_interface);
4046 	} else if (dbus_message_is_method_call (message,
4047 						"org.freedesktop.Hal.Device",
4048 						"EmitCondition")) {
4049 		return device_emit_condition (connection, message, local_interface);
4050 	} else if (dbus_message_is_method_call (message,
4051 						"org.freedesktop.Hal.Device",
4052 						"ClaimInterface")) {
4053 		return device_claim_interface (connection, message, local_interface);
4054 #if 0
4055 	} else if (dbus_message_is_method_call (message,
4056 						"org.freedesktop.Hal.Device",
4057 						"ReleaseInterface")) {
4058 		return device_release_interface (connection, message, local_interface);
4059 #endif
4060 	} else if (dbus_message_is_method_call (message,
4061 						"org.freedesktop.Hal.Device",
4062 						"AddonIsReady")) {
4063 		return addon_is_ready (connection, message, local_interface);
4064 	} else if (dbus_message_is_method_call (message,
4065 						"org.freedesktop.DBus.Introspectable",
4066 						"Introspect")) {
4067 		return do_introspect (connection, message, local_interface);
4068 	} else {
4069 		const char *interface;
4070 		const char *udi;
4071 		const char *method;
4072 		const char *signature;
4073 		HalDevice *d;
4074 
4075 		/* check for device-specific interfaces that individual objects may support */
4076 
4077 		udi = dbus_message_get_path (message);
4078 		interface = dbus_message_get_interface (message);
4079 		method = dbus_message_get_member (message);
4080 		signature = dbus_message_get_signature (message);
4081 
4082 		d = NULL;
4083 
4084 		if (udi != NULL) {
4085 			d = hal_device_store_find (hald_get_gdl (), udi);
4086 			if (d == NULL)
4087 				d = hal_device_store_find (hald_get_tdl (), udi);
4088 		}
4089 
4090 		if (d != NULL && interface != NULL) {
4091 			GSList *i;
4092 
4093 			for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
4094 				HelperInterfaceHandler *hih = i->data;
4095 				if (strcmp (hih->udi, udi) == 0 &&
4096 				    strcmp (hih->interface_name, interface) == 0) {
4097 					DBusPendingCall *pending_call;
4098 					DBusMessage *copy;
4099 
4100 					/*HAL_INFO (("forwarding method to connection 0x%x", hih->connection));*/
4101 
4102 					dbus_message_ref (message);
4103 
4104 					/* send a copy of the message */
4105 					copy = dbus_message_copy (message);
4106 					if (!dbus_connection_send_with_reply (hih->connection,
4107 									      copy,
4108 									      &pending_call,
4109 									      /*-1*/ 8000)) {
4110 						/* TODO: handle error */
4111 					} else {
4112 						/*HAL_INFO (("connection=%x message=%x", connection, message));*/
4113 						dbus_pending_call_set_notify (pending_call,
4114 									      reply_from_fwd_message,
4115 									      (void *) message,
4116 									      NULL);
4117 					}
4118 
4119 					dbus_message_unref (copy);
4120 
4121 					return DBUS_HANDLER_RESULT_HANDLED;
4122 				}
4123 			}
4124 		}
4125 
4126 		if (d != NULL && interface != NULL && method != NULL && signature != NULL) {
4127 			GSList *interfaces;
4128 			GSList *i;
4129 
4130 			interfaces = hal_device_property_get_strlist (d, "info.interfaces");
4131 			for (i = interfaces; i != NULL; i = g_slist_next (i)) {
4132 				const char *ifname = (const char *) i->data;
4133 
4134 				if (strcmp (ifname, interface) == 0) {
4135 					guint num;
4136 					GSList *method_names;
4137 					char *s;
4138 
4139 					s = g_strdup_printf ("%s.method_names", interface);
4140 					method_names = hal_device_property_get_strlist (d, s);
4141 					g_free (s);
4142 					for (i = method_names, num = 0; i != NULL; i = g_slist_next (i), num++) {
4143 						const char *methodname = (const char *) i->data;
4144 						if (strcmp (methodname, method) == 0) {
4145 							const char *execpath;
4146 							const char *sig;
4147 
4148 							s = g_strdup_printf ("%s.method_execpaths", interface);
4149 							execpath = hal_device_property_get_strlist_elem (d, s, num);
4150 							g_free (s);
4151 							s = g_strdup_printf ("%s.method_signatures", interface);
4152 							sig = hal_device_property_get_strlist_elem (d, s, num);
4153 							g_free (s);
4154 
4155 							if (execpath != NULL && sig != NULL &&
4156 							    strcmp (sig, signature) == 0) {
4157 
4158 								HAL_INFO (("OK for method '%s' with signature '%s' on interface '%s' for UDI '%s' and execpath '%s'", method, signature, interface, udi, execpath));
4159 
4160 								return hald_exec_method (d, connection, local_interface,
4161 											 message, execpath);
4162 							}
4163 
4164 						}
4165 					}
4166 				}
4167 			}
4168 
4169 		}
4170 	}
4171 
4172 	return osspec_filter_function (connection, message, user_data);
4173 }
4174 
4175 
4176 /** Message handler for method invocations. All invocations on any object
4177  *  or interface is routed through this function.
4178  *
4179  *  @param  connection          D-BUS connection
4180  *  @param  message             Message
4181  *  @param  user_data           User data
4182  *  @return                     What to do with the message
4183  */
4184 DBusHandlerResult
4185 hald_dbus_filter_function (DBusConnection * connection,
4186 			   DBusMessage * message, void *user_data)
4187 {
4188 	if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
4189 	    strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
4190 
4191 		/* this is a local message; e.g. from libdbus in this process */
4192 
4193 		HAL_INFO (("Got disconnected from the system message bus; "
4194 			   "retrying to reconnect every 3000 ms"));
4195 		dbus_connection_unref (dbus_connection);
4196 		dbus_connection = NULL;
4197 
4198 		g_timeout_add (3000, reinit_dbus, NULL);
4199 
4200 	} else if (dbus_message_is_signal (message,
4201 					   DBUS_INTERFACE_DBUS,
4202 					   "NameOwnerChanged")) {
4203 
4204 		if (services_with_locks != NULL || services_with_claims != NULL)
4205 			service_deleted (message);
4206 	} else
4207 		return hald_dbus_filter_handle_methods (connection, message, user_data, FALSE);
4208 
4209 	return DBUS_HANDLER_RESULT_HANDLED;
4210 }
4211 
4212 
4213 
4214 static DBusHandlerResult
4215 local_server_message_handler (DBusConnection *connection,
4216 			      DBusMessage *message,
4217 			      void *user_data)
4218 {
4219 	/*HAL_INFO (("local_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
4220 		   dbus_message_get_destination (message),
4221 		   dbus_message_get_path (message),
4222 		   dbus_message_get_interface (message),
4223 		   dbus_message_get_member (message)));*/
4224 
4225 	if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
4226 		DBusMessage *reply;
4227 
4228 		/* cheat, and handle AddMatch since libhal will try to invoke this method */
4229 		reply = dbus_message_new_method_return (message);
4230 		if (reply == NULL)
4231 			DIE (("No memory"));
4232 		if (!dbus_connection_send (connection, reply, NULL))
4233 			DIE (("No memory"));
4234 		dbus_message_unref (reply);
4235 		return DBUS_HANDLER_RESULT_HANDLED;
4236 	} else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
4237 		   strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
4238 		GSList *i;
4239 		GSList *j;
4240 
4241 		HAL_INFO (("Client to local_server was disconnected"));
4242 
4243 		for (i = helper_interface_handlers; i != NULL; i = j) {
4244 			HelperInterfaceHandler *hih = i->data;
4245 
4246 			j = g_slist_next (i);
4247 
4248 			if (hih->connection == connection) {
4249 				g_free (hih->interface_name);
4250 				g_free (hih->introspection_xml);
4251 				g_free (hih->udi);
4252 				g_free (hih);
4253 				helper_interface_handlers = g_slist_remove_link (helper_interface_handlers, i);
4254 			}
4255 		}
4256 
4257 		dbus_connection_unref (connection);
4258 		return DBUS_HANDLER_RESULT_HANDLED;
4259 	} else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) {
4260 		DBusMessage *copy;
4261 
4262 		/* it's a signal, just forward it onto the system message bus */
4263 		copy = dbus_message_copy (message);
4264 		if (dbus_connection != NULL) {
4265 			dbus_connection_send (dbus_connection, copy, NULL);
4266 		}
4267 		dbus_message_unref (copy);
4268 	} else {
4269 		return hald_dbus_filter_handle_methods (connection, message, user_data, TRUE);
4270 	}
4271 
4272 	return DBUS_HANDLER_RESULT_HANDLED;
4273 }
4274 
4275 static void
4276 local_server_unregister_handler (DBusConnection *connection, void *user_data)
4277 {
4278 	HAL_INFO (("unregistered"));
4279 }
4280 
4281 static void
4282 local_server_handle_connection (DBusServer *server,
4283 			  DBusConnection *new_connection,
4284 			  void *data)
4285 {
4286 	DBusObjectPathVTable vtable = { &local_server_unregister_handler,
4287 					&local_server_message_handler,
4288 					NULL, NULL, NULL, NULL};
4289 
4290 	HAL_INFO (("%d: Got a connection", getpid ()));
4291 	HAL_INFO (("dbus_connection_get_is_connected = %d", dbus_connection_get_is_connected (new_connection)));
4292 
4293 	/*dbus_connection_add_filter (new_connection, server_filter_function, NULL, NULL);*/
4294 
4295 	dbus_connection_register_fallback (new_connection,
4296 					   "/org/freedesktop",
4297 					   &vtable,
4298 					   NULL);
4299 	dbus_connection_ref (new_connection);
4300 	dbus_connection_setup_with_g_main (new_connection, NULL);
4301 }
4302 
4303 
4304 static DBusServer *local_server = NULL;
4305 
4306 char *
4307 hald_dbus_local_server_addr (void)
4308 {
4309 	if (local_server == NULL)
4310 		return NULL;
4311 
4312 	return dbus_server_get_address (local_server);
4313 }
4314 
4315 gboolean
4316 hald_dbus_local_server_init (void)
4317 {
4318 	gboolean ret;
4319 	DBusError error;
4320 	char *server_addr;
4321 
4322 	ret = FALSE;
4323 
4324 	/* setup a server listening on a socket so we can do point to point
4325 	 * connections for programs spawned by hald
4326 	 */
4327 	dbus_error_init (&error);
4328 	if ((local_server = dbus_server_listen (HALD_DBUS_ADDRESS, &error)) == NULL) {
4329 		HAL_ERROR (("Cannot create D-BUS server"));
4330 		goto out;
4331 	}
4332 	server_addr = dbus_server_get_address (local_server);
4333 	HAL_INFO (("local server is listening at %s", server_addr));
4334 	dbus_free (server_addr);
4335 	dbus_server_setup_with_g_main (local_server, NULL);
4336 	dbus_server_set_new_connection_function (local_server, local_server_handle_connection, NULL, NULL);
4337 
4338 	ret = TRUE;
4339 
4340 out:
4341 	return ret;
4342 }
4343 
4344 gboolean
4345 hald_dbus_init (void)
4346 {
4347 	DBusError dbus_error;
4348 
4349 	HAL_INFO (("entering"));
4350 
4351 	dbus_connection_set_change_sigpipe (TRUE);
4352 
4353 	dbus_error_init (&dbus_error);
4354 	dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
4355 	if (dbus_connection == NULL) {
4356 		HAL_ERROR (("dbus_bus_get(): %s", dbus_error.message));
4357 		return FALSE;
4358 	}
4359 
4360 	dbus_connection_setup_with_g_main (dbus_connection, NULL);
4361 	dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
4362 
4363 	dbus_bus_request_name (dbus_connection, "org.freedesktop.Hal",
4364 				  0, &dbus_error);
4365 	if (dbus_error_is_set (&dbus_error)) {
4366 		HAL_ERROR (("dbus_bus_request_name(): %s",
4367 			    dbus_error.message));
4368 		return FALSE;
4369 	}
4370 
4371 	dbus_connection_add_filter (dbus_connection, hald_dbus_filter_function, NULL, NULL);
4372 
4373 	dbus_bus_add_match (dbus_connection,
4374 			    "type='signal'"
4375 			    ",interface='"DBUS_INTERFACE_DBUS"'"
4376 			    ",sender='"DBUS_SERVICE_DBUS"'"
4377 			    ",member='NameOwnerChanged'",
4378 			    NULL);
4379 
4380 	return TRUE;
4381 }
4382 
4383 /** @} */
4384