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