dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / hal / hald / hald_dbus.c
blobfed81378730018d00e812a1fe0e3ff826a3eca6a
1 /***************************************************************************
2 * CVSID: $Id$
4 * dbus.c : D-BUS interface of HAL daemon
6 * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
8 * Licensed under the Academic Free License version 2.1
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.
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.
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
24 **************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
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>
38 #include <dbus/dbus.h>
39 #include <dbus/dbus-glib-lowlevel.h>
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"
51 #define HALD_DBUS_ADDRESS "unix:tmpdir=" HALD_SOCKET_DIR
53 static DBusConnection *dbus_connection = NULL;
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)));
61 /**
62 * @defgroup DaemonErrors Error conditions
63 * @ingroup HalDaemon
64 * @brief Various error messages the HAL daemon can raise
65 * @{
68 /** Raise HAL error
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
75 static void
76 raise_error (DBusConnection *connection,
77 DBusMessage *in_reply_to,
78 const char *error_name,
79 char *format, ...)
81 char buf[512];
82 DBusMessage *reply;
84 va_list args;
85 va_start(args, format);
86 vsnprintf(buf, sizeof buf, format, args);
87 va_end(args);
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);
98 /** Raise the org.freedesktop.Hal.NoSuchDevice error
100 * @param connection D-Bus connection
101 * @param in_reply_to message to report error on
102 * @param udi Unique device id given
104 static void
105 raise_no_such_device (DBusConnection *connection,
106 DBusMessage *in_reply_to, const char *udi)
108 raise_error (
109 connection, in_reply_to,
110 "org.freedesktop.Hal.NoSuchDevice",
111 "No device with id %s",
116 /** Raise the org.freedesktop.Hal.NoSuchProperty error
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
123 static void
124 raise_no_such_property (DBusConnection *connection,
125 DBusMessage *in_reply_to,
126 const char *device_id, const char *key)
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
136 /** Raise the org.freedesktop.Hal.TypeMismatch error
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
143 static void
144 raise_property_type_error (DBusConnection *connection,
145 DBusMessage *in_reply_to,
146 const char *device_id, const char *key)
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
156 /** Raise the org.freedesktop.Hal.SyntaxError error
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
163 static void
164 raise_syntax (DBusConnection *connection,
165 DBusMessage *in_reply_to, const char *method_name)
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
175 /** Raise the org.freedesktop.Hal.DeviceNotLocked error
177 * @param connection D-Bus connection
178 * @param in_reply_to message to report error on
179 * @param device device which isn't locked
181 static void
182 raise_device_not_locked (DBusConnection *connection,
183 DBusMessage *in_reply_to,
184 HalDevice *device)
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)
194 /** Raise the org.freedesktop.Hal.DeviceAlreadyLocked error
196 * @param connection D-Bus connection
197 * @param in_reply_to message to report error on
198 * @param device device which isn't locked
200 static void
201 raise_device_already_locked (DBusConnection *connection,
202 DBusMessage *in_reply_to,
203 HalDevice *device)
205 DBusMessage *reply;
206 const char *reason;
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));
213 reply = dbus_message_new_error (in_reply_to,
214 "org.freedesktop.Hal.DeviceAlreadyLocked",
215 reason);
217 if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
218 DIE (("No memory"));
220 dbus_message_unref (reply);
223 /** Raise the org.freedesktop.Hal.BranchAlreadyClaimed error
225 * @param connection D-Bus connection
226 * @param in_reply_to message to report error on
227 * @param udi branch which isn't claimed
229 static void
230 raise_branch_already_claimed (DBusConnection *connection,
231 DBusMessage *in_reply_to,
232 HalDevice *device)
234 DBusMessage *reply;
235 const char *claim_service;
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));
242 reply = dbus_message_new_error (in_reply_to,
243 "org.freedesktop.Hal.BranchAlreadyClaimed",
244 claim_service);
246 if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
247 DIE (("No memory"));
249 dbus_message_unref (reply);
252 /** Raise the org.freedesktop.Hal.BranchNotClaimed error
254 * @param connection D-Bus connection
255 * @param in_reply_to message to report error on
256 * @param udi branch which isn't claimed
258 static void
259 raise_branch_not_claimed (DBusConnection *connection,
260 DBusMessage *in_reply_to,
261 HalDevice *device)
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)
271 /** Raise the org.freedesktop.Hal.PermissionDenied error
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
277 static void
278 raise_permission_denied (DBusConnection *connection,
279 DBusMessage *in_reply_to,
280 const char *reason)
282 raise_error (
283 connection, in_reply_to,
284 "org.freedesktop.Hal.PermissionDenied",
285 "Permission denied: %s",
286 reason
290 /** @} */
293 * @defgroup ManagerInterface D-BUS interface org.freedesktop.Hal.Manager
294 * @ingroup HalDaemon
295 * @brief D-BUS interface for querying device objects
297 * @{
300 static gboolean
301 foreach_device_get_udi (HalDeviceStore *store, HalDevice *device,
302 gpointer user_data)
304 DBusMessageIter *iter = user_data;
305 const char *udi;
307 udi = hal_device_get_udi (device);
308 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &udi);
310 return TRUE;
313 /** Get all devices.
315 * <pre>
316 * array{object_reference} Manager.GetAllDevices()
317 * </pre>
319 * @param connection D-BUS connection
320 * @param message Message
321 * @return What to do with the message
323 DBusHandlerResult
324 manager_get_all_devices (DBusConnection * connection,
325 DBusMessage * message)
327 DBusMessage *reply;
328 DBusMessageIter iter;
329 DBusMessageIter iter_array;
331 reply = dbus_message_new_method_return (message);
332 if (reply == NULL)
333 DIE (("No memory"));
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);
341 hal_device_store_foreach (hald_get_gdl (),
342 foreach_device_get_udi,
343 &iter_array);
345 dbus_message_iter_close_container (&iter, &iter_array);
347 if (!dbus_connection_send (connection, reply, NULL))
348 DIE (("No memory"));
350 dbus_message_unref (reply);
352 return DBUS_HANDLER_RESULT_HANDLED;
355 typedef struct {
356 const char *key;
357 const char *value;
358 DBusMessageIter *iter;
359 } DeviceMatchInfo;
361 static gboolean
362 foreach_device_match_get_udi (HalDeviceStore *store, HalDevice *device,
363 gpointer user_data)
365 DeviceMatchInfo *info = user_data;
366 const char *dev_value;
368 if (hal_device_property_get_type (device,
369 info->key) != DBUS_TYPE_STRING)
370 return TRUE;
372 dev_value = hal_device_property_get_string (device, info->key);
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);
382 return TRUE;
385 static gboolean
386 foreach_device_match_get_udi_tdl (HalDeviceStore *store, HalDevice *device,
387 gpointer user_data)
389 DeviceMatchInfo *info = user_data;
390 const char *dev_value;
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;
397 if (hal_device_property_get_type (device,
398 info->key) != DBUS_TYPE_STRING)
399 return TRUE;
401 dev_value = hal_device_property_get_string (device, info->key);
403 if (dev_value != NULL && strcmp (dev_value, info->value) == 0) {
404 const char *udi;
405 udi = hal_device_get_udi (device);
407 dbus_message_iter_append_basic (info->iter,
408 DBUS_TYPE_STRING,
409 &udi);
412 return TRUE;
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.
418 * <pre>
419 * array{object_reference} Manager.FindDeviceStringMatch(string key,
420 * string value)
421 * </pre>
423 * @param connection D-BUS connection
424 * @param message Message
425 * @return What to do with the message
427 DBusHandlerResult
428 manager_find_device_string_match (DBusConnection * connection,
429 DBusMessage * message)
431 DBusMessage *reply;
432 DBusMessageIter iter;
433 DBusMessageIter iter_array;
434 DBusError error;
435 const char *key;
436 const char *value;
437 DeviceMatchInfo info;
439 HAL_TRACE (("entering"));
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;
451 reply = dbus_message_new_method_return (message);
452 if (reply == NULL)
453 DIE (("No memory"));
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);
461 info.key = key;
462 info.value = value;
463 info.iter = &iter_array;
465 hal_device_store_foreach (hald_get_gdl (),
466 foreach_device_match_get_udi,
467 &info);
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);
474 dbus_message_iter_close_container (&iter, &iter_array);
476 if (!dbus_connection_send (connection, reply, NULL))
477 DIE (("No memory"));
479 dbus_message_unref (reply);
481 return DBUS_HANDLER_RESULT_HANDLED;
484 typedef struct {
485 const char *capability;
486 DBusMessageIter *iter;
487 } DeviceCapabilityInfo;
489 static gboolean
490 foreach_device_by_capability (HalDeviceStore *store, HalDevice *device, gpointer user_data)
492 DeviceCapabilityInfo *info = (DeviceCapabilityInfo *) user_data;
494 if (hal_device_has_capability (device, info->capability)) {
495 dbus_message_iter_append_basic (info->iter,
496 DBUS_TYPE_STRING,
497 &(device->udi));
500 return TRUE;
503 /** Find devices in the GDL with a given capability.
505 * <pre>
506 * array{object_reference} Manager.FindDeviceByCapability(string capability)
507 * </pre>
509 * @param connection D-BUS connection
510 * @param message Message
511 * @return What to do with the message
513 DBusHandlerResult
514 manager_find_device_by_capability (DBusConnection * connection,
515 DBusMessage * message)
517 DBusMessage *reply;
518 DBusMessageIter iter;
519 DBusMessageIter iter_array;
520 DBusError error;
521 const char *capability;
522 DeviceCapabilityInfo info;
524 HAL_TRACE (("entering"));
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;
535 reply = dbus_message_new_method_return (message);
536 if (reply == NULL)
537 DIE (("No memory"));
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);
545 info.capability = capability;
546 info.iter = &iter_array;
548 hal_device_store_foreach (hald_get_gdl (),
549 foreach_device_by_capability,
550 &info);
552 dbus_message_iter_close_container (&iter, &iter_array);
554 if (!dbus_connection_send (connection, reply, NULL))
555 DIE (("No memory"));
557 dbus_message_unref (reply);
559 return DBUS_HANDLER_RESULT_HANDLED;
563 /** Determine if a device exists.
565 * <pre>
566 * bool Manager.DeviceExists(string udi)
567 * </pre>
569 * @param connection D-BUS connection
570 * @param message Message
571 * @return What to do with the message
573 DBusHandlerResult
574 manager_device_exists (DBusConnection * connection, DBusMessage * message)
576 DBusMessage *reply;
577 DBusMessageIter iter;
578 DBusError error;
579 HalDevice *d;
580 const char *udi;
581 dbus_bool_t b;
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;
591 HAL_TRACE (("entering, udi=%s", udi));
593 d = hal_device_store_find (hald_get_gdl (), udi);
595 if (d == NULL)
596 d = hal_device_store_find (hald_get_tdl (), udi);
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);
603 if (reply == NULL)
604 DIE (("No memory"));
606 if (!dbus_connection_send (connection, reply, NULL))
607 DIE (("No memory"));
609 dbus_message_unref (reply);
610 return DBUS_HANDLER_RESULT_HANDLED;
613 /** Send signal DeviceAdded(string udi) on the org.freedesktop.Hal.Manager
614 * interface on the object /org/freedesktop/Hal/Manager.
616 * @param device The HalDevice added
618 void
619 manager_send_signal_device_added (HalDevice *device)
621 const char *udi = hal_device_get_udi (device);
622 DBusMessage *message;
623 DBusMessageIter iter;
625 if (dbus_connection == NULL)
626 goto out;
628 HAL_TRACE (("entering, udi=%s", udi));
630 message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
631 "org.freedesktop.Hal.Manager",
632 "DeviceAdded");
634 dbus_message_iter_init_append (message, &iter);
635 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
637 if (!dbus_connection_send (dbus_connection, message, NULL))
638 DIE (("error broadcasting message"));
640 dbus_message_unref (message);
642 out:
646 /** Send signal DeviceRemoved(string udi) on the org.freedesktop.Hal.Manager
647 * interface on the object /org/freedesktop/Hal/Manager.
649 * @param device The HalDevice removed
651 void
652 manager_send_signal_device_removed (HalDevice *device)
654 const char *udi = hal_device_get_udi (device);
655 DBusMessage *message;
656 DBusMessageIter iter;
658 if (dbus_connection == NULL)
659 goto out;
661 HAL_TRACE (("entering, udi=%s", udi));
663 message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
664 "org.freedesktop.Hal.Manager",
665 "DeviceRemoved");
667 dbus_message_iter_init_append (message, &iter);
668 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
670 if (!dbus_connection_send (dbus_connection, message, NULL))
671 DIE (("error broadcasting message"));
673 dbus_message_unref (message);
674 out:
678 /** Send signal NewCapability(string udi, string capability) on the
679 * org.freedesktop.Hal.Manager interface on the object
680 * /org/freedesktop/Hal/Manager.
682 * @param udi Unique Device Id
683 * @param capability Capability
685 void
686 manager_send_signal_new_capability (HalDevice *device,
687 const char *capability)
689 const char *udi = hal_device_get_udi (device);
690 DBusMessage *message;
691 DBusMessageIter iter;
693 if (dbus_connection == NULL)
694 goto out;
696 HAL_TRACE (("entering, udi=%s, cap=%s", udi, capability));
698 message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
699 "org.freedesktop.Hal.Manager",
700 "NewCapability");
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);
706 if (!dbus_connection_send (dbus_connection, message, NULL))
707 DIE (("error broadcasting message"));
709 dbus_message_unref (message);
710 out:
714 /** @} */
717 * @defgroup DeviceInterface D-BUS interface org.freedesktop.Hal.Device
718 * @ingroup HalDaemon
719 * @brief D-BUS interface for generic device operations
720 * @{
723 static gboolean
724 foreach_property_append (HalDevice *device, HalProperty *p,
725 gpointer user_data)
727 DBusMessageIter *iter;
728 DBusMessageIter iter_dict_entry;
729 const char *key;
730 int type;
732 iter = (DBusMessageIter *)user_data;
734 dbus_message_iter_open_container (iter,
735 DBUS_TYPE_DICT_ENTRY,
736 NULL,
737 &iter_dict_entry);
739 key = hal_property_get_key (p);
740 type = hal_property_get_type (p);
742 dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &key);
744 switch (type) {
745 case HAL_PROPERTY_TYPE_STRING:
747 DBusMessageIter iter_var;
748 const char *v;
750 v = hal_property_get_string (p);
752 dbus_message_iter_open_container (&iter_dict_entry,
753 DBUS_TYPE_VARIANT,
754 DBUS_TYPE_STRING_AS_STRING,
755 &iter_var);
757 dbus_message_iter_append_basic (&iter_var,
758 DBUS_TYPE_STRING,
759 &v);
761 dbus_message_iter_close_container (&iter_dict_entry,
762 &iter_var);
763 break;
765 case HAL_PROPERTY_TYPE_INT32:
767 DBusMessageIter iter_var;
768 dbus_int32_t v;
770 v = hal_property_get_int (p);
772 dbus_message_iter_open_container (&iter_dict_entry,
773 DBUS_TYPE_VARIANT,
774 DBUS_TYPE_INT32_AS_STRING,
775 &iter_var);
777 dbus_message_iter_append_basic (&iter_var,
778 DBUS_TYPE_INT32,
779 &v);
781 dbus_message_iter_close_container (&iter_dict_entry,
782 &iter_var);
783 break;
785 case HAL_PROPERTY_TYPE_UINT64:
787 DBusMessageIter iter_var;
788 dbus_uint64_t v;
790 v = hal_property_get_uint64 (p);
792 dbus_message_iter_open_container (&iter_dict_entry,
793 DBUS_TYPE_VARIANT,
794 DBUS_TYPE_UINT64_AS_STRING,
795 &iter_var);
797 dbus_message_iter_append_basic (&iter_var,
798 DBUS_TYPE_UINT64,
799 &v);
801 dbus_message_iter_close_container (&iter_dict_entry,
802 &iter_var);
803 break;
805 case HAL_PROPERTY_TYPE_DOUBLE:
807 DBusMessageIter iter_var;
808 double v;
810 v = hal_property_get_double (p);
812 dbus_message_iter_open_container (&iter_dict_entry,
813 DBUS_TYPE_VARIANT,
814 DBUS_TYPE_DOUBLE_AS_STRING,
815 &iter_var);
817 dbus_message_iter_append_basic (&iter_var,
818 DBUS_TYPE_DOUBLE,
819 &v);
821 dbus_message_iter_close_container (&iter_dict_entry,
822 &iter_var);
823 break;
825 case HAL_PROPERTY_TYPE_BOOLEAN:
827 DBusMessageIter iter_var;
828 dbus_bool_t v;
830 v = hal_property_get_bool (p);
832 dbus_message_iter_open_container (&iter_dict_entry,
833 DBUS_TYPE_VARIANT,
834 DBUS_TYPE_BOOLEAN_AS_STRING,
835 &iter_var);
837 dbus_message_iter_append_basic (&iter_var,
838 DBUS_TYPE_BOOLEAN,
839 &v);
841 dbus_message_iter_close_container (&iter_dict_entry,
842 &iter_var);
843 break;
845 case HAL_PROPERTY_TYPE_STRLIST:
847 DBusMessageIter iter_var, iter_array;
848 GSList *iter;
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);
856 dbus_message_iter_open_container (&iter_var,
857 DBUS_TYPE_ARRAY,
858 DBUS_TYPE_STRING_AS_STRING,
859 &iter_array);
861 for (iter = hal_property_get_strlist (p); iter != NULL; iter = iter->next) {
863 const char *v;
864 v = (const char *) iter->data;
866 dbus_message_iter_append_basic (&iter_array,
867 DBUS_TYPE_STRING,
868 &v);
871 dbus_message_iter_close_container (&iter_var,
872 &iter_array);
874 dbus_message_iter_close_container (&iter_dict_entry,
875 &iter_var);
876 break;
879 default:
880 HAL_WARNING (("Unknown property type 0x%04x", type));
881 break;
884 dbus_message_iter_close_container (iter, &iter_dict_entry);
887 return TRUE;
892 /** Get all properties on a device.
894 * <pre>
895 * map{string, any} Device.GetAllProperties()
897 * raises org.freedesktop.Hal.NoSuchDevice
898 * </pre>
900 * @param connection D-BUS connection
901 * @param message Message
902 * @return What to do with the message
904 DBusHandlerResult
905 device_get_all_properties (DBusConnection * connection,
906 DBusMessage * message)
908 DBusMessage *reply;
909 DBusMessageIter iter;
910 DBusMessageIter iter_dict;
911 HalDevice *d;
912 const char *udi;
914 udi = dbus_message_get_path (message);
916 HAL_TRACE (("entering, udi=%s", udi));
918 d = hal_device_store_find (hald_get_gdl (), udi);
919 if (d == NULL)
920 d = hal_device_store_find (hald_get_tdl (), udi);
922 if (d == NULL) {
923 raise_no_such_device (connection, message, udi);
924 return DBUS_HANDLER_RESULT_HANDLED;
927 reply = dbus_message_new_method_return (message);
928 if (reply == NULL)
929 DIE (("No memory"));
931 dbus_message_iter_init_append (reply, &iter);
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);
941 hal_device_property_foreach (d,
942 foreach_property_append,
943 &iter_dict);
945 dbus_message_iter_close_container (&iter, &iter_dict);
947 if (!dbus_connection_send (connection, reply, NULL))
948 DIE (("No memory"));
950 dbus_message_unref (reply);
952 return DBUS_HANDLER_RESULT_HANDLED;
955 #ifdef sun
956 #include <sys/stat.h>
957 static dbus_bool_t
958 user_at_console(unsigned long uid)
960 struct stat st;
962 return ((stat("/dev/vt/console_user", &st) == 0) && (st.st_uid == uid));
964 #endif /* sun */
966 static dbus_bool_t
967 sender_has_privileges (DBusConnection *connection, DBusMessage *message)
969 DBusError error;
970 unsigned long user_uid;
971 const char *user_base_svc;
972 dbus_bool_t ret;
974 ret = FALSE;
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;
982 HAL_DEBUG (("base_svc = %s", user_base_svc));
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;
992 HAL_INFO (("uid for caller is %ld", user_uid));
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;
1004 #endif
1005 HAL_WARNING (("uid %d is not privileged", user_uid));
1006 goto out;
1009 ret = TRUE;
1011 out:
1012 return ret;
1016 /** Set multiple properties on a device in an atomic fashion.
1018 * <pre>
1019 * Device.GetAllProperties(map{string, any} properties)
1021 * raises org.freedesktop.Hal.NoSuchDevice
1022 * </pre>
1024 * @param connection D-BUS connection
1025 * @param message Message
1026 * @return What to do with the message
1028 static DBusHandlerResult
1029 device_set_multiple_properties (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
1031 DBusMessage *reply;
1032 DBusMessageIter iter;
1033 DBusMessageIter dict_iter;
1034 HalDevice *d;
1035 const char *udi;
1037 udi = dbus_message_get_path (message);
1039 HAL_TRACE (("entering, udi=%s", udi));
1041 d = hal_device_store_find (hald_get_gdl (), udi);
1042 if (d == NULL)
1043 d = hal_device_store_find (hald_get_tdl (), udi);
1045 if (d == NULL) {
1046 raise_no_such_device (connection, message, udi);
1047 return DBUS_HANDLER_RESULT_HANDLED;
1050 if (!local_interface && !sender_has_privileges (connection, message)) {
1051 raise_permission_denied (connection, message, "SetProperty: not privileged");
1052 return DBUS_HANDLER_RESULT_HANDLED;
1055 dbus_message_iter_init (message, &iter);
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;
1064 dbus_message_iter_recurse (&iter, &dict_iter);
1066 /* update atomically */
1067 device_property_atomic_update_begin ();
1069 while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY)
1071 DBusMessageIter dict_entry_iter, var_iter, array_iter;
1072 const char *key;
1073 int change_type;
1074 dbus_bool_t rc;
1076 dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
1077 dbus_message_iter_get_basic (&dict_entry_iter, &key);
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);
1083 rc = FALSE;
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 */
1090 dbus_message_iter_recurse (&var_iter, &array_iter);
1092 hal_device_property_strlist_clear (d, key);
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);
1102 break;
1103 case DBUS_TYPE_STRING:
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;
1111 case DBUS_TYPE_INT32:
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;
1119 case DBUS_TYPE_UINT64:
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;
1127 case DBUS_TYPE_DOUBLE:
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;
1135 case DBUS_TYPE_BOOLEAN:
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;
1143 default:
1144 /* TODO: error */
1145 break;
1148 /* TODO: error out on rc==FALSE? */
1150 dbus_message_iter_next (&dict_iter);
1153 device_property_atomic_update_end ();
1156 reply = dbus_message_new_method_return (message);
1157 if (reply == NULL)
1158 DIE (("No memory"));
1160 if (!dbus_connection_send (connection, reply, NULL))
1161 DIE (("No memory"));
1163 dbus_message_unref (reply);
1164 return DBUS_HANDLER_RESULT_HANDLED;
1168 /** Get a property on a device.
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)
1177 * raises org.freedesktop.Hal.NoSuchDevice,
1178 * org.freedesktop.Hal.NoSuchProperty
1179 * </pre>
1181 * @param connection D-BUS connection
1182 * @param message Message
1183 * @return What to do with the message
1185 DBusHandlerResult
1186 device_get_property (DBusConnection * connection, DBusMessage * message)
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;
1197 udi = dbus_message_get_path (message);
1199 HAL_TRACE (("entering, udi=%s", udi));
1201 d = hal_device_store_find (hald_get_gdl (), udi);
1202 if (d == NULL)
1203 d = hal_device_store_find (hald_get_tdl (), udi);
1205 if (d == NULL) {
1206 raise_no_such_device (connection, message, udi);
1207 return DBUS_HANDLER_RESULT_HANDLED;
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;
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;
1224 reply = dbus_message_new_method_return (message);
1225 if (reply == NULL)
1226 DIE (("No memory"));
1228 dbus_message_iter_init_append (reply, &iter);
1230 type = hal_property_get_type (p);
1231 switch (type) {
1232 case HAL_PROPERTY_TYPE_STRING:
1234 const char *s;
1235 s = hal_property_get_string (p);
1236 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &s);
1237 break;
1239 case HAL_PROPERTY_TYPE_INT32:
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;
1246 case HAL_PROPERTY_TYPE_UINT64:
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;
1253 case HAL_PROPERTY_TYPE_DOUBLE:
1255 double d;
1256 d = hal_property_get_double (p);
1257 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &d);
1258 break;
1260 case HAL_PROPERTY_TYPE_BOOLEAN:
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;
1267 case HAL_PROPERTY_TYPE_STRLIST:
1269 GSList *l;
1270 DBusMessageIter iter_array;
1272 dbus_message_iter_open_container (&iter,
1273 DBUS_TYPE_ARRAY,
1274 DBUS_TYPE_STRING_AS_STRING,
1275 &iter_array);
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));
1281 dbus_message_iter_close_container (&iter, &iter_array);
1283 break;
1285 default:
1286 HAL_WARNING (("Unknown property type %d", type));
1287 break;
1290 if (!dbus_connection_send (connection, reply, NULL))
1291 DIE (("No memory"));
1293 dbus_message_unref (reply);
1295 return DBUS_HANDLER_RESULT_HANDLED;
1299 /** Get the type of a property on a device.
1301 * <pre>
1302 * int Device.GetPropertyType(string key)
1304 * raises org.freedesktop.Hal.NoSuchDevice,
1305 * org.freedesktop.Hal.NoSuchProperty
1306 * </pre>
1308 * @param connection D-BUS connection
1309 * @param message Message
1310 * @return What to do with the message
1312 DBusHandlerResult
1313 device_get_property_type (DBusConnection * connection,
1314 DBusMessage * message)
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;
1325 udi = dbus_message_get_path (message);
1327 HAL_TRACE (("entering, udi=%s", udi));
1329 d = hal_device_store_find (hald_get_gdl (), udi);
1330 if (d == NULL)
1331 d = hal_device_store_find (hald_get_tdl (), udi);
1333 if (d == NULL) {
1334 raise_no_such_device (connection, message, udi);
1335 return DBUS_HANDLER_RESULT_HANDLED;
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;
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;
1352 reply = dbus_message_new_method_return (message);
1353 if (reply == NULL)
1354 DIE (("No memory"));
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);
1360 if (!dbus_connection_send (connection, reply, NULL))
1361 DIE (("No memory"));
1363 dbus_message_unref (reply);
1365 return DBUS_HANDLER_RESULT_HANDLED;
1368 /** Set a property on a device.
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)
1377 * raises org.freedesktop.Hal.NoSuchDevice,
1378 * org.freedesktop.Hal.NoSuchProperty
1379 * org.freedesktop.Hal.TypeMismatch
1380 * </pre>
1382 * @param connection D-BUS connection
1383 * @param message Message
1384 * @return What to do with the message
1386 DBusHandlerResult
1387 device_set_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1389 const char *udi;
1390 char *key;
1391 int type;
1392 dbus_bool_t rc;
1393 HalDevice *device;
1394 DBusMessageIter iter;
1395 DBusMessage *reply;
1397 HAL_TRACE (("entering"));
1399 udi = dbus_message_get_path (message);
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;
1407 dbus_message_iter_get_basic (&iter, &key);
1409 if (!local_interface && !sender_has_privileges (connection, message)) {
1410 raise_permission_denied (connection, message, "SetProperty: not privileged");
1411 return DBUS_HANDLER_RESULT_HANDLED;
1414 HAL_DEBUG (("udi=%s, key=%s", udi, key));
1416 device = hal_device_store_find (hald_get_gdl (), udi);
1417 if (device == NULL)
1418 device = hal_device_store_find (hald_get_tdl (), udi);
1420 if (device == NULL) {
1421 raise_no_such_device (connection, message, udi);
1422 return DBUS_HANDLER_RESULT_HANDLED;
1424 dbus_message_iter_next (&iter);
1426 /** @todo check permissions of the sender vs property to be modified */
1428 type = dbus_message_iter_get_arg_type (&iter);
1429 rc = FALSE;
1431 switch (type) {
1432 case DBUS_TYPE_STRING:
1434 const char *v;
1435 dbus_message_iter_get_basic (&iter, &v);
1436 rc = hal_device_property_set_string (device, key, v);
1437 break;
1439 case DBUS_TYPE_INT32:
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;
1446 case DBUS_TYPE_UINT64:
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;
1453 case DBUS_TYPE_DOUBLE:
1455 double v;
1456 dbus_message_iter_get_basic (&iter, &v);
1457 rc = hal_device_property_set_double (device, key, v);
1458 break;
1460 case DBUS_TYPE_BOOLEAN:
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;
1467 default:
1468 HAL_WARNING (("Unsupported property type %d", type));
1469 break;
1472 if (!rc) {
1473 raise_property_type_error (connection, message, udi, key);
1474 return DBUS_HANDLER_RESULT_HANDLED;
1477 reply = dbus_message_new_method_return (message);
1478 if (reply == NULL)
1479 DIE (("No memory"));
1481 if (!dbus_connection_send (connection, reply, NULL))
1482 DIE (("No memory"));
1484 dbus_message_unref (reply);
1485 return DBUS_HANDLER_RESULT_HANDLED;
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.
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.
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.
1504 * <pre>
1505 * void Device.AddCapability(string capability)
1507 * raises org.freedesktop.Hal.NoSuchDevice,
1508 * raises org.freedesktop.Hal.PermissionDenied,
1509 * </pre>
1511 * @param connection D-BUS connection
1512 * @param message Message
1513 * @return What to do with the message
1515 DBusHandlerResult
1516 device_add_capability (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1518 const char *udi;
1519 const char *capability;
1520 HalDevice *d;
1521 DBusMessage *reply;
1522 DBusError error;
1524 HAL_TRACE (("entering"));
1526 if (!local_interface && !sender_has_privileges (connection, message)) {
1527 raise_permission_denied (connection, message, "AddCapability: not privileged");
1528 return DBUS_HANDLER_RESULT_HANDLED;
1531 udi = dbus_message_get_path (message);
1533 d = hal_device_store_find (hald_get_gdl (), udi);
1534 if (d == NULL)
1535 d = hal_device_store_find (hald_get_tdl (), udi);
1537 if (d == NULL) {
1538 raise_no_such_device (connection, message, udi);
1539 return DBUS_HANDLER_RESULT_HANDLED;
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;
1551 hal_device_add_capability (d, capability);
1553 reply = dbus_message_new_method_return (message);
1554 if (reply == NULL)
1555 DIE (("No memory"));
1557 if (!dbus_connection_send (connection, reply, NULL))
1558 DIE (("No memory"));
1560 dbus_message_unref (reply);
1561 return DBUS_HANDLER_RESULT_HANDLED;
1565 /* TODO: docs */
1566 static DBusHandlerResult
1567 device_string_list_append_prepend (DBusConnection * connection, DBusMessage * message, dbus_bool_t do_prepend)
1569 const char *udi;
1570 const char *key;
1571 const char *value;
1572 HalDevice *d;
1573 DBusMessage *reply;
1574 DBusError error;
1575 gboolean ret;
1577 HAL_TRACE (("entering"));
1579 udi = dbus_message_get_path (message);
1581 d = hal_device_store_find (hald_get_gdl (), udi);
1582 if (d == NULL)
1583 d = hal_device_store_find (hald_get_tdl (), udi);
1585 if (d == NULL) {
1586 raise_no_such_device (connection, message, udi);
1587 return DBUS_HANDLER_RESULT_HANDLED;
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;
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;
1608 reply = dbus_message_new_method_return (message);
1609 if (reply == NULL)
1610 DIE (("No memory"));
1612 if (!dbus_connection_send (connection, reply, NULL))
1613 DIE (("No memory"));
1615 dbus_message_unref (reply);
1616 return DBUS_HANDLER_RESULT_HANDLED;
1619 /* TODO: docs */
1620 static DBusHandlerResult
1621 device_string_list_remove (DBusConnection * connection, DBusMessage * message)
1623 const char *udi;
1624 const char *key;
1625 const char *value;
1626 HalDevice *d;
1627 DBusMessage *reply;
1628 DBusError error;
1629 gboolean ret;
1631 HAL_TRACE (("entering"));
1633 udi = dbus_message_get_path (message);
1635 d = hal_device_store_find (hald_get_gdl (), udi);
1636 if (d == NULL)
1637 d = hal_device_store_find (hald_get_tdl (), udi);
1639 if (d == NULL) {
1640 raise_no_such_device (connection, message, udi);
1641 return DBUS_HANDLER_RESULT_HANDLED;
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;
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;
1659 reply = dbus_message_new_method_return (message);
1660 if (reply == NULL)
1661 DIE (("No memory"));
1663 if (!dbus_connection_send (connection, reply, NULL))
1664 DIE (("No memory"));
1666 dbus_message_unref (reply);
1667 return DBUS_HANDLER_RESULT_HANDLED;
1672 /** Remove a property on a device.
1674 * <pre>
1675 * void Device.RemoveProperty(string key)
1677 * raises org.freedesktop.Hal.NoSuchDevice,
1678 * org.freedesktop.Hal.NoSuchProperty
1679 * org.freedesktop.Hal.PermissionDenied
1680 * </pre>
1682 * @param connection D-BUS connection
1683 * @param message Message
1684 * @return What to do with the message
1686 DBusHandlerResult
1687 device_remove_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1689 const char *udi;
1690 char *key;
1691 HalDevice *d;
1692 DBusMessage *reply;
1693 DBusError error;
1695 HAL_TRACE (("entering"));
1697 udi = dbus_message_get_path (message);
1699 if (!local_interface && !sender_has_privileges (connection, message)) {
1700 raise_permission_denied (connection, message, "RemoveProperty: not privileged");
1701 return DBUS_HANDLER_RESULT_HANDLED;
1704 d = hal_device_store_find (hald_get_gdl (), udi);
1705 if (d == NULL)
1706 d = hal_device_store_find (hald_get_tdl (), udi);
1708 if (d == NULL) {
1709 raise_no_such_device (connection, message, udi);
1710 return DBUS_HANDLER_RESULT_HANDLED;
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;
1721 if (!hal_device_property_remove (d, key)) {
1722 raise_no_such_property (connection, message, udi, key);
1723 return DBUS_HANDLER_RESULT_HANDLED;
1727 reply = dbus_message_new_method_return (message);
1728 if (reply == NULL)
1729 DIE (("No memory"));
1731 if (!dbus_connection_send (connection, reply, NULL))
1732 DIE (("No memory"));
1734 dbus_message_unref (reply);
1735 return DBUS_HANDLER_RESULT_HANDLED;
1739 /** Determine if a property exists
1741 * <pre>
1742 * bool Device.PropertyExists(string key)
1744 * raises org.freedesktop.Hal.NoSuchDevice,
1745 * </pre>
1747 * @param connection D-BUS connection
1748 * @param message Message
1749 * @return What to do with the message
1751 DBusHandlerResult
1752 device_property_exists (DBusConnection * connection, DBusMessage * message)
1754 const char *udi;
1755 char *key;
1756 HalDevice *d;
1757 DBusMessage *reply;
1758 DBusError error;
1759 DBusMessageIter iter;
1760 dbus_bool_t b;
1762 HAL_TRACE (("entering"));
1764 udi = dbus_message_get_path (message);
1766 d = hal_device_store_find (hald_get_gdl (), udi);
1767 if (d == NULL)
1768 d = hal_device_store_find (hald_get_tdl (), udi);
1770 if (d == NULL) {
1771 raise_no_such_device (connection, message, udi);
1772 return DBUS_HANDLER_RESULT_HANDLED;
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;
1783 reply = dbus_message_new_method_return (message);
1784 if (reply == NULL)
1785 DIE (("No memory"));
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);
1791 if (!dbus_connection_send (connection, reply, NULL))
1792 DIE (("No memory"));
1794 dbus_message_unref (reply);
1795 return DBUS_HANDLER_RESULT_HANDLED;
1799 /** Determine if a device has a capability
1801 * <pre>
1802 * bool Device.QueryCapability(string capability_name)
1804 * raises org.freedesktop.Hal.NoSuchDevice,
1805 * </pre>
1807 * @param connection D-BUS connection
1808 * @param message Message
1809 * @return What to do with the message
1811 DBusHandlerResult
1812 device_query_capability (DBusConnection * connection,
1813 DBusMessage * message)
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;
1824 HAL_TRACE (("entering"));
1826 udi = dbus_message_get_path (message);
1828 d = hal_device_store_find (hald_get_gdl (), udi);
1829 if (d == NULL)
1830 d = hal_device_store_find (hald_get_tdl (), udi);
1832 if (d == NULL) {
1833 raise_no_such_device (connection, message, udi);
1834 return DBUS_HANDLER_RESULT_HANDLED;
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;
1845 reply = dbus_message_new_method_return (message);
1846 if (reply == NULL)
1847 DIE (("No memory"));
1849 rc = FALSE;
1850 caps = hal_device_property_get_strlist (d, "info.capabilities");
1851 if (caps != NULL) {
1852 GSList *iter;
1854 for (iter = caps; iter != NULL; iter=g_slist_next(iter)) {
1855 if (strcmp (iter->data, capability) == 0) {
1856 rc = TRUE;
1857 break;
1862 dbus_message_iter_init_append (reply, &iter);
1863 dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rc);
1865 if (!dbus_connection_send (connection, reply, NULL))
1866 DIE (("No memory"));
1868 dbus_message_unref (reply);
1869 return DBUS_HANDLER_RESULT_HANDLED;
1872 static GHashTable *services_with_locks = NULL;
1874 /** Grab an advisory lock on a device.
1876 * <pre>
1877 * bool Device.Lock(string reason)
1879 * raises org.freedesktop.Hal.NoSuchDevice,
1880 * org.freedesktop.Hal.DeviceAlreadyLocked
1881 * </pre>
1883 * @param connection D-BUS connection
1884 * @param message Message
1885 * @return What to do with the message
1887 DBusHandlerResult
1888 device_lock (DBusConnection * connection,
1889 DBusMessage * message)
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;
1899 HAL_TRACE (("entering"));
1901 udi = dbus_message_get_path (message);
1903 d = hal_device_store_find (hald_get_gdl (), udi);
1904 if (d == NULL)
1905 d = hal_device_store_find (hald_get_tdl (), udi);
1907 if (d == NULL) {
1908 raise_no_such_device (connection, message, udi);
1909 return DBUS_HANDLER_RESULT_HANDLED;
1912 already_locked = hal_device_property_get_bool (d, "info.locked");
1914 if (already_locked) {
1915 raise_device_already_locked (connection, message, d);
1916 return DBUS_HANDLER_RESULT_HANDLED;
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;
1927 reply = dbus_message_new_method_return (message);
1928 if (reply == NULL)
1929 DIE (("No memory"));
1931 sender = dbus_message_get_sender (message);
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);
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);
1946 g_hash_table_insert (services_with_locks, g_strdup (sender),
1947 g_object_ref (d));
1949 if (!dbus_connection_send (connection, reply, NULL))
1950 DIE (("No memory"));
1952 dbus_message_unref (reply);
1953 return DBUS_HANDLER_RESULT_HANDLED;
1956 /** Release an advisory lock on a device.
1958 * <pre>
1959 * bool Device.Unlock()
1961 * raises org.freedesktop.Hal.NoSuchDevice,
1962 * org.freedesktop.Hal.DeviceNotLocked,
1963 * org.freedesktop.Hal.PermissionDenied
1964 * </pre>
1966 * @param connection D-BUS connection
1967 * @param message Message
1968 * @return What to do with the message
1970 DBusHandlerResult
1971 device_unlock (DBusConnection * connection,
1972 DBusMessage * message)
1974 dbus_bool_t rc;
1975 const char *udi;
1976 HalDevice *d;
1977 DBusMessage *reply;
1978 DBusError error;
1979 const char *sender;
1981 HAL_TRACE (("entering"));
1983 udi = dbus_message_get_path (message);
1985 d = hal_device_store_find (hald_get_gdl (), udi);
1986 if (d == NULL)
1987 d = hal_device_store_find (hald_get_tdl (), udi);
1989 if (d == NULL) {
1990 raise_no_such_device (connection, message, udi);
1991 return DBUS_HANDLER_RESULT_HANDLED;
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;
2001 reply = dbus_message_new_method_return (message);
2002 if (reply == NULL)
2003 DIE (("No memory"));
2005 rc = hal_device_property_get_bool (d, "info.locked");
2007 if (!rc) {
2008 raise_device_not_locked (connection, message, d);
2009 return DBUS_HANDLER_RESULT_HANDLED;
2012 sender = dbus_message_get_sender (message);
2014 if (strcmp (sender, hal_device_property_get_string (
2015 d, "info.locked.dbus_name")) != 0) {
2016 char *reason;
2018 reason = g_strdup_printf ("Service '%s' does not own the "
2019 "lock on %s", sender,
2020 hal_device_get_udi (d));
2022 raise_permission_denied (connection, message, reason);
2024 g_free (reason);
2026 return DBUS_HANDLER_RESULT_HANDLED;
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));
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");
2040 /* FIXME? Pointless? */
2041 if (!dbus_connection_send (connection, reply, NULL))
2042 DIE (("No memory"));
2044 dbus_message_unref (reply);
2045 return DBUS_HANDLER_RESULT_HANDLED;
2048 static GHashTable *services_with_claims = NULL;
2050 /** Claim a branch.
2052 * <pre>
2053 * bool Manager.ClaimBranch(string udi, string claim_service)
2054 * </pre>
2056 * @param connection D-BUS connection
2057 * @param message Message
2058 * @return What to do with the message
2060 DBusHandlerResult
2061 manager_claim_branch (DBusConnection * connection, DBusMessage * message)
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;
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;
2082 HAL_TRACE (("entering, udi=%s", udi));
2084 d = hal_device_store_find (hald_get_gdl (), udi);
2086 if (d == NULL) {
2087 raise_no_such_device (connection, message, udi);
2088 return DBUS_HANDLER_RESULT_HANDLED;
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;
2097 reply = dbus_message_new_method_return (message);
2098 if (reply == NULL)
2099 DIE (("No memory"));
2101 sender = dbus_message_get_sender (message);
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;
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);
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);
2124 g_hash_table_insert (services_with_claims, g_strdup (sender),
2125 g_object_ref (d));
2127 if (!dbus_connection_send (connection, reply, NULL))
2128 DIE (("No memory"));
2130 dbus_message_unref (reply);
2131 return DBUS_HANDLER_RESULT_HANDLED;
2134 /** Unclaim a branch.
2136 * <pre>
2137 * bool Manager.UnclaimBranch(string udi)
2138 * </pre>
2140 * @param connection D-BUS connection
2141 * @param message Message
2142 * @return What to do with the message
2144 DBusHandlerResult
2145 manager_unclaim_branch (DBusConnection * connection, DBusMessage * message)
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;
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;
2164 HAL_TRACE (("entering, udi=%s", udi));
2166 d = hal_device_store_find (hald_get_gdl (), udi);
2168 if (d == NULL) {
2169 raise_no_such_device (connection, message, udi);
2170 return DBUS_HANDLER_RESULT_HANDLED;
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;
2179 reply = dbus_message_new_method_return (message);
2180 if (reply == NULL)
2181 DIE (("No memory"));
2183 if (strcmp (sender, hal_device_property_get_string (
2184 d, "info.claimed.dbus_name")) != 0) {
2185 char *reason;
2187 reason = g_strdup_printf ("Service '%s' does not own the "
2188 "claim on %s", sender,
2189 hal_device_get_udi (d));
2191 raise_permission_denied (connection, message, reason);
2193 g_free (reason);
2195 return DBUS_HANDLER_RESULT_HANDLED;
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));
2205 hal_util_branch_claim (hald_get_gdl (), d, FALSE, NULL, 0);
2206 hal_device_property_remove (d, "info.claimed.dbus_name");
2208 if (!dbus_connection_send (connection, reply, NULL))
2209 DIE (("No memory"));
2211 dbus_message_unref (reply);
2212 return DBUS_HANDLER_RESULT_HANDLED;
2216 /** Counter for atomic updating */
2217 static int atomic_count = 0;
2219 /** Number of updates pending */
2220 static int num_pending_updates = 0;
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;
2231 static PendingUpdate *pending_updates_head = NULL;
2233 /** Begin an atomic update - this is useful for updating several properties
2234 * in one go.
2236 * Note that an atomic update is recursive - use with caution!
2238 void
2239 device_property_atomic_update_begin (void)
2241 atomic_count++;
2244 /** End an atomic update.
2246 * Note that an atomic update is recursive - use with caution!
2248 void
2249 device_property_atomic_update_end (void)
2251 PendingUpdate *pu_iter = NULL;
2252 PendingUpdate *pu_iter_next = NULL;
2253 PendingUpdate *pu_iter2 = NULL;
2255 --atomic_count;
2257 if (atomic_count < 0) {
2258 HAL_WARNING (("*** atomic_count = %d < 0 !!", atomic_count));
2259 atomic_count = 0;
2262 if (atomic_count == 0 && num_pending_updates > 0) {
2263 DBusMessage *message;
2264 DBusMessageIter iter;
2265 DBusMessageIter iter_array;
2267 for (pu_iter = pending_updates_head;
2268 pu_iter != NULL; pu_iter = pu_iter_next) {
2269 int num_updates_this;
2271 pu_iter_next = pu_iter->next;
2273 /* see if we've already processed this */
2274 if (pu_iter->udi == NULL)
2275 goto already_processed;
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++;
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);
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);
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));
2322 dbus_message_iter_close_container (&iter_array, &iter_struct);
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;
2333 g_free (pu_iter->udi);
2334 dbus_message_iter_close_container (&iter, &iter_array);
2336 if (dbus_connection != NULL) {
2337 if (!dbus_connection_send (dbus_connection, message, NULL))
2338 DIE (("error broadcasting message"));
2341 dbus_message_unref (message);
2343 already_processed:
2344 g_free (pu_iter);
2346 } /* for all updates */
2348 num_pending_updates = 0;
2349 pending_updates_head = NULL;
2355 void
2356 device_send_signal_property_modified (HalDevice *device, const char *key,
2357 dbus_bool_t added, dbus_bool_t removed)
2359 const char *udi = hal_device_get_udi (device);
2360 DBusMessage *message;
2361 DBusMessageIter iter;
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"));
2371 if (atomic_count > 0) {
2372 PendingUpdate *pu;
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;
2381 pending_updates_head = pu;
2382 num_pending_updates++;
2383 } else {
2384 dbus_int32_t i;
2385 DBusMessageIter iter_struct;
2386 DBusMessageIter iter_array;
2388 if (dbus_connection == NULL)
2389 goto out;
2391 message = dbus_message_new_signal (udi,
2392 "org.freedesktop.Hal.Device",
2393 "PropertyModified");
2395 dbus_message_iter_init_append (message, &iter);
2396 i = 1;
2397 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
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);
2408 dbus_message_iter_open_container (&iter_array,
2409 DBUS_TYPE_STRUCT,
2410 NULL,
2411 &iter_struct);
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);
2417 dbus_message_iter_close_container (&iter_array, &iter_struct);
2418 dbus_message_iter_close_container (&iter, &iter_array);
2420 if (!dbus_connection_send (dbus_connection, message, NULL))
2421 DIE (("error broadcasting message"));
2423 dbus_message_unref (message);
2425 out:
2429 /** Emits a condition on a device; the device has to be in the GDL for
2430 * this function to have effect.
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).
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.
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
2448 void
2449 device_send_signal_condition (HalDevice *device, const char *condition_name, const char *condition_details)
2451 const char *udi = hal_device_get_udi (device);
2452 DBusMessage *message;
2453 DBusMessageIter iter;
2455 if (dbus_connection == NULL)
2456 goto out;
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);
2469 if (!dbus_connection_send (dbus_connection, message, NULL))
2470 DIE (("error broadcasting message"));
2472 dbus_message_unref (message);
2473 out:
2474 return;
2479 static gboolean
2480 reinit_dbus (gpointer user_data)
2482 HAL_INFO (("entering!"));
2483 if (hald_dbus_init ())
2484 return FALSE;
2485 else
2486 return TRUE;
2489 static void
2490 service_deleted (DBusMessage *message)
2492 char *old_service_name;
2493 char *new_service_name;
2494 HalDevice *d;
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;
2504 if (services_with_locks != NULL) {
2505 d = g_hash_table_lookup (services_with_locks, new_service_name);
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");
2512 g_hash_table_remove (services_with_locks, new_service_name);
2516 if (services_with_claims != NULL) {
2517 d = g_hash_table_lookup (services_with_claims, new_service_name);
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");
2523 g_hash_table_remove (services_with_claims, new_service_name);
2528 static DBusHandlerResult
2529 device_rescan (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2531 const char *udi;
2532 HalDevice *device;
2533 DBusMessage *reply;
2534 DBusMessageIter iter;
2535 gboolean res;
2537 HAL_INFO (("entering, local_interface=%d", local_interface));
2539 udi = dbus_message_get_path (message);
2541 if (!local_interface && !sender_has_privileges (connection, message)) {
2542 raise_permission_denied (connection, message, "Rescan: not privileged");
2543 return DBUS_HANDLER_RESULT_HANDLED;
2546 HAL_DEBUG (("udi=%s", udi));
2548 device = hal_device_store_find (hald_get_gdl (), udi);
2549 if (device == NULL)
2550 device = hal_device_store_find (hald_get_tdl (), udi);
2552 if (device == NULL) {
2553 raise_no_such_device (connection, message, udi);
2554 return DBUS_HANDLER_RESULT_HANDLED;
2557 res = osspec_device_rescan (device);
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);
2565 if (!dbus_connection_send (connection, reply, NULL))
2566 DIE (("No memory"));
2568 dbus_message_unref (reply);
2569 return DBUS_HANDLER_RESULT_HANDLED;
2572 static DBusHandlerResult
2573 device_reprobe (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2575 const char *udi;
2576 HalDevice *device;
2577 DBusMessageIter iter;
2578 DBusMessage *reply;
2579 gboolean res;
2581 HAL_TRACE (("entering"));
2583 udi = dbus_message_get_path (message);
2585 if (!local_interface && !sender_has_privileges (connection, message)) {
2586 raise_permission_denied (connection, message, "Reprobe: not privileged");
2587 return DBUS_HANDLER_RESULT_HANDLED;
2590 HAL_DEBUG (("udi=%s", udi));
2592 device = hal_device_store_find (hald_get_gdl (), udi);
2593 if (device == NULL)
2594 device = hal_device_store_find (hald_get_tdl (), udi);
2596 if (device == NULL) {
2597 raise_no_such_device (connection, message, udi);
2598 return DBUS_HANDLER_RESULT_HANDLED;
2601 res = osspec_device_reprobe (device);
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);
2609 if (!dbus_connection_send (connection, reply, NULL))
2610 DIE (("No memory"));
2612 dbus_message_unref (reply);
2613 return DBUS_HANDLER_RESULT_HANDLED;
2617 static DBusHandlerResult
2618 device_emit_condition (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
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;
2629 HAL_TRACE (("entering"));
2631 udi = dbus_message_get_path (message);
2633 if (!local_interface) {
2634 raise_permission_denied (connection, message, "EmitCondition: only allowed for helpers");
2635 return DBUS_HANDLER_RESULT_HANDLED;
2638 HAL_DEBUG (("udi=%s", udi));
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;
2650 device = hal_device_store_find (hald_get_gdl (), udi);
2651 if (device == NULL)
2652 device = hal_device_store_find (hald_get_tdl (), udi);
2654 if (device == NULL) {
2655 raise_no_such_device (connection, message, udi);
2656 return DBUS_HANDLER_RESULT_HANDLED;
2659 device_send_signal_condition (device, condition_name, condition_details);
2661 res = TRUE;
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);
2669 if (!dbus_connection_send (connection, reply, NULL))
2670 DIE (("No memory"));
2672 dbus_message_unref (reply);
2673 return DBUS_HANDLER_RESULT_HANDLED;
2676 typedef struct
2678 DBusConnection *connection;
2679 char *interface_name;
2680 char *introspection_xml;
2681 char *udi;
2682 } HelperInterfaceHandler;
2684 static GSList *helper_interface_handlers = NULL;
2686 static DBusHandlerResult
2687 device_claim_interface (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
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;
2698 HAL_TRACE (("entering"));
2700 udi = dbus_message_get_path (message);
2702 if (!local_interface) {
2703 raise_permission_denied (connection, message, "ClaimInterface: only allowed for helpers");
2704 return DBUS_HANDLER_RESULT_HANDLED;
2707 HAL_DEBUG (("udi=%s", udi));
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;
2718 device = hal_device_store_find (hald_get_gdl (), udi);
2719 if (device == NULL)
2720 device = hal_device_store_find (hald_get_tdl (), udi);
2722 if (device == NULL) {
2723 raise_no_such_device (connection, message, udi);
2724 return DBUS_HANDLER_RESULT_HANDLED;
2727 res = TRUE;
2729 HAL_INFO (("Local connection 0x%x to handle interface '%s' on udi '%s'",
2730 connection,
2731 interface_name,
2732 udi));
2734 hal_device_property_strlist_add (device, "info.interfaces", interface_name);
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);
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);
2750 if (!dbus_connection_send (connection, reply, NULL))
2751 DIE (("No memory"));
2753 dbus_message_unref (reply);
2754 return DBUS_HANDLER_RESULT_HANDLED;
2759 static DBusHandlerResult
2760 addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2762 const char *udi;
2763 HalDevice *device;
2764 DBusMessageIter iter;
2765 DBusMessage *reply;
2766 DBusError error;
2767 dbus_bool_t res;
2769 HAL_TRACE (("entering"));
2771 udi = dbus_message_get_path (message);
2773 if (!local_interface) {
2774 raise_permission_denied (connection, message, "AddonIsReady: only allowed for helpers");
2775 return DBUS_HANDLER_RESULT_HANDLED;
2778 HAL_DEBUG (("udi=%s", udi));
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;
2787 device = hal_device_store_find (hald_get_gdl (), udi);
2788 if (device == NULL)
2789 device = hal_device_store_find (hald_get_tdl (), udi);
2791 if (device == NULL) {
2792 raise_no_such_device (connection, message, udi);
2793 return DBUS_HANDLER_RESULT_HANDLED;
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);
2802 res = TRUE;
2804 HAL_INFO (("AddonIsReady on udi '%s'", udi));
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);
2812 if (!dbus_connection_send (connection, reply, NULL))
2813 DIE (("No memory"));
2815 dbus_message_unref (reply);
2816 return DBUS_HANDLER_RESULT_HANDLED;
2821 * Create new device in tdl. Return temporary udi.
2823 DBusHandlerResult
2824 manager_new_device (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2826 DBusMessage *reply;
2827 DBusMessageIter iter;
2828 DBusError error;
2829 HalDevice *d;
2830 gchar *udi;
2831 int i;
2832 struct timeval tv;
2834 dbus_error_init (&error);
2836 if (!local_interface && !sender_has_privileges (connection, message)) {
2837 raise_permission_denied (connection, message, "NewDevice: not privileged");
2838 return DBUS_HANDLER_RESULT_HANDLED;
2841 reply = dbus_message_new_method_return (message);
2842 if (reply == NULL)
2843 DIE (("No memory"));
2845 dbus_message_iter_init_append (reply, &iter);
2846 d = hal_device_new ();
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;
2856 if (!udi) {
2857 raise_error (connection, message, "org.freedesktop.Hal.NoSpace", "NewDevice: no space for device");
2858 return DBUS_HANDLER_RESULT_HANDLED;
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);
2867 if (!dbus_connection_send (connection, reply, NULL))
2868 DIE (("No memory"));
2870 dbus_message_unref (reply);
2872 return DBUS_HANDLER_RESULT_HANDLED;
2877 * Callout helper.
2879 static void
2880 manager_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2882 HAL_INFO (("Remove callouts completed udi=%s", d->udi));
2884 if (!hal_device_store_remove (hald_get_gdl (), d)) {
2885 HAL_WARNING (("Error removing device"));
2891 * Remove device. Looks in gdl and tdl.
2893 DBusHandlerResult
2894 manager_remove (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2896 DBusMessage *reply;
2897 DBusMessageIter iter;
2898 DBusError error;
2899 HalDevice *d;
2900 char *udi;
2901 int in_tdl = 0;
2903 dbus_error_init (&error);
2905 if (!local_interface && !sender_has_privileges (connection, message)) {
2906 raise_permission_denied (connection, message, "Remove: not privileged");
2907 return DBUS_HANDLER_RESULT_HANDLED;
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;
2917 reply = dbus_message_new_method_return (message);
2918 if (reply == NULL)
2919 DIE (("No memory"));
2921 dbus_message_iter_init_append (reply, &iter);
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;
2928 if (d == NULL) {
2929 raise_no_such_device (connection, message, udi);
2930 return DBUS_HANDLER_RESULT_HANDLED;
2933 /* FIXME:
2934 * run "info.callouts.remove" ?
2935 * delete in gdl ?
2936 * (auto) stop "info.addons" ?
2939 if (!in_tdl) {
2940 hal_util_callout_device_remove (d, manager_remove_done, NULL, NULL);
2943 hal_device_store_remove (in_tdl ? hald_get_tdl () : hald_get_gdl (), d);
2944 g_object_unref (d);
2946 if (!dbus_connection_send (connection, reply, NULL))
2947 DIE (("No memory"));
2949 dbus_message_unref (reply);
2951 return DBUS_HANDLER_RESULT_HANDLED;
2956 * Callout helper.
2958 static void
2959 manager_commit_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2961 HAL_INFO (("Add callouts completed udi=%s", d->udi));
2965 * Preprobing helper.
2967 static void
2968 manager_commit_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
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
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");
2979 HAL_INFO (("Preprobing merged info.ignore==TRUE"));
2981 return;
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);
2988 hal_util_callout_device_add (d, manager_commit_done, NULL, NULL);
2993 * Move device from tdl to gdl. Runs helpers and callouts.
2995 DBusHandlerResult
2996 manager_commit_to_gdl (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2998 DBusMessage *reply;
2999 DBusMessageIter iter;
3000 DBusError error;
3001 HalDevice *d;
3002 char udi[256], *udi0, *tmp_udi;
3004 dbus_error_init (&error);
3006 if (!local_interface && !sender_has_privileges (connection, message)) {
3007 raise_permission_denied (connection, message, "CommitToGdl: not privileged");
3008 return DBUS_HANDLER_RESULT_HANDLED;
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;
3019 reply = dbus_message_new_method_return (message);
3020 if (reply == NULL)
3021 DIE (("No memory"));
3023 dbus_message_iter_init_append (reply, &iter);
3025 /* look it up in tdl */
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;
3033 /* sanity check & avoid races */
3034 hal_util_compute_udi (hald_get_gdl (), udi, sizeof udi, "%s", udi0);
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;
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);
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"?
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);
3065 /* move from tdl to gdl */
3066 hal_device_store_remove (hald_get_tdl (), d);
3067 hal_device_store_add (hald_get_gdl (), d);
3069 if (!dbus_connection_send (connection, reply, NULL))
3070 DIE (("No memory"));
3072 dbus_message_unref (reply);
3074 return DBUS_HANDLER_RESULT_HANDLED;
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;
3088 static void
3089 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3090 gint return_code, gchar **error,
3091 gpointer data1, gpointer data2);
3094 static void
3095 hald_exec_method_free_mi (MethodInvocation *mi)
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);
3107 /* returns FALSE if we don't actually invoke anything */
3108 static gboolean
3109 hald_exec_method_do_invocation (MethodInvocation *mi)
3111 gboolean ret;
3112 HalDevice *d;
3114 ret = FALSE;
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);
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,
3128 hald_exec_method_cb,
3129 (gpointer) mi->message,
3130 (gpointer) mi->connection);
3132 ret = TRUE;
3133 } else {
3134 HAL_WARNING (("In-queue method call on non-existant device"));
3136 raise_no_such_device (mi->connection, mi->message, mi->udi);
3139 return ret;
3143 static GHashTable *udi_to_method_queue = NULL;
3146 gboolean
3147 device_is_executing_method (HalDevice *d, const char *interface_name, const char *method_name)
3149 gpointer origkey;
3150 gboolean ret;
3151 GList *queue;
3153 ret = FALSE;
3155 if (g_hash_table_lookup_extended (udi_to_method_queue, d->udi, &origkey, (gpointer) &queue)) {
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;
3166 ret = TRUE;
3168 return ret;
3171 static void
3172 hald_exec_method_process_queue (const char *udi);
3174 static void
3175 hald_exec_method_enqueue (MethodInvocation *mi)
3177 gpointer origkey;
3178 GList *queue;
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);
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);
3196 hald_exec_method_do_invocation (mi);
3201 static void
3202 hald_exec_method_process_queue (const char *udi)
3204 gpointer origkey;
3205 GList *queue;
3206 MethodInvocation *mi;
3208 if (g_hash_table_lookup_extended (udi_to_method_queue, udi, &origkey, (gpointer) &queue)) {
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"));
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;
3224 HAL_INFO (("Refreshing mount state for %s since Unmount() completed", mi->udi));
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);
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));
3238 hald_exec_method_free_mi (mi);
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);
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);
3255 static void
3256 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3257 gint return_code, gchar **error,
3258 gpointer data1, gpointer data2)
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 gboolean invalid_name = FALSE;
3269 hald_exec_method_process_queue (d->udi);
3271 message = (DBusMessage *) data1;
3272 conn = (DBusConnection *) data2;
3274 if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
3275 error[0] != NULL && error[1] != NULL) {
3276 exp_name = error[0];
3277 if (error[0] != NULL) {
3278 exp_detail = error[1];
3280 HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
3283 if (exit_type != HALD_RUN_SUCCESS) {
3284 reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3285 if (conn != NULL) {
3286 if (!dbus_connection_send (conn, reply, NULL))
3287 DIE (("No memory"));
3289 dbus_message_unref (reply);
3290 } else if (exp_name != NULL && exp_detail != NULL) {
3291 if (!is_valid_interface_name (exp_name)) {
3293 * error name may be invalid,
3294 * if so we need a generic HAL error name;
3295 * otherwise, dbus will be messed up.
3297 invalid_name = TRUE;
3298 exp_detail = g_strconcat (exp_name, " \n ", exp_detail, NULL);
3299 exp_name = "org.freedesktop.Hal.Device.UnknownError";
3301 reply = dbus_message_new_error (message, exp_name, exp_detail);
3302 if (reply == NULL) {
3303 /* error name may be invalid - assume caller fucked up and use a generic HAL error name */
3304 reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3305 if (reply == NULL) {
3306 DIE (("No memory"));
3309 if (conn != NULL) {
3310 if (!dbus_connection_send (conn, reply, NULL))
3311 DIE (("No memory"));
3313 dbus_message_unref (reply);
3315 } else {
3316 result = (dbus_int32_t) return_code;
3318 reply = dbus_message_new_method_return (message);
3319 if (reply == NULL)
3320 DIE (("No memory"));
3322 dbus_message_iter_init_append (reply, &iter);
3323 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &result);
3325 if (conn != NULL) {
3326 if (!dbus_connection_send (conn, reply, NULL))
3327 DIE (("No memory"));
3330 dbus_message_unref (reply);
3333 if (invalid_name)
3334 g_free (exp_detail);
3335 dbus_message_unref (message);
3338 static DBusHandlerResult
3339 hald_exec_method (HalDevice *d, DBusConnection *connection, dbus_bool_t local_interface,
3340 DBusMessage *message, const char *execpath)
3342 int type;
3343 GString *stdin_str;
3344 DBusMessageIter iter;
3345 char *extra_env[3];
3346 char uid_export[128];
3347 char sender_export[128];
3348 MethodInvocation *mi;
3350 /* add calling uid */
3351 extra_env[0] = NULL;
3352 extra_env[1] = NULL;
3353 if (local_interface) {
3354 extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
3355 extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3356 } else {
3357 const char *sender;
3359 sender = dbus_message_get_sender (message);
3360 if (sender != NULL) {
3361 DBusError error;
3362 unsigned long uid;
3364 dbus_error_init (&error);
3365 uid = dbus_bus_get_unix_user (connection, sender, &error);
3366 if (!dbus_error_is_set (&error)) {
3367 sprintf (uid_export, "HAL_METHOD_INVOKED_BY_UID=%lu", uid);
3368 extra_env[0] = uid_export;
3370 snprintf (sender_export, sizeof (sender_export),
3371 "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=%s", sender);
3372 extra_env[1] = sender_export;
3376 if (extra_env[0] == NULL)
3377 extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=nobody";
3378 if (extra_env[1] == NULL)
3379 extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3382 extra_env[2] = NULL;
3384 /* prepare stdin with parameters */
3385 stdin_str = g_string_sized_new (256); /* default size for passing params; can grow */
3386 dbus_message_iter_init (message, &iter);
3387 while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) {
3388 switch (type) {
3389 case DBUS_TYPE_BYTE:
3391 unsigned char value;
3392 dbus_message_iter_get_basic (&iter, &value);
3393 g_string_append_printf (stdin_str, "%u", value);
3394 break;
3396 case DBUS_TYPE_INT16:
3398 dbus_int16_t value;
3399 dbus_message_iter_get_basic (&iter, &value);
3400 g_string_append_printf (stdin_str, "%d", value);
3401 break;
3403 case DBUS_TYPE_UINT16:
3405 dbus_uint16_t value;
3406 dbus_message_iter_get_basic (&iter, &value);
3407 g_string_append_printf (stdin_str, "%u", value);
3408 break;
3410 case DBUS_TYPE_INT32:
3412 dbus_int32_t value;
3413 dbus_message_iter_get_basic (&iter, &value);
3414 g_string_append_printf (stdin_str, "%d", value);
3415 break;
3417 case DBUS_TYPE_UINT32:
3419 dbus_uint32_t value;
3420 dbus_message_iter_get_basic (&iter, &value);
3421 g_string_append_printf (stdin_str, "%u", value);
3422 break;
3424 case DBUS_TYPE_INT64:
3426 dbus_int64_t value;
3427 dbus_message_iter_get_basic (&iter, &value);
3428 g_string_append_printf (stdin_str, "%lld", (long long int) value);
3429 break;
3431 case DBUS_TYPE_UINT64:
3433 dbus_uint64_t value;
3434 dbus_message_iter_get_basic (&iter, &value);
3435 g_string_append_printf (stdin_str, "%llu", (long long unsigned int) value);
3436 break;
3438 case DBUS_TYPE_DOUBLE:
3440 double value;
3441 dbus_message_iter_get_basic (&iter, &value);
3442 g_string_append_printf (stdin_str, "%g", value);
3443 break;
3445 case DBUS_TYPE_BOOLEAN:
3447 dbus_bool_t value;
3448 dbus_message_iter_get_basic (&iter, &value);
3449 g_string_append (stdin_str, value ? "true" : "false");
3450 break;
3452 case DBUS_TYPE_STRING:
3454 char *value;
3455 dbus_message_iter_get_basic (&iter, &value);
3456 g_string_append (stdin_str, value);
3457 break;
3460 case DBUS_TYPE_ARRAY:
3462 DBusMessageIter iter_strlist;
3463 if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)
3464 goto error;
3466 dbus_message_iter_recurse (&iter, &iter_strlist);
3467 while (dbus_message_iter_get_arg_type (&iter_strlist) == DBUS_TYPE_STRING) {
3468 const char *value;
3469 dbus_message_iter_get_basic (&iter_strlist, &value);
3470 g_string_append (stdin_str, value);
3471 g_string_append (stdin_str, "\t");
3472 dbus_message_iter_next(&iter_strlist);
3474 break;
3477 default:
3478 goto error;
3481 g_string_append_c (stdin_str, '\n');
3482 dbus_message_iter_next (&iter);
3485 mi = g_new0 (MethodInvocation, 1);
3486 mi->udi = g_strdup (d->udi);
3487 mi->execpath = g_strdup (execpath);
3488 mi->extra_env = g_strdupv (extra_env);
3489 mi->mstdin = g_strdup (stdin_str->str);
3490 mi->message = message;
3491 mi->connection = connection;
3492 mi->member = g_strdup (dbus_message_get_member (message));
3493 mi->interface = g_strdup (dbus_message_get_interface (message));
3494 hald_exec_method_enqueue (mi);
3496 dbus_message_ref (message);
3497 g_string_free (stdin_str, TRUE);
3499 return DBUS_HANDLER_RESULT_HANDLED;
3501 error:
3502 g_string_free (stdin_str, TRUE);
3503 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3506 static gboolean
3507 foreach_device_get_xml_node (HalDeviceStore *store, HalDevice *device,
3508 gpointer user_data)
3510 GString *xml = user_data;
3511 const char *udi, *name;
3513 udi = hal_device_get_udi (device);
3514 name = strrchr(udi, '/')+1;
3516 xml = g_string_append(xml, " <node name=\"");
3517 xml = g_string_append(xml, name);
3518 xml = g_string_append(xml, "\"/>\n");
3520 return TRUE;
3523 static DBusHandlerResult
3524 do_introspect (DBusConnection *connection,
3525 DBusMessage *message,
3526 dbus_bool_t local_interface)
3528 const char *path;
3529 DBusMessage *reply;
3530 GString *xml;
3531 char *xml_string;
3533 HAL_TRACE (("entering do_introspect"));
3535 path = dbus_message_get_path (message);
3537 xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
3538 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
3539 "<node>\n"
3540 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
3541 " <method name=\"Introspect\">\n"
3542 " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
3543 " </method>\n"
3544 " </interface>\n");
3546 if (strcmp (path, "/") == 0) {
3548 xml = g_string_append (xml,
3549 " <node name=\"org\"/>\n");
3551 } else if (strcmp (path, "/org") == 0) {
3553 xml = g_string_append (xml,
3554 " <node name=\"freedesktop\"/>\n");
3556 } else if (strcmp (path, "/org/freedesktop") == 0) {
3558 xml = g_string_append (xml,
3559 " <node name=\"Hal\"/>\n");
3561 } else if (strcmp (path, "/org/freedesktop/Hal") == 0) {
3563 xml = g_string_append (xml,
3564 " <node name=\"Manager\"/>\n"
3565 " <node name=\"devices\"/>\n");
3567 } else if (strcmp (path, "/org/freedesktop/Hal/devices") == 0) {
3569 hal_device_store_foreach (hald_get_gdl (),
3570 foreach_device_get_xml_node,
3571 xml);
3573 } else if (strcmp (path, "/org/freedesktop/Hal/Manager") == 0) {
3575 xml = g_string_append (xml,
3576 " <interface name=\"org.freedesktop.Hal.Manager\">\n"
3577 " <method name=\"GetAllDevices\">\n"
3578 " <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3579 " </method>\n"
3580 " <method name=\"DeviceExists\">\n"
3581 " <arg name=\"does_it_exist\" direction=\"out\" type=\"b\"/>\n"
3582 " <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3583 " </method>\n"
3584 " <method name=\"FindDeviceStringMatch\">\n"
3585 " <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3586 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3587 " <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3588 " </method>\n"
3589 " <method name=\"FindDeviceByCapability\">\n"
3590 " <arg name=\"devices\" direction=\"out\" type=\"ao\"/>\n"
3591 " <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3592 " </method>\n"
3593 " <method name=\"ClaimBranch\">\n"
3594 " <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3595 " <arg name=\"claim_service\" direction=\"in\" type=\"s\"/>\n"
3596 " <arg name=\"result\" direction=\"out\" type=\"b\"/>\n"
3597 " </method>\n"
3598 " <method name=\"UnclaimBranch\">\n"
3599 " <arg name=\"udi\" direction=\"in\" type=\"o\"/>\n"
3600 " <arg name=\"result\" direction=\"out\" type=\"b\"/>\n"
3601 " </method>\n"
3602 " <method name=\"NewDevice\">\n"
3603 " <arg name=\"temporary_udi\" direction=\"out\" type=\"s\"/>\n"
3604 " </method>\n"
3605 " <method name=\"Remove\">\n"
3606 " <arg name=\"udi\" direction=\"in\" type=\"s\"/>\n"
3607 " </method>\n"
3608 " <method name=\"CommitToGdl\">\n"
3609 " <arg name=\"temporary_udi\" direction=\"in\" type=\"s\"/>\n"
3610 " <arg name=\"global_udi\" direction=\"in\" type=\"s\"/>\n"
3611 " </method>\n"
3612 " </interface>\n");
3613 } else {
3614 HalDevice *d;
3616 d = hal_device_store_find (hald_get_gdl (), path);
3617 if (d == NULL)
3618 d = hal_device_store_find (hald_get_tdl (), path);
3620 if (d == NULL) {
3621 raise_no_such_device (connection, message, path);
3622 return DBUS_HANDLER_RESULT_HANDLED;
3625 xml = g_string_append (xml,
3626 " <interface name=\"org.freedesktop.Hal.Device\">\n"
3627 " <method name=\"GetAllProperties\">\n"
3628 " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n"
3629 " </method>\n"
3630 " <method name=\"SetMultipleProperties\">\n"
3631 " <arg name=\"properties\" direction=\"in\" type=\"a{sv}\"/>\n"
3632 " </method>\n"
3633 " <method name=\"GetProperty\">\n"
3634 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3635 " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"
3636 " </method>\n"
3637 " <method name=\"GetPropertyString\">\n"
3638 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3639 " <arg name=\"value\" direction=\"out\" type=\"s\"/>\n"
3640 " </method>\n"
3641 " <method name=\"GetPropertyStringList\">\n"
3642 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3643 " <arg name=\"value\" direction=\"out\" type=\"as\"/>\n"
3644 " </method>\n"
3645 " <method name=\"GetPropertyInteger\">\n"
3646 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3647 " <arg name=\"value\" direction=\"out\" type=\"i\"/>\n"
3648 " </method>\n"
3649 " <method name=\"GetPropertyBoolean\">\n"
3650 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3651 " <arg name=\"value\" direction=\"out\" type=\"b\"/>\n"
3652 " </method>\n"
3653 " <method name=\"GetPropertyDouble\">\n"
3654 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3655 " <arg name=\"value\" direction=\"out\" type=\"d\"/>\n"
3656 " </method>\n"
3657 " <method name=\"SetProperty\">\n"
3658 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3659 " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"
3660 " </method>\n"
3661 " <method name=\"SetPropertyString\">\n"
3662 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3663 " <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3664 " </method>\n"
3665 " <method name=\"SetPropertyStringList\">\n"
3666 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3667 " <arg name=\"value\" direction=\"in\" type=\"as\"/>\n"
3668 " </method>\n"
3669 " <method name=\"SetPropertyInteger\">\n"
3670 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3671 " <arg name=\"value\" direction=\"in\" type=\"i\"/>\n"
3672 " </method>\n"
3673 " <method name=\"SetPropertyBoolean\">\n"
3674 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3675 " <arg name=\"value\" direction=\"in\" type=\"b\"/>\n"
3676 " </method>\n"
3677 " <method name=\"SetPropertyDouble\">\n"
3678 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3679 " <arg name=\"value\" direction=\"in\" type=\"d\"/>\n"
3680 " </method>\n"
3682 " <method name=\"RemoveProperty\">\n"
3683 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3684 " </method>\n"
3685 " <method name=\"GetPropertyType\">\n"
3686 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3687 " <arg name=\"type\" direction=\"out\" type=\"i\"/>\n"
3688 " </method>\n"
3689 " <method name=\"PropertyExists\">\n"
3690 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3691 " <arg name=\"does_it_exist\" direction=\"out\" type=\"b\"/>\n"
3692 " </method>\n"
3693 " <method name=\"AddCapability\">\n"
3694 " <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3695 " </method>\n"
3696 " <method name=\"QueryCapability\">\n"
3697 " <arg name=\"capability\" direction=\"in\" type=\"s\"/>\n"
3698 " <arg name=\"does_it_have_capability\" direction=\"out\" type=\"b\"/>\n"
3699 " </method>\n"
3700 " <method name=\"Lock\">\n"
3701 " <arg name=\"reason\" direction=\"in\" type=\"s\"/>\n"
3702 " <arg name=\"acquired_lock\" direction=\"out\" type=\"b\"/>\n"
3703 " </method>\n"
3704 " <method name=\"Unlock\">\n"
3705 " <arg name=\"released_lock\" direction=\"out\" type=\"b\"/>\n"
3706 " </method>\n"
3708 " <method name=\"StringListAppend\">\n"
3709 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3710 " <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3711 " </method>\n"
3712 " <method name=\"StringListPrepend\">\n"
3713 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3714 " <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3715 " </method>\n"
3716 " <method name=\"StringListRemove\">\n"
3717 " <arg name=\"key\" direction=\"in\" type=\"s\"/>\n"
3718 " <arg name=\"value\" direction=\"in\" type=\"s\"/>\n"
3719 " </method>\n"
3720 " <method name=\"EmitCondition\">\n"
3721 " <arg name=\"condition_name\" direction=\"in\" type=\"s\"/>\n"
3722 " <arg name=\"condition_details\" direction=\"in\" type=\"s\"/>\n"
3723 " <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3724 " </method>\n"
3726 " <method name=\"Rescan\">\n"
3727 " <arg name=\"call_had_sideeffect\" direction=\"out\" type=\"b\"/>\n"
3728 " </method>\n"
3729 " <method name=\"Reprobe\">\n"
3730 " <arg name=\"call_had_sideeffect\" direction=\"out\" type=\"b\"/>\n"
3731 " </method>\n"
3733 " <method name=\"ClaimInterface\">\n"
3734 " <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
3735 " <arg name=\"introspection_xml\" direction=\"in\" type=\"s\"/>\n"
3736 " <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3737 " </method>\n"
3739 " <method name=\"AddonIsReady\">\n"
3740 " <arg name=\"rc\" direction=\"out\" type=\"b\"/>\n"
3741 " </method>\n"
3743 " </interface>\n");
3745 GSList *interfaces;
3746 GSList *i;
3748 interfaces = hal_device_property_get_strlist (d, "info.interfaces");
3749 for (i = interfaces; i != NULL; i = g_slist_next (i)) {
3750 const char *ifname = (const char *) i->data;
3751 char *method_names_prop;
3752 char *method_signatures_prop;
3753 char *method_argnames_prop;
3754 GSList *method_names;
3755 GSList *method_signatures;
3756 GSList *method_argnames;
3757 GSList *j;
3758 GSList *k;
3759 GSList *l;
3761 g_string_append_printf (xml, " <interface name=\"%s\">\n", ifname);
3763 method_names_prop = g_strdup_printf ("%s.method_names", ifname);
3764 method_signatures_prop = g_strdup_printf ("%s.method_signatures", ifname);
3765 method_argnames_prop = g_strdup_printf ("%s.method_argnames", ifname);
3767 method_names = hal_device_property_get_strlist (d, method_names_prop);
3768 method_signatures = hal_device_property_get_strlist (d, method_signatures_prop);
3769 method_argnames = hal_device_property_get_strlist (d, method_argnames_prop);
3771 /* consult local list */
3772 if (method_names == NULL) {
3773 GSList *i;
3775 for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
3776 HelperInterfaceHandler *hih = i->data;
3777 if (strcmp (hih->udi, path) == 0) {
3778 xml = g_string_append (xml, hih->introspection_xml);
3784 for (j = method_names, k = method_signatures, l = method_argnames;
3785 j != NULL && k != NULL && l != NULL;
3786 j = g_slist_next (j), k = g_slist_next (k), l = g_slist_next (l)) {
3787 const char *name;
3788 const char *sig;
3789 const char *argnames;
3790 char **args;
3791 unsigned int n;
3792 unsigned int m;
3794 name = j->data;
3795 sig = k->data;
3796 argnames = l->data;
3798 args = g_strsplit (argnames, " ", 0);
3800 g_string_append_printf (xml, " <method name=\"%s\">\n", name);
3802 for (n = 0, m = 0; n < strlen (sig) && args[m] != NULL; n++, m++) {
3803 switch (sig[n]) {
3804 case 'a':
3805 if (n == strlen (sig) - 1) {
3806 HAL_WARNING (("Broken signature for method %s "
3807 "on interface %s for object %s",
3808 name, ifname, path));
3809 continue;
3811 g_string_append_printf (
3812 xml,
3813 " <arg name=\"%s\" direction=\"in\" type=\"a%c\"/>\n",
3814 args[m], sig[n + 1]);
3815 n++;
3816 break;
3818 default:
3819 g_string_append_printf (
3820 xml,
3821 " <arg name=\"%s\" direction=\"in\" type=\"%c\"/>\n",
3822 args[m], sig[n]);
3823 break;
3826 xml = g_string_append (
3827 xml,
3828 " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n");
3829 xml = g_string_append (
3830 xml,
3831 " </method>\n");
3836 xml = g_string_append (xml, " </interface>\n");
3838 g_free (method_names_prop);
3839 g_free (method_signatures_prop);
3840 g_free (method_argnames_prop);
3845 reply = dbus_message_new_method_return (message);
3847 xml = g_string_append (xml, "</node>\n");
3848 xml_string = g_string_free (xml, FALSE);
3850 dbus_message_append_args (reply,
3851 DBUS_TYPE_STRING, &xml_string,
3852 DBUS_TYPE_INVALID);
3854 g_free (xml_string);
3856 if (reply == NULL)
3857 DIE (("No memory"));
3859 if (!dbus_connection_send (connection, reply, NULL))
3860 DIE (("No memory"));
3862 dbus_message_unref (reply);
3863 return DBUS_HANDLER_RESULT_HANDLED;
3866 static void
3867 reply_from_fwd_message (DBusPendingCall *pending_call,
3868 void *user_data)
3870 DBusMessage *reply_from_addon;
3871 DBusMessage *method_from_caller;
3872 DBusMessage *reply;
3874 /*HAL_INFO (("in reply_from_fwd_message : user_data = 0x%x", user_data));*/
3876 method_from_caller = (DBusMessage *) user_data;
3877 reply_from_addon = dbus_pending_call_steal_reply (pending_call);
3879 reply = dbus_message_copy (reply_from_addon);
3880 dbus_message_set_destination (reply, dbus_message_get_sender (method_from_caller));
3881 dbus_message_set_reply_serial (reply, dbus_message_get_serial (method_from_caller));
3883 if (dbus_connection != NULL)
3884 dbus_connection_send (dbus_connection, reply, NULL);
3886 dbus_message_unref (reply_from_addon);
3887 dbus_message_unref (reply);
3888 dbus_message_unref (method_from_caller);
3889 dbus_pending_call_unref (pending_call);
3892 static DBusHandlerResult
3893 hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *message,
3894 void *user_data, dbus_bool_t local_interface)
3896 /*HAL_INFO (("connection=0x%x obj_path=%s interface=%s method=%s local_interface=%d",
3897 connection,
3898 dbus_message_get_path (message),
3899 dbus_message_get_interface (message),
3900 dbus_message_get_member (message),
3901 local_interface));*/
3903 if (dbus_message_is_method_call (message,
3904 "org.freedesktop.Hal.Manager",
3905 "GetAllDevices") &&
3906 strcmp (dbus_message_get_path (message),
3907 "/org/freedesktop/Hal/Manager") == 0) {
3908 return manager_get_all_devices (connection, message);
3909 } else if (dbus_message_is_method_call (message,
3910 "org.freedesktop.Hal.Manager",
3911 "DeviceExists") &&
3912 strcmp (dbus_message_get_path (message),
3913 "/org/freedesktop/Hal/Manager") == 0) {
3914 return manager_device_exists (connection, message);
3915 } else if (dbus_message_is_method_call (message,
3916 "org.freedesktop.Hal.Manager",
3917 "FindDeviceStringMatch") &&
3918 strcmp (dbus_message_get_path (message),
3919 "/org/freedesktop/Hal/Manager") == 0) {
3920 return manager_find_device_string_match (connection,
3921 message);
3922 } else if (dbus_message_is_method_call
3923 (message, "org.freedesktop.Hal.Manager",
3924 "FindDeviceByCapability")
3925 && strcmp (dbus_message_get_path (message),
3926 "/org/freedesktop/Hal/Manager") == 0) {
3927 return manager_find_device_by_capability (connection,
3928 message);
3929 } else if (dbus_message_is_method_call (message,
3930 "org.freedesktop.Hal.Manager",
3931 "ClaimBranch") &&
3932 strcmp (dbus_message_get_path (message),
3933 "/org/freedesktop/Hal/Manager") == 0) {
3934 return manager_claim_branch (connection, message);
3935 } else if (dbus_message_is_method_call (message,
3936 "org.freedesktop.Hal.Manager",
3937 "UnclaimBranch") &&
3938 strcmp (dbus_message_get_path (message),
3939 "/org/freedesktop/Hal/Manager") == 0) {
3940 return manager_unclaim_branch (connection, message);
3941 } else if (dbus_message_is_method_call (message,
3942 "org.freedesktop.Hal.Manager",
3943 "NewDevice") &&
3944 strcmp (dbus_message_get_path (message),
3945 "/org/freedesktop/Hal/Manager") == 0) {
3946 return manager_new_device (connection, message, local_interface);
3947 } else if (dbus_message_is_method_call (message,
3948 "org.freedesktop.Hal.Manager",
3949 "Remove") &&
3950 strcmp (dbus_message_get_path (message),
3951 "/org/freedesktop/Hal/Manager") == 0) {
3952 return manager_remove (connection, message, local_interface);
3953 } else if (dbus_message_is_method_call (message,
3954 "org.freedesktop.Hal.Manager",
3955 "CommitToGdl") &&
3956 strcmp (dbus_message_get_path (message),
3957 "/org/freedesktop/Hal/Manager") == 0) {
3958 return manager_commit_to_gdl (connection, message, local_interface);
3959 } else if (dbus_message_is_method_call (message,
3960 "org.freedesktop.Hal.Device",
3961 "GetAllProperties")) {
3962 return device_get_all_properties (connection, message);
3963 } else if (dbus_message_is_method_call (message,
3964 "org.freedesktop.Hal.Device",
3965 "SetMultipleProperties")) {
3966 return device_set_multiple_properties (connection, message, local_interface);
3967 } else if (dbus_message_is_method_call (message,
3968 "org.freedesktop.Hal.Device",
3969 "GetProperty")) {
3970 return device_get_property (connection, message);
3971 } else if (dbus_message_is_method_call (message,
3972 "org.freedesktop.Hal.Device",
3973 "GetPropertyString")) {
3974 return device_get_property (connection, message);
3975 } else if (dbus_message_is_method_call (message,
3976 "org.freedesktop.Hal.Device",
3977 "GetPropertyStringList")) {
3978 return device_get_property (connection, message);
3979 } else if (dbus_message_is_method_call (message,
3980 "org.freedesktop.Hal.Device",
3981 "GetPropertyInteger")) {
3982 return device_get_property (connection, message);
3983 } else if (dbus_message_is_method_call (message,
3984 "org.freedesktop.Hal.Device",
3985 "GetPropertyBoolean")) {
3986 return device_get_property (connection, message);
3987 } else if (dbus_message_is_method_call (message,
3988 "org.freedesktop.Hal.Device",
3989 "GetPropertyDouble")) {
3990 return device_get_property (connection, message);
3991 } else if (dbus_message_is_method_call (message,
3992 "org.freedesktop.Hal.Device",
3993 "SetProperty")) {
3994 return device_set_property (connection, message, local_interface);
3995 } else if (dbus_message_is_method_call (message,
3996 "org.freedesktop.Hal.Device",
3997 "SetPropertyString")) {
3998 return device_set_property (connection, message, local_interface);
3999 } else if (dbus_message_is_method_call (message,
4000 "org.freedesktop.Hal.Device",
4001 "SetPropertyInteger")) {
4002 return device_set_property (connection, message, local_interface);
4003 } else if (dbus_message_is_method_call (message,
4004 "org.freedesktop.Hal.Device",
4005 "SetPropertyBoolean")) {
4006 return device_set_property (connection, message, local_interface);
4007 } else if (dbus_message_is_method_call (message,
4008 "org.freedesktop.Hal.Device",
4009 "SetPropertyDouble")) {
4010 return device_set_property (connection, message, local_interface);
4011 } else if (dbus_message_is_method_call (message,
4012 "org.freedesktop.Hal.Device",
4013 "RemoveProperty")) {
4014 return device_remove_property (connection, message, local_interface);
4015 } else if (dbus_message_is_method_call (message,
4016 "org.freedesktop.Hal.Device",
4017 "GetPropertyType")) {
4018 return device_get_property_type (connection, message);
4019 } else if (dbus_message_is_method_call (message,
4020 "org.freedesktop.Hal.Device",
4021 "PropertyExists")) {
4022 return device_property_exists (connection, message);
4023 } else if (dbus_message_is_method_call (message,
4024 "org.freedesktop.Hal.Device",
4025 "AddCapability")) {
4026 return device_add_capability (connection, message, local_interface);
4027 } else if (dbus_message_is_method_call (message,
4028 "org.freedesktop.Hal.Device",
4029 "QueryCapability")) {
4030 return device_query_capability (connection, message);
4031 } else if (dbus_message_is_method_call (message,
4032 "org.freedesktop.Hal.Device",
4033 "Lock")) {
4034 return device_lock (connection, message);
4035 } else if (dbus_message_is_method_call (message,
4036 "org.freedesktop.Hal.Device",
4037 "Unlock")) {
4038 return device_unlock (connection, message);
4039 } else if (dbus_message_is_method_call (message,
4040 "org.freedesktop.Hal.Device",
4041 "StringListAppend")) {
4042 return device_string_list_append_prepend (connection, message, FALSE);
4043 } else if (dbus_message_is_method_call (message,
4044 "org.freedesktop.Hal.Device",
4045 "StringListPrepend")) {
4046 return device_string_list_append_prepend (connection, message, TRUE);
4047 } else if (dbus_message_is_method_call (message,
4048 "org.freedesktop.Hal.Device",
4049 "StringListRemove")) {
4050 return device_string_list_remove (connection, message);
4051 } else if (dbus_message_is_method_call (message,
4052 "org.freedesktop.Hal.Device",
4053 "Rescan")) {
4054 return device_rescan (connection, message, local_interface);
4055 } else if (dbus_message_is_method_call (message,
4056 "org.freedesktop.Hal.Device",
4057 "Reprobe")) {
4058 return device_reprobe (connection, message, local_interface);
4059 } else if (dbus_message_is_method_call (message,
4060 "org.freedesktop.Hal.Device",
4061 "EmitCondition")) {
4062 return device_emit_condition (connection, message, local_interface);
4063 } else if (dbus_message_is_method_call (message,
4064 "org.freedesktop.Hal.Device",
4065 "ClaimInterface")) {
4066 return device_claim_interface (connection, message, local_interface);
4067 #if 0
4068 } else if (dbus_message_is_method_call (message,
4069 "org.freedesktop.Hal.Device",
4070 "ReleaseInterface")) {
4071 return device_release_interface (connection, message, local_interface);
4072 #endif
4073 } else if (dbus_message_is_method_call (message,
4074 "org.freedesktop.Hal.Device",
4075 "AddonIsReady")) {
4076 return addon_is_ready (connection, message, local_interface);
4077 } else if (dbus_message_is_method_call (message,
4078 "org.freedesktop.DBus.Introspectable",
4079 "Introspect")) {
4080 return do_introspect (connection, message, local_interface);
4081 } else {
4082 const char *interface;
4083 const char *udi;
4084 const char *method;
4085 const char *signature;
4086 HalDevice *d;
4088 /* check for device-specific interfaces that individual objects may support */
4090 udi = dbus_message_get_path (message);
4091 interface = dbus_message_get_interface (message);
4092 method = dbus_message_get_member (message);
4093 signature = dbus_message_get_signature (message);
4095 d = NULL;
4097 if (udi != NULL) {
4098 d = hal_device_store_find (hald_get_gdl (), udi);
4099 if (d == NULL)
4100 d = hal_device_store_find (hald_get_tdl (), udi);
4103 if (d != NULL && interface != NULL) {
4104 GSList *i;
4106 for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
4107 HelperInterfaceHandler *hih = i->data;
4108 if (strcmp (hih->udi, udi) == 0 &&
4109 strcmp (hih->interface_name, interface) == 0) {
4110 DBusPendingCall *pending_call;
4111 DBusMessage *copy;
4113 /*HAL_INFO (("forwarding method to connection 0x%x", hih->connection));*/
4115 dbus_message_ref (message);
4117 /* send a copy of the message */
4118 copy = dbus_message_copy (message);
4119 if (!dbus_connection_send_with_reply (hih->connection,
4120 copy,
4121 &pending_call,
4122 /*-1*/ 8000)) {
4123 /* TODO: handle error */
4124 } else {
4125 /*HAL_INFO (("connection=%x message=%x", connection, message));*/
4126 dbus_pending_call_set_notify (pending_call,
4127 reply_from_fwd_message,
4128 (void *) message,
4129 NULL);
4132 dbus_message_unref (copy);
4134 return DBUS_HANDLER_RESULT_HANDLED;
4139 if (d != NULL && interface != NULL && method != NULL && signature != NULL) {
4140 GSList *interfaces;
4141 GSList *i;
4143 interfaces = hal_device_property_get_strlist (d, "info.interfaces");
4144 for (i = interfaces; i != NULL; i = g_slist_next (i)) {
4145 const char *ifname = (const char *) i->data;
4147 if (strcmp (ifname, interface) == 0) {
4148 guint num;
4149 GSList *method_names;
4150 char *s;
4152 s = g_strdup_printf ("%s.method_names", interface);
4153 method_names = hal_device_property_get_strlist (d, s);
4154 g_free (s);
4155 for (i = method_names, num = 0; i != NULL; i = g_slist_next (i), num++) {
4156 const char *methodname = (const char *) i->data;
4157 if (strcmp (methodname, method) == 0) {
4158 const char *execpath;
4159 const char *sig;
4161 s = g_strdup_printf ("%s.method_execpaths", interface);
4162 execpath = hal_device_property_get_strlist_elem (d, s, num);
4163 g_free (s);
4164 s = g_strdup_printf ("%s.method_signatures", interface);
4165 sig = hal_device_property_get_strlist_elem (d, s, num);
4166 g_free (s);
4168 if (execpath != NULL && sig != NULL &&
4169 strcmp (sig, signature) == 0) {
4171 HAL_INFO (("OK for method '%s' with signature '%s' on interface '%s' for UDI '%s' and execpath '%s'", method, signature, interface, udi, execpath));
4173 return hald_exec_method (d, connection, local_interface,
4174 message, execpath);
4185 return osspec_filter_function (connection, message, user_data);
4189 /** Message handler for method invocations. All invocations on any object
4190 * or interface is routed through this function.
4192 * @param connection D-BUS connection
4193 * @param message Message
4194 * @param user_data User data
4195 * @return What to do with the message
4197 DBusHandlerResult
4198 hald_dbus_filter_function (DBusConnection * connection,
4199 DBusMessage * message, void *user_data)
4201 if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
4202 strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
4204 /* this is a local message; e.g. from libdbus in this process */
4206 HAL_INFO (("Got disconnected from the system message bus; "
4207 "retrying to reconnect every 3000 ms"));
4208 dbus_connection_unref (dbus_connection);
4209 dbus_connection = NULL;
4211 g_timeout_add (3000, reinit_dbus, NULL);
4213 } else if (dbus_message_is_signal (message,
4214 DBUS_INTERFACE_DBUS,
4215 "NameOwnerChanged")) {
4217 if (services_with_locks != NULL || services_with_claims != NULL)
4218 service_deleted (message);
4219 } else
4220 return hald_dbus_filter_handle_methods (connection, message, user_data, FALSE);
4222 return DBUS_HANDLER_RESULT_HANDLED;
4227 static DBusHandlerResult
4228 local_server_message_handler (DBusConnection *connection,
4229 DBusMessage *message,
4230 void *user_data)
4232 /*HAL_INFO (("local_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
4233 dbus_message_get_destination (message),
4234 dbus_message_get_path (message),
4235 dbus_message_get_interface (message),
4236 dbus_message_get_member (message)));*/
4238 if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
4239 DBusMessage *reply;
4241 /* cheat, and handle AddMatch since libhal will try to invoke this method */
4242 reply = dbus_message_new_method_return (message);
4243 if (reply == NULL)
4244 DIE (("No memory"));
4245 if (!dbus_connection_send (connection, reply, NULL))
4246 DIE (("No memory"));
4247 dbus_message_unref (reply);
4248 return DBUS_HANDLER_RESULT_HANDLED;
4249 } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
4250 strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
4251 GSList *i;
4252 GSList *j;
4254 HAL_INFO (("Client to local_server was disconnected"));
4256 for (i = helper_interface_handlers; i != NULL; i = j) {
4257 HelperInterfaceHandler *hih = i->data;
4259 j = g_slist_next (i);
4261 if (hih->connection == connection) {
4262 g_free (hih->interface_name);
4263 g_free (hih->introspection_xml);
4264 g_free (hih->udi);
4265 g_free (hih);
4266 helper_interface_handlers = g_slist_remove_link (helper_interface_handlers, i);
4270 dbus_connection_unref (connection);
4271 return DBUS_HANDLER_RESULT_HANDLED;
4272 } else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) {
4273 DBusMessage *copy;
4275 /* it's a signal, just forward it onto the system message bus */
4276 copy = dbus_message_copy (message);
4277 if (dbus_connection != NULL) {
4278 dbus_connection_send (dbus_connection, copy, NULL);
4280 dbus_message_unref (copy);
4281 } else {
4282 return hald_dbus_filter_handle_methods (connection, message, user_data, TRUE);
4285 return DBUS_HANDLER_RESULT_HANDLED;
4288 static void
4289 local_server_unregister_handler (DBusConnection *connection, void *user_data)
4291 HAL_INFO (("unregistered"));
4294 static void
4295 local_server_handle_connection (DBusServer *server,
4296 DBusConnection *new_connection,
4297 void *data)
4299 DBusObjectPathVTable vtable = { &local_server_unregister_handler,
4300 &local_server_message_handler,
4301 NULL, NULL, NULL, NULL};
4303 HAL_INFO (("%d: Got a connection", getpid ()));
4304 HAL_INFO (("dbus_connection_get_is_connected = %d", dbus_connection_get_is_connected (new_connection)));
4306 /*dbus_connection_add_filter (new_connection, server_filter_function, NULL, NULL);*/
4308 dbus_connection_register_fallback (new_connection,
4309 "/org/freedesktop",
4310 &vtable,
4311 NULL);
4312 dbus_connection_ref (new_connection);
4313 dbus_connection_setup_with_g_main (new_connection, NULL);
4317 static DBusServer *local_server = NULL;
4319 char *
4320 hald_dbus_local_server_addr (void)
4322 if (local_server == NULL)
4323 return NULL;
4325 return dbus_server_get_address (local_server);
4328 gboolean
4329 hald_dbus_local_server_init (void)
4331 gboolean ret;
4332 DBusError error;
4333 char *server_addr;
4335 ret = FALSE;
4337 /* setup a server listening on a socket so we can do point to point
4338 * connections for programs spawned by hald
4340 dbus_error_init (&error);
4341 if ((local_server = dbus_server_listen (HALD_DBUS_ADDRESS, &error)) == NULL) {
4342 HAL_ERROR (("Cannot create D-BUS server"));
4343 goto out;
4345 server_addr = dbus_server_get_address (local_server);
4346 HAL_INFO (("local server is listening at %s", server_addr));
4347 dbus_free (server_addr);
4348 dbus_server_setup_with_g_main (local_server, NULL);
4349 dbus_server_set_new_connection_function (local_server, local_server_handle_connection, NULL, NULL);
4351 ret = TRUE;
4353 out:
4354 return ret;
4357 gboolean
4358 hald_dbus_init (void)
4360 DBusError dbus_error;
4362 HAL_INFO (("entering"));
4364 dbus_connection_set_change_sigpipe (TRUE);
4366 dbus_error_init (&dbus_error);
4367 dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
4368 if (dbus_connection == NULL) {
4369 HAL_ERROR (("dbus_bus_get(): %s", dbus_error.message));
4370 return FALSE;
4373 dbus_connection_setup_with_g_main (dbus_connection, NULL);
4374 dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
4376 dbus_bus_request_name (dbus_connection, "org.freedesktop.Hal",
4377 0, &dbus_error);
4378 if (dbus_error_is_set (&dbus_error)) {
4379 HAL_ERROR (("dbus_bus_request_name(): %s",
4380 dbus_error.message));
4381 return FALSE;
4384 dbus_connection_add_filter (dbus_connection, hald_dbus_filter_function, NULL, NULL);
4386 dbus_bus_add_match (dbus_connection,
4387 "type='signal'"
4388 ",interface='"DBUS_INTERFACE_DBUS"'"
4389 ",sender='"DBUS_SERVICE_DBUS"'"
4390 ",member='NameOwnerChanged'",
4391 NULL);
4393 return TRUE;
4396 /** @} */