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