1 /*************************************************************************** 2 * CVSID: $Id$ 3 * 4 * libhal.c : HAL daemon C convenience library 5 * 6 * Copyright (C) 2003 David Zeuthen, <david@fubar.dk> 7 * Copyright (C) 2006 Sjoerd Simons, <sjoerd@luon.net> 8 * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk> 9 * 10 * Licensed under the Academic Free License version 2.1 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 * 26 **************************************************************************/ 27 28 #ifdef HAVE_CONFIG_H 29 # include <config.h> 30 #endif 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <dbus/dbus.h> 36 37 #include "libhal.h" 38 39 #ifdef ENABLE_NLS 40 # include <libintl.h> 41 # define _(String) dgettext (GETTEXT_PACKAGE, String) 42 # ifdef gettext_noop 43 # define N_(String) gettext_noop (String) 44 # else 45 # define N_(String) (String) 46 # endif 47 #else 48 /* Stubs that do something close enough. */ 49 # define textdomain(String) (String) 50 # define gettext(String) (String) 51 # define dgettext(Domain,Message) (Message) 52 # define dcgettext(Domain,Message,Type) (Message) 53 # define bindtextdomain(Domain,Directory) (Domain) 54 # define _(String) 55 # define N_(String) (String) 56 #endif 57 58 /** 59 * LIBHAL_CHECK_PARAM_VALID: 60 * @_param_: the prameter to check for 61 * @_name_: the name of the prameter (for debug output) 62 * @_ret_: what to use for return value if the prameter is NULL 63 * 64 * Handy macro for checking whether a parameter is valid and not NULL. 65 */ 66 #define LIBHAL_CHECK_PARAM_VALID(_param_,_name_,_ret_) \ 67 do { \ 68 if (_param_ == NULL) { \ 69 fprintf (stderr, \ 70 "%s %d : invalid paramater. %s is NULL.\n", \ 71 __FILE__, __LINE__, _name_); \ 72 return _ret_; \ 73 } \ 74 } while(0) 75 76 77 static char **libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements); 78 79 static dbus_bool_t libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter); 80 81 82 /** 83 * libhal_free_string_array: 84 * @str_array: the array to be freed 85 * 86 * Frees a NULL-terminated array of strings. If passed NULL, does nothing. 87 */ 88 void 89 libhal_free_string_array (char **str_array) 90 { 91 if (str_array != NULL) { 92 int i; 93 94 for (i = 0; str_array[i] != NULL; i++) { 95 free (str_array[i]); 96 str_array[i] = NULL; 97 } 98 free (str_array); 99 str_array = NULL; 100 } 101 } 102 103 104 /** 105 * libhal_get_string_array_from_iter: 106 * @iter: the message iterator to extract the strings from 107 * @num_elements: pointer to an integer where to store number of elements (can be NULL) 108 * 109 * Creates a NULL terminated array of strings from a dbus message iterator. 110 * 111 * Returns: pointer to the string array 112 */ 113 static char ** 114 libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements) 115 { 116 int count; 117 char **buffer; 118 119 count = 0; 120 buffer = (char **)malloc (sizeof (char *) * 8); 121 122 if (buffer == NULL) 123 goto oom; 124 125 buffer[0] = NULL; 126 while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING) { 127 const char *value; 128 char *str; 129 130 if ((count % 8) == 0 && count != 0) { 131 buffer = realloc (buffer, sizeof (char *) * (count + 8)); 132 if (buffer == NULL) 133 goto oom; 134 } 135 136 dbus_message_iter_get_basic (iter, &value); 137 str = strdup (value); 138 if (str == NULL) 139 goto oom; 140 141 buffer[count] = str; 142 143 dbus_message_iter_next(iter); 144 count++; 145 } 146 147 if ((count % 8) == 0) { 148 buffer = realloc (buffer, sizeof (char *) * (count + 1)); 149 if (buffer == NULL) 150 goto oom; 151 } 152 153 buffer[count] = NULL; 154 if (num_elements != NULL) 155 *num_elements = count; 156 return buffer; 157 158 oom: 159 fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__); 160 return NULL; 161 162 } 163 164 /** 165 * libhal_free_string: 166 * @str: the nul-terminated sting to free 167 * 168 * Used to free strings returned by libhal. 169 */ 170 void 171 libhal_free_string (char *str) 172 { 173 if (str != NULL) { 174 free (str); 175 str = NULL; 176 } 177 } 178 179 180 /** 181 * LibHalPropertySet: 182 * 183 * Represents a set of properties. Opaque; use the 184 * libhal_property_set_*() family of functions to access it. 185 */ 186 struct LibHalPropertySet_s { 187 unsigned int num_properties; /**< Number of properties in set */ 188 LibHalProperty *properties_head; 189 /**< Pointer to first property or NULL 190 * if there are no properties */ 191 }; 192 193 /** 194 * LibHalProperty: 195 * 196 * Represents a property. Opaque. 197 */ 198 struct LibHalProperty_s { 199 int type; /**< Type of property */ 200 char *key; /**< ASCII string */ 201 202 /** Possible values of the property */ 203 union { 204 char *str_value; /**< UTF-8 zero-terminated string */ 205 dbus_int32_t int_value; 206 /**< 32-bit signed integer */ 207 dbus_uint64_t uint64_value; 208 /**< 64-bit unsigned integer */ 209 double double_value; /**< IEEE754 double precision float */ 210 dbus_bool_t bool_value; 211 /**< Truth value */ 212 213 char **strlist_value; /**< List of UTF-8 zero-terminated strings */ 214 } v; 215 216 LibHalProperty *next; /**< Next property or NULL if this is 217 * the last */ 218 }; 219 220 /** 221 * LibHalContext: 222 * 223 * Context for connection to the HAL daemon. Opaque, use the 224 * libhal_ctx_*() family of functions to access it. 225 */ 226 struct LibHalContext_s { 227 DBusConnection *connection; /**< D-BUS connection */ 228 dbus_bool_t is_initialized; /**< Are we initialised */ 229 dbus_bool_t is_shutdown; /**< Have we been shutdown */ 230 dbus_bool_t cache_enabled; /**< Is the cache enabled */ 231 dbus_bool_t is_direct; /**< Whether the connection to hald is direct */ 232 233 /** Device added */ 234 LibHalDeviceAdded device_added; 235 236 /** Device removed */ 237 LibHalDeviceRemoved device_removed; 238 239 /** Device got a new capability */ 240 LibHalDeviceNewCapability device_new_capability; 241 242 /** Device got a new capability */ 243 LibHalDeviceLostCapability device_lost_capability; 244 245 /** A property of a device changed */ 246 LibHalDevicePropertyModified device_property_modified; 247 248 /** A non-continous event on the device occured */ 249 LibHalDeviceCondition device_condition; 250 251 void *user_data; /**< User data */ 252 }; 253 254 /** 255 * libhal_ctx_set_user_data: 256 * @ctx: the context for the connection to hald 257 * @user_data: user data 258 * 259 * Set user data for the context. 260 * 261 * Returns: TRUE if user data was successfully set, FALSE if otherwise 262 */ 263 dbus_bool_t 264 libhal_ctx_set_user_data(LibHalContext *ctx, void *user_data) 265 { 266 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 267 ctx->user_data = user_data; 268 return TRUE; 269 } 270 271 /** 272 * libhal_ctx_get_user_data: 273 * @ctx: the context for the connection to hald 274 * 275 * Get user data for the context. 276 * 277 * Returns: opaque pointer stored through libhal_ctx_set_user_data() or NULL if not set. 278 */ 279 void* 280 libhal_ctx_get_user_data(LibHalContext *ctx) 281 { 282 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 283 return ctx->user_data; 284 } 285 286 287 /** 288 * libhal_property_fill_value_from_variant: 289 * @p: the property to fill in 290 * @var_iter: variant iterator to extract the value from 291 * 292 * Fills in the value for the LibHalProperty given a variant iterator. 293 * 294 * Returns: Whether the value was put in. 295 */ 296 static dbus_bool_t 297 libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter) 298 { 299 DBusMessageIter iter_array; 300 switch (p->type) { 301 case DBUS_TYPE_ARRAY: 302 if (dbus_message_iter_get_element_type (var_iter) != DBUS_TYPE_STRING) 303 return FALSE; 304 305 dbus_message_iter_recurse (var_iter, &iter_array); 306 p->v.strlist_value = libhal_get_string_array_from_iter (&iter_array, NULL); 307 308 p->type = LIBHAL_PROPERTY_TYPE_STRLIST; 309 310 break; 311 case DBUS_TYPE_STRING: 312 { 313 const char *v; 314 315 dbus_message_iter_get_basic (var_iter, &v); 316 317 p->v.str_value = strdup (v); 318 if (p->v.str_value == NULL) 319 return FALSE; 320 p->type = LIBHAL_PROPERTY_TYPE_STRING; 321 322 break; 323 } 324 case DBUS_TYPE_INT32: 325 { 326 dbus_int32_t v; 327 328 dbus_message_iter_get_basic (var_iter, &v); 329 330 p->v.int_value = v; 331 p->type = LIBHAL_PROPERTY_TYPE_INT32; 332 333 break; 334 } 335 case DBUS_TYPE_UINT64: 336 { 337 dbus_uint64_t v; 338 339 dbus_message_iter_get_basic (var_iter, &v); 340 341 p->v.uint64_value = v; 342 p->type = LIBHAL_PROPERTY_TYPE_UINT64; 343 344 break; 345 } 346 case DBUS_TYPE_DOUBLE: 347 { 348 double v; 349 350 dbus_message_iter_get_basic (var_iter, &v); 351 352 p->v.double_value = v; 353 p->type = LIBHAL_PROPERTY_TYPE_DOUBLE; 354 355 break; 356 } 357 case DBUS_TYPE_BOOLEAN: 358 { 359 double v; 360 361 dbus_message_iter_get_basic (var_iter, &v); 362 363 p->v.double_value = v; 364 p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN; 365 366 break; 367 } 368 default: 369 /** @todo report error */ 370 break; 371 } 372 373 return TRUE; 374 } 375 376 /** 377 * libhal_device_get_all_properties: 378 * @ctx: the context for the connection to hald 379 * @udi: the Unique id of device 380 * @error: pointer to an initialized dbus error object for returning errors or NULL 381 * 382 * Retrieve all the properties on a device. 383 * 384 * Returns: An object represent all properties. Must be freed with libhal_free_property_set(). 385 */ 386 LibHalPropertySet * 387 libhal_device_get_all_properties (LibHalContext *ctx, const char *udi, DBusError *error) 388 { 389 DBusMessage *message; 390 DBusMessage *reply; 391 DBusMessageIter reply_iter; 392 DBusMessageIter dict_iter; 393 LibHalPropertySet *result; 394 LibHalProperty *p_last; 395 DBusError _error; 396 397 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 398 399 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 400 "org.freedesktop.Hal.Device", 401 "GetAllProperties"); 402 403 if (message == NULL) { 404 fprintf (stderr, 405 "%s %d : Couldn't allocate D-BUS message\n", 406 __FILE__, __LINE__); 407 return NULL; 408 } 409 410 dbus_error_init (&_error); 411 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 412 message, -1, 413 &_error); 414 415 dbus_move_error (&_error, error); 416 if (error != NULL && dbus_error_is_set (error)) { 417 fprintf (stderr, 418 "%s %d : %s\n", 419 __FILE__, __LINE__, error->message); 420 421 dbus_message_unref (message); 422 return NULL; 423 } 424 425 if (reply == NULL) { 426 dbus_message_unref (message); 427 return NULL; 428 } 429 430 dbus_message_iter_init (reply, &reply_iter); 431 432 result = malloc (sizeof (LibHalPropertySet)); 433 if (result == NULL) 434 goto oom; 435 436 /* 437 result->properties = malloc(sizeof(LibHalProperty)*result->num_properties); 438 if( result->properties==NULL ) 439 { 440 /// @todo cleanup 441 return NULL; 442 } 443 */ 444 445 result->properties_head = NULL; 446 result->num_properties = 0; 447 448 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY && 449 dbus_message_iter_get_element_type (&reply_iter) != DBUS_TYPE_DICT_ENTRY) { 450 fprintf (stderr, "%s %d : error, expecting an array of dict entries\n", 451 __FILE__, __LINE__); 452 dbus_message_unref (message); 453 dbus_message_unref (reply); 454 return NULL; 455 } 456 457 dbus_message_iter_recurse (&reply_iter, &dict_iter); 458 459 p_last = NULL; 460 461 while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY) 462 { 463 DBusMessageIter dict_entry_iter, var_iter; 464 const char *key; 465 LibHalProperty *p; 466 467 dbus_message_iter_recurse (&dict_iter, &dict_entry_iter); 468 469 dbus_message_iter_get_basic (&dict_entry_iter, &key); 470 471 p = malloc (sizeof (LibHalProperty)); 472 if (p == NULL) 473 goto oom; 474 475 p->next = NULL; 476 477 if (result->num_properties == 0) 478 result->properties_head = p; 479 480 if (p_last != NULL) 481 p_last->next = p; 482 483 p_last = p; 484 485 p->key = strdup (key); 486 if (p->key == NULL) 487 goto oom; 488 489 dbus_message_iter_next (&dict_entry_iter); 490 491 dbus_message_iter_recurse (&dict_entry_iter, &var_iter); 492 493 494 p->type = dbus_message_iter_get_arg_type (&var_iter); 495 496 result->num_properties++; 497 498 if(!libhal_property_fill_value_from_variant (p, &var_iter)) 499 goto oom; 500 501 dbus_message_iter_next (&dict_iter); 502 } 503 504 dbus_message_unref (message); 505 dbus_message_unref (reply); 506 507 return result; 508 509 oom: 510 fprintf (stderr, 511 "%s %d : error allocating memory\n", 512 __FILE__, __LINE__); 513 /** @todo FIXME cleanup */ 514 return NULL; 515 } 516 517 /** 518 * libhal_free_property_set: 519 * @set: property-set to free 520 * 521 * Free a property set earlier obtained with libhal_device_get_all_properties(). 522 */ 523 void 524 libhal_free_property_set (LibHalPropertySet * set) 525 { 526 LibHalProperty *p; 527 LibHalProperty *q; 528 529 if (set == NULL) 530 return; 531 532 for (p = set->properties_head; p != NULL; p = q) { 533 free (p->key); 534 if (p->type == DBUS_TYPE_STRING) 535 free (p->v.str_value); 536 if (p->type == LIBHAL_PROPERTY_TYPE_STRLIST) 537 libhal_free_string_array (p->v.strlist_value); 538 q = p->next; 539 free (p); 540 } 541 free (set); 542 } 543 544 /** 545 * libhal_property_set_get_num_elems: 546 * @set: property set to consider 547 * 548 * Get the number of properties in a property set. 549 * 550 * Returns: number of properties in given property set 551 */ 552 unsigned int 553 libhal_property_set_get_num_elems (LibHalPropertySet *set) 554 { 555 unsigned int num_elems; 556 LibHalProperty *p; 557 558 if (set == NULL) 559 return 0; 560 561 num_elems = 0; 562 for (p = set->properties_head; p != NULL; p = p->next) 563 num_elems++; 564 565 return num_elems; 566 } 567 568 static LibHalProperty * 569 property_set_lookup (const LibHalPropertySet *set, const char *key) 570 { 571 LibHalProperty *p; 572 573 LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); 574 LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); 575 576 for (p = set->properties_head; p != NULL; p = p->next) 577 if (strcmp (key, p->key) == 0) 578 return p; 579 580 return NULL; 581 } 582 583 /** 584 * libhal_ps_get_type: 585 * @set: property set 586 * @key: name of property to inspect 587 * 588 * Get the type of a given property. 589 * 590 * Returns: the #LibHalPropertyType of the given property, 591 * LIBHAL_PROPERTY_TYPE_INVALID if property is not in the set 592 */ 593 LibHalPropertyType 594 libhal_ps_get_type (const LibHalPropertySet *set, const char *key) 595 { 596 LibHalProperty *p; 597 598 LIBHAL_CHECK_PARAM_VALID(set, "*set", LIBHAL_PROPERTY_TYPE_INVALID); 599 LIBHAL_CHECK_PARAM_VALID(key, "*key", LIBHAL_PROPERTY_TYPE_INVALID); 600 601 p = property_set_lookup (set, key); 602 if (p) return p->type; 603 else return LIBHAL_PROPERTY_TYPE_INVALID; 604 } 605 606 /** 607 * libhal_ps_get_string: 608 * @set: property set 609 * @key: name of property to inspect 610 * 611 * Get the value of a property of type string. 612 * 613 * Returns: UTF8 nul-terminated string. This pointer is only valid 614 * until libhal_free_property_set() is invoked on the property set 615 * this property belongs to. NULL if property is not in the set or not a string 616 */ 617 const char * 618 libhal_ps_get_string (const LibHalPropertySet *set, const char *key) 619 { 620 LibHalProperty *p; 621 622 LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); 623 LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); 624 625 p = property_set_lookup (set, key); 626 if (p && p->type == LIBHAL_PROPERTY_TYPE_STRING) 627 return p->v.str_value; 628 else return NULL; 629 } 630 631 /** 632 * libhal_ps_get_int: 633 * @set: property set 634 * @key: name of property to inspect 635 * 636 * Get the value of a property of type signed integer. 637 * 638 * Returns: property value (32-bit signed integer) 639 */ 640 dbus_int32_t 641 libhal_ps_get_int32 (const LibHalPropertySet *set, const char *key) 642 { 643 LibHalProperty *p; 644 645 LIBHAL_CHECK_PARAM_VALID(set, "*set", 0); 646 LIBHAL_CHECK_PARAM_VALID(key, "*key", 0); 647 648 p = property_set_lookup (set, key); 649 if (p && p->type == LIBHAL_PROPERTY_TYPE_INT32) 650 return p->v.int_value; 651 else return 0; 652 } 653 654 /** 655 * libhal_ps_get_uint64: 656 * @set: property set 657 * @key: name of property to inspect 658 * 659 * Get the value of a property of type unsigned integer. 660 * 661 * Returns: property value (64-bit unsigned integer) 662 */ 663 dbus_uint64_t 664 libhal_ps_get_uint64 (const LibHalPropertySet *set, const char *key) 665 { 666 LibHalProperty *p; 667 668 LIBHAL_CHECK_PARAM_VALID(set, "*set", 0); 669 LIBHAL_CHECK_PARAM_VALID(key, "*key", 0); 670 671 p = property_set_lookup (set, key); 672 if (p && p->type == LIBHAL_PROPERTY_TYPE_UINT64) 673 return p->v.uint64_value; 674 else return 0; 675 } 676 677 /** 678 * libhal_ps_get_double: 679 * @set: property set 680 * @key: name of property to inspect 681 * 682 * Get the value of a property of type double. 683 * 684 * Returns: property value (IEEE754 double precision float) 685 */ 686 double 687 libhal_ps_get_double (const LibHalPropertySet *set, const char *key) 688 { 689 LibHalProperty *p; 690 691 LIBHAL_CHECK_PARAM_VALID(set, "*set", 0.0); 692 LIBHAL_CHECK_PARAM_VALID(key, "*key", 0.0); 693 694 p = property_set_lookup (set, key); 695 if (p && p->type == LIBHAL_PROPERTY_TYPE_DOUBLE) 696 return p->v.double_value; 697 else return 0.0; 698 } 699 700 /** 701 * libhal_ps_get_bool: 702 * @set: property set 703 * @key: name of property to inspect 704 * 705 * Get the value of a property of type bool. 706 * 707 * Returns: property value (bool) 708 */ 709 dbus_bool_t 710 libhal_ps_get_bool (const LibHalPropertySet *set, const char *key) 711 { 712 LibHalProperty *p; 713 714 LIBHAL_CHECK_PARAM_VALID(set, "*set", FALSE); 715 LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); 716 717 p = property_set_lookup (set, key); 718 if (p && p->type == LIBHAL_PROPERTY_TYPE_BOOLEAN) 719 return p->v.bool_value; 720 else return FALSE; 721 } 722 723 /** 724 * libhal_ps_get_strlist: 725 * @set: property set 726 * @key: name of property to inspect 727 * 728 * Get the value of a property of type string list. 729 * 730 * Returns: pointer to array of strings, this is owned by the property set 731 */ 732 const char *const * 733 libhal_ps_get_strlist (const LibHalPropertySet *set, const char *key) 734 { 735 LibHalProperty *p; 736 737 LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); 738 LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); 739 740 p = property_set_lookup (set, key); 741 if (p && p->type == LIBHAL_PROPERTY_TYPE_STRLIST) 742 return (const char *const *) p->v.strlist_value; 743 else return NULL; 744 } 745 746 747 /** 748 * libhal_psi_init: 749 * @iter: iterator object 750 * @set: property set to iterate over 751 * 752 * Initialize a property set iterator. 753 * 754 */ 755 void 756 libhal_psi_init (LibHalPropertySetIterator * iter, LibHalPropertySet * set) 757 { 758 if (set == NULL) 759 return; 760 761 iter->set = set; 762 iter->idx = 0; 763 iter->cur_prop = set->properties_head; 764 } 765 766 767 /** 768 * libhal_psi_has_more: 769 * @iter: iterator object 770 * 771 * Determine whether there are more properties to iterate over. 772 * 773 * Returns: TRUE if there are more properties, FALSE otherwise. 774 */ 775 dbus_bool_t 776 libhal_psi_has_more (LibHalPropertySetIterator * iter) 777 { 778 return iter->idx < iter->set->num_properties; 779 } 780 781 /** 782 * libhal_psi_next: 783 * @iter: iterator object 784 * 785 * Advance iterator to next property. 786 */ 787 void 788 libhal_psi_next (LibHalPropertySetIterator * iter) 789 { 790 iter->idx++; 791 iter->cur_prop = iter->cur_prop->next; 792 } 793 794 /** 795 * libhal_psi_get_type: 796 * @iter: iterator object 797 * 798 * Get type of property. 799 * 800 * Returns: the property type at the iterator's position 801 */ 802 LibHalPropertyType 803 libhal_psi_get_type (LibHalPropertySetIterator * iter) 804 { 805 return iter->cur_prop->type; 806 } 807 808 /** 809 * libhal_psi_get_key: 810 * @iter: iterator object 811 * 812 * Get the key of a property. 813 * 814 * Returns: ASCII nul-terminated string. This pointer is only valid 815 * until libhal_free_property_set() is invoked on the property set 816 * this property belongs to. 817 */ 818 char * 819 libhal_psi_get_key (LibHalPropertySetIterator * iter) 820 { 821 return iter->cur_prop->key; 822 } 823 824 /** 825 * libhal_psi_get_string: 826 * @iter: iterator object 827 * 828 * Get the value of a property of type string. 829 * 830 * Returns: UTF8 nul-terminated string. This pointer is only valid 831 * until libhal_free_property_set() is invoked on the property set 832 * this property belongs to. 833 */ 834 char * 835 libhal_psi_get_string (LibHalPropertySetIterator * iter) 836 { 837 return iter->cur_prop->v.str_value; 838 } 839 840 /** 841 * libhal_psi_get_int: 842 * @iter: iterator object 843 * 844 * Get the value of a property of type signed integer. 845 * 846 * Returns: property value (32-bit signed integer) 847 */ 848 dbus_int32_t 849 libhal_psi_get_int (LibHalPropertySetIterator * iter) 850 { 851 return iter->cur_prop->v.int_value; 852 } 853 854 /** 855 * libhal_psi_get_uint64: 856 * @iter: iterator object 857 * 858 * Get the value of a property of type unsigned integer. 859 * 860 * Returns: property value (64-bit unsigned integer) 861 */ 862 dbus_uint64_t 863 libhal_psi_get_uint64 (LibHalPropertySetIterator * iter) 864 { 865 return iter->cur_prop->v.uint64_value; 866 } 867 868 /** 869 * libhal_psi_get_double: 870 * @iter: iterator object 871 * 872 * Get the value of a property of type double. 873 * 874 * Returns: property value (IEEE754 double precision float) 875 */ 876 double 877 libhal_psi_get_double (LibHalPropertySetIterator * iter) 878 { 879 return iter->cur_prop->v.double_value; 880 } 881 882 /** 883 * libhal_psi_get_bool: 884 * @iter: iterator object 885 * 886 * Get the value of a property of type bool. 887 * 888 * Returns: property value (bool) 889 */ 890 dbus_bool_t 891 libhal_psi_get_bool (LibHalPropertySetIterator * iter) 892 { 893 return iter->cur_prop->v.bool_value; 894 } 895 896 /** 897 * libhal_psi_get_strlist: 898 * @iter: iterator object 899 * 900 * Get the value of a property of type string list. 901 * 902 * Returns: pointer to array of strings 903 */ 904 char ** 905 libhal_psi_get_strlist (LibHalPropertySetIterator * iter) 906 { 907 return iter->cur_prop->v.strlist_value; 908 } 909 910 911 static DBusHandlerResult 912 filter_func (DBusConnection * connection, 913 DBusMessage * message, void *user_data) 914 { 915 const char *object_path; 916 DBusError error; 917 LibHalContext *ctx = (LibHalContext *) user_data; 918 919 if (ctx->is_shutdown) 920 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 921 922 dbus_error_init (&error); 923 924 object_path = dbus_message_get_path (message); 925 926 /*printf("*** in filter_func, object_path=%s\n", object_path);*/ 927 928 if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", 929 "DeviceAdded")) { 930 char *udi; 931 if (dbus_message_get_args (message, &error, 932 DBUS_TYPE_STRING, &udi, 933 DBUS_TYPE_INVALID)) { 934 if (ctx->device_added != NULL) { 935 ctx->device_added (ctx, udi); 936 } 937 } else { 938 LIBHAL_FREE_DBUS_ERROR(&error); 939 } 940 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 941 } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", "DeviceRemoved")) { 942 char *udi; 943 if (dbus_message_get_args (message, &error, 944 DBUS_TYPE_STRING, &udi, 945 DBUS_TYPE_INVALID)) { 946 if (ctx->device_removed != NULL) { 947 ctx->device_removed (ctx, udi); 948 } 949 } else { 950 LIBHAL_FREE_DBUS_ERROR(&error); 951 } 952 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 953 } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","NewCapability")) { 954 char *udi; 955 char *capability; 956 if (dbus_message_get_args (message, &error, 957 DBUS_TYPE_STRING, &udi, 958 DBUS_TYPE_STRING, &capability, 959 DBUS_TYPE_INVALID)) { 960 if (ctx->device_new_capability != NULL) { 961 ctx->device_new_capability (ctx, udi, capability); 962 } 963 } else { 964 LIBHAL_FREE_DBUS_ERROR(&error); 965 } 966 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 967 } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "Condition")) { 968 char *condition_name; 969 char *condition_detail; 970 if (dbus_message_get_args (message, &error, 971 DBUS_TYPE_STRING, &condition_name, 972 DBUS_TYPE_STRING, &condition_detail, 973 DBUS_TYPE_INVALID)) { 974 if (ctx->device_condition != NULL) { 975 ctx->device_condition (ctx, object_path, condition_name, condition_detail); 976 } 977 } else { 978 LIBHAL_FREE_DBUS_ERROR(&error); 979 } 980 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 981 } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "PropertyModified")) { 982 if (ctx->device_property_modified != NULL) { 983 int i; 984 char *key; 985 dbus_bool_t removed; 986 dbus_bool_t added; 987 int num_modifications; 988 DBusMessageIter iter; 989 DBusMessageIter iter_array; 990 991 dbus_message_iter_init (message, &iter); 992 dbus_message_iter_get_basic (&iter, &num_modifications); 993 dbus_message_iter_next (&iter); 994 995 dbus_message_iter_recurse (&iter, &iter_array); 996 997 for (i = 0; i < num_modifications; i++) { 998 DBusMessageIter iter_struct; 999 1000 dbus_message_iter_recurse (&iter_array, &iter_struct); 1001 1002 dbus_message_iter_get_basic (&iter_struct, &key); 1003 dbus_message_iter_next (&iter_struct); 1004 dbus_message_iter_get_basic (&iter_struct, &removed); 1005 dbus_message_iter_next (&iter_struct); 1006 dbus_message_iter_get_basic (&iter_struct, &added); 1007 1008 ctx->device_property_modified (ctx, 1009 object_path, 1010 key, removed, 1011 added); 1012 1013 dbus_message_iter_next (&iter_array); 1014 } 1015 1016 } 1017 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1018 } 1019 1020 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1021 } 1022 1023 /* for i18n purposes */ 1024 static dbus_bool_t libhal_already_initialized_once = FALSE; 1025 1026 1027 /** 1028 * libhal_get_all_devices: 1029 * @ctx: the context for the connection to hald 1030 * @num_devices: the number of devices will be stored here 1031 * @error: pointer to an initialized dbus error object for returning errors or NULL 1032 * 1033 * Get all devices in the Global Device List (GDL). 1034 * 1035 * Returns: An array of device identifiers terminated with NULL. It is 1036 * the responsibility of the caller to free with 1037 * libhal_free_string_array(). If an error occurs NULL is returned. 1038 */ 1039 char ** 1040 libhal_get_all_devices (LibHalContext *ctx, int *num_devices, DBusError *error) 1041 { 1042 DBusMessage *message; 1043 DBusMessage *reply; 1044 DBusMessageIter iter_array, reply_iter; 1045 char **hal_device_names; 1046 DBusError _error; 1047 1048 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 1049 1050 *num_devices = 0; 1051 1052 message = dbus_message_new_method_call ("org.freedesktop.Hal", 1053 "/org/freedesktop/Hal/Manager", 1054 "org.freedesktop.Hal.Manager", 1055 "GetAllDevices"); 1056 if (message == NULL) { 1057 fprintf (stderr, "%s %d : Could not allocate D-BUS message\n", __FILE__, __LINE__); 1058 return NULL; 1059 } 1060 1061 dbus_error_init (&_error); 1062 reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &_error); 1063 1064 dbus_message_unref (message); 1065 1066 dbus_move_error (&_error, error); 1067 if (error != NULL && dbus_error_is_set (error)) { 1068 return NULL; 1069 } 1070 if (reply == NULL) { 1071 return NULL; 1072 } 1073 1074 /* now analyze reply */ 1075 dbus_message_iter_init (reply, &reply_iter); 1076 1077 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { 1078 fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); 1079 dbus_message_unref (reply); 1080 return NULL; 1081 } 1082 1083 dbus_message_iter_recurse (&reply_iter, &iter_array); 1084 1085 hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); 1086 1087 dbus_message_unref (reply); 1088 return hal_device_names; 1089 } 1090 1091 /** 1092 * libhal_device_get_property_type: 1093 * @ctx: the context for the connection to hald 1094 * @udi: the Unique Device Id 1095 * @key: name of the property 1096 * @error: pointer to an initialized dbus error object for returning errors or NULL 1097 * 1098 * Query a property type of a device. 1099 * 1100 * Returns: A LibHalPropertyType. LIBHAL_PROPERTY_TYPE_INVALID is 1101 * return if the property doesn't exist. 1102 */ 1103 LibHalPropertyType 1104 libhal_device_get_property_type (LibHalContext *ctx, const char *udi, const char *key, DBusError *error) 1105 { 1106 DBusMessage *message; 1107 DBusMessage *reply; 1108 DBusMessageIter iter, reply_iter; 1109 int type; 1110 DBusError _error; 1111 1112 LIBHAL_CHECK_LIBHALCONTEXT(ctx, LIBHAL_PROPERTY_TYPE_INVALID); /* or return NULL? */ 1113 1114 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1115 "org.freedesktop.Hal.Device", 1116 "GetPropertyType"); 1117 if (message == NULL) { 1118 fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__); 1119 return LIBHAL_PROPERTY_TYPE_INVALID; 1120 } 1121 1122 dbus_message_iter_init_append (message, &iter); 1123 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1124 1125 dbus_error_init (&_error); 1126 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1127 message, -1, 1128 &_error); 1129 1130 dbus_message_unref (message); 1131 1132 dbus_move_error (&_error, error); 1133 if (error != NULL && dbus_error_is_set (error)) { 1134 return LIBHAL_PROPERTY_TYPE_INVALID; 1135 } 1136 if (reply == NULL) { 1137 return LIBHAL_PROPERTY_TYPE_INVALID; 1138 } 1139 1140 dbus_message_iter_init (reply, &reply_iter); 1141 dbus_message_iter_get_basic (&reply_iter, &type); 1142 1143 dbus_message_unref (reply); 1144 return type; 1145 } 1146 1147 /** 1148 * libhal_device_get_property_strlist: 1149 * @ctx: the context for the connection to hald 1150 * @udi: unique Device Id 1151 * @key: name of the property 1152 * @error: pointer to an initialized dbus error object for returning errors or NULL 1153 * 1154 * Get the value of a property of type string list. 1155 * 1156 * Returns: Array of pointers to UTF8 nul-terminated strings 1157 * terminated by NULL. The caller is responsible for freeing this 1158 * string array with the function libhal_free_string_array(). Returns 1159 * NULL if the property didn't exist or we are OOM 1160 */ 1161 char ** 1162 libhal_device_get_property_strlist (LibHalContext *ctx, const char *udi, const char *key, DBusError *error) 1163 { 1164 DBusMessage *message; 1165 DBusMessage *reply; 1166 DBusMessageIter iter, iter_array, reply_iter; 1167 char **our_strings; 1168 DBusError _error; 1169 1170 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 1171 1172 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1173 "org.freedesktop.Hal.Device", 1174 "GetPropertyStringList"); 1175 if (message == NULL) { 1176 fprintf (stderr, 1177 "%s %d : Couldn't allocate D-BUS message\n", 1178 __FILE__, __LINE__); 1179 return NULL; 1180 } 1181 1182 dbus_message_iter_init_append (message, &iter); 1183 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1184 1185 dbus_error_init (&_error); 1186 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1187 message, -1, 1188 &_error); 1189 1190 dbus_message_unref (message); 1191 1192 dbus_move_error (&_error, error); 1193 if (error != NULL && dbus_error_is_set (error)) { 1194 return NULL; 1195 } 1196 if (reply == NULL) { 1197 return NULL; 1198 } 1199 /* now analyse reply */ 1200 dbus_message_iter_init (reply, &reply_iter); 1201 1202 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { 1203 fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); 1204 dbus_message_unref (reply); 1205 return NULL; 1206 } 1207 1208 dbus_message_iter_recurse (&reply_iter, &iter_array); 1209 1210 our_strings = libhal_get_string_array_from_iter (&iter_array, NULL); 1211 1212 dbus_message_unref (reply); 1213 return our_strings; 1214 } 1215 1216 /** 1217 * libhal_device_get_property_string: 1218 * @ctx: the context for the connection to hald 1219 * @udi: the Unique Device Id 1220 * @key: the name of the property 1221 * @error: pointer to an initialized dbus error object for returning errors or NULL 1222 * 1223 * Get the value of a property of type string. 1224 * 1225 * Returns: UTF8 nul-terminated string. The caller is responsible for 1226 * freeing this string with the function libhal_free_string(). Returns 1227 * NULL if the property didn't exist or we are OOM. 1228 */ 1229 char * 1230 libhal_device_get_property_string (LibHalContext *ctx, 1231 const char *udi, const char *key, DBusError *error) 1232 { 1233 DBusMessage *message; 1234 DBusMessage *reply; 1235 DBusMessageIter iter, reply_iter; 1236 char *value; 1237 char *dbus_str; 1238 DBusError _error; 1239 1240 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 1241 1242 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1243 "org.freedesktop.Hal.Device", 1244 "GetPropertyString"); 1245 1246 if (message == NULL) { 1247 fprintf (stderr, 1248 "%s %d : Couldn't allocate D-BUS message\n", 1249 __FILE__, __LINE__); 1250 return NULL; 1251 } 1252 1253 dbus_message_iter_init_append (message, &iter); 1254 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1255 1256 dbus_error_init (&_error); 1257 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1258 message, -1, 1259 &_error); 1260 1261 dbus_message_unref (message); 1262 1263 dbus_move_error (&_error, error); 1264 if (error != NULL && dbus_error_is_set (error)) { 1265 return NULL; 1266 } 1267 if (reply == NULL) { 1268 return NULL; 1269 } 1270 1271 dbus_message_iter_init (reply, &reply_iter); 1272 1273 /* now analyze reply */ 1274 if (dbus_message_iter_get_arg_type (&reply_iter) != 1275 DBUS_TYPE_STRING) { 1276 dbus_message_unref (reply); 1277 return NULL; 1278 } 1279 1280 dbus_message_iter_get_basic (&reply_iter, &dbus_str); 1281 value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL); 1282 if (value == NULL) { 1283 fprintf (stderr, "%s %d : error allocating memory\n", 1284 __FILE__, __LINE__); 1285 } 1286 1287 dbus_message_unref (reply); 1288 return value; 1289 } 1290 1291 /** 1292 * libhal_device_get_property_int: 1293 * @ctx: the context for the connection to hald 1294 * @udi: the Unique Device Id 1295 * @key: name of the property 1296 * @error: pointer to an initialized dbus error object for returning errors or NULL 1297 * 1298 * Get the value of a property of type integer. 1299 * 1300 * Returns: Property value (32-bit signed integer) 1301 */ 1302 dbus_int32_t 1303 libhal_device_get_property_int (LibHalContext *ctx, 1304 const char *udi, const char *key, DBusError *error) 1305 { 1306 DBusMessage *message; 1307 DBusMessage *reply; 1308 DBusMessageIter iter, reply_iter; 1309 dbus_int32_t value; 1310 DBusError _error; 1311 1312 LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1); 1313 1314 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1315 "org.freedesktop.Hal.Device", 1316 "GetPropertyInteger"); 1317 if (message == NULL) { 1318 fprintf (stderr, 1319 "%s %d : Couldn't allocate D-BUS message\n", 1320 __FILE__, __LINE__); 1321 return -1; 1322 } 1323 1324 dbus_message_iter_init_append (message, &iter); 1325 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1326 1327 dbus_error_init (&_error); 1328 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1329 message, -1, 1330 &_error); 1331 1332 dbus_message_unref (message); 1333 1334 dbus_move_error (&_error, error); 1335 if (error != NULL && dbus_error_is_set (error)) { 1336 return -1; 1337 } 1338 if (reply == NULL) { 1339 return -1; 1340 } 1341 1342 dbus_message_iter_init (reply, &reply_iter); 1343 1344 /* now analyze reply */ 1345 if (dbus_message_iter_get_arg_type (&reply_iter) != 1346 DBUS_TYPE_INT32) { 1347 fprintf (stderr, 1348 "%s %d : property '%s' for device '%s' is not " 1349 "of type integer\n", __FILE__, __LINE__, key, 1350 udi); 1351 dbus_message_unref (reply); 1352 return -1; 1353 } 1354 dbus_message_iter_get_basic (&reply_iter, &value); 1355 1356 dbus_message_unref (reply); 1357 return value; 1358 } 1359 1360 /** 1361 * libhal_device_get_property_uint64: 1362 * @ctx: the context for the connection to hald 1363 * @udi: the Unique Device Id 1364 * @key: name of the property 1365 * @error: pointer to an initialized dbus error object for returning errors or NULL 1366 * 1367 * Get the value of a property of type signed integer. 1368 * 1369 * Returns: Property value (64-bit unsigned integer) 1370 */ 1371 dbus_uint64_t 1372 libhal_device_get_property_uint64 (LibHalContext *ctx, 1373 const char *udi, const char *key, DBusError *error) 1374 { 1375 DBusMessage *message; 1376 DBusMessage *reply; 1377 DBusMessageIter iter, reply_iter; 1378 dbus_uint64_t value; 1379 DBusError _error; 1380 1381 LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1); 1382 1383 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1384 "org.freedesktop.Hal.Device", 1385 "GetPropertyInteger"); 1386 if (message == NULL) { 1387 fprintf (stderr, 1388 "%s %d : Couldn't allocate D-BUS message\n", 1389 __FILE__, __LINE__); 1390 return -1; 1391 } 1392 1393 dbus_message_iter_init_append (message, &iter); 1394 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1395 1396 dbus_error_init (&_error); 1397 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1398 message, -1, 1399 &_error); 1400 1401 dbus_message_unref (message); 1402 1403 dbus_move_error (&_error, error); 1404 if (error != NULL && dbus_error_is_set (error)) { 1405 return -1; 1406 } 1407 if (reply == NULL) { 1408 return -1; 1409 } 1410 1411 dbus_message_iter_init (reply, &reply_iter); 1412 /* now analyze reply */ 1413 if (dbus_message_iter_get_arg_type (&reply_iter) != 1414 DBUS_TYPE_UINT64) { 1415 fprintf (stderr, 1416 "%s %d : property '%s' for device '%s' is not " 1417 "of type integer\n", __FILE__, __LINE__, key, 1418 udi); 1419 dbus_message_unref (reply); 1420 return -1; 1421 } 1422 dbus_message_iter_get_basic (&reply_iter, &value); 1423 1424 dbus_message_unref (reply); 1425 return value; 1426 } 1427 1428 /** 1429 * libhal_device_get_property_double: 1430 * @ctx: the context for the connection to hald 1431 * @udi: the Unique Device Id 1432 * @key: name of the property 1433 * @error: pointer to an initialized dbus error object for returning errors or NULL 1434 * 1435 * Get the value of a property of type double. 1436 * 1437 * Returns: Property value (IEEE754 double precision float) 1438 */ 1439 double 1440 libhal_device_get_property_double (LibHalContext *ctx, 1441 const char *udi, const char *key, DBusError *error) 1442 { 1443 DBusMessage *message; 1444 DBusMessage *reply; 1445 DBusMessageIter iter, reply_iter; 1446 double value; 1447 DBusError _error; 1448 1449 LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1.0); 1450 1451 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1452 "org.freedesktop.Hal.Device", 1453 "GetPropertyDouble"); 1454 if (message == NULL) { 1455 fprintf (stderr, 1456 "%s %d : Couldn't allocate D-BUS message\n", 1457 __FILE__, __LINE__); 1458 return -1.0f; 1459 } 1460 1461 dbus_message_iter_init_append (message, &iter); 1462 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1463 1464 dbus_error_init (&_error); 1465 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1466 message, -1, 1467 &_error); 1468 1469 dbus_message_unref (message); 1470 1471 dbus_move_error (&_error, error); 1472 if (error != NULL && dbus_error_is_set (error)) { 1473 return -1.0f; 1474 } 1475 if (reply == NULL) { 1476 return -1.0f; 1477 } 1478 1479 dbus_message_iter_init (reply, &reply_iter); 1480 1481 /* now analyze reply */ 1482 if (dbus_message_iter_get_arg_type (&reply_iter) != 1483 DBUS_TYPE_DOUBLE) { 1484 fprintf (stderr, 1485 "%s %d : property '%s' for device '%s' is not " 1486 "of type double\n", __FILE__, __LINE__, key, udi); 1487 dbus_message_unref (reply); 1488 return -1.0f; 1489 } 1490 dbus_message_iter_get_basic (&reply_iter, &value); 1491 1492 dbus_message_unref (reply); 1493 return (double) value; 1494 } 1495 1496 /** 1497 * libhal_device_get_property_bool: 1498 * @ctx: the context for the connection to hald 1499 * @udi: the Unique Device Id 1500 * @key: name of the property 1501 * @error: pointer to an initialized dbus error object for returning errors or NULL 1502 * 1503 * Get the value of a property of type bool. 1504 * 1505 * Returns: Property value (boolean) 1506 */ 1507 dbus_bool_t 1508 libhal_device_get_property_bool (LibHalContext *ctx, 1509 const char *udi, const char *key, DBusError *error) 1510 { 1511 DBusMessage *message; 1512 DBusMessage *reply; 1513 DBusMessageIter iter, reply_iter; 1514 dbus_bool_t value; 1515 DBusError _error; 1516 1517 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1518 1519 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1520 "org.freedesktop.Hal.Device", 1521 "GetPropertyBoolean"); 1522 if (message == NULL) { 1523 fprintf (stderr, 1524 "%s %d : Couldn't allocate D-BUS message\n", 1525 __FILE__, __LINE__); 1526 return FALSE; 1527 } 1528 1529 dbus_message_iter_init_append (message, &iter); 1530 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1531 1532 dbus_error_init (&_error); 1533 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1534 message, -1, 1535 &_error); 1536 1537 dbus_message_unref (message); 1538 1539 dbus_move_error (&_error, error); 1540 if (error != NULL && dbus_error_is_set (error)) { 1541 return FALSE; 1542 } 1543 if (reply == NULL) { 1544 return FALSE; 1545 } 1546 1547 dbus_message_iter_init (reply, &reply_iter); 1548 1549 /* now analyze reply */ 1550 if (dbus_message_iter_get_arg_type (&reply_iter) != 1551 DBUS_TYPE_BOOLEAN) { 1552 fprintf (stderr, 1553 "%s %d : property '%s' for device '%s' is not " 1554 "of type bool\n", __FILE__, __LINE__, key, udi); 1555 dbus_message_unref (reply); 1556 return FALSE; 1557 } 1558 dbus_message_iter_get_basic (&reply_iter, &value); 1559 1560 dbus_message_unref (reply); 1561 return value; 1562 } 1563 1564 1565 /* generic helper */ 1566 static dbus_bool_t 1567 libhal_device_set_property_helper (LibHalContext *ctx, 1568 const char *udi, 1569 const char *key, 1570 int type, 1571 const char *str_value, 1572 dbus_int32_t int_value, 1573 dbus_uint64_t uint64_value, 1574 double double_value, 1575 dbus_bool_t bool_value, 1576 DBusError *error) 1577 { 1578 DBusMessage *message; 1579 DBusMessage *reply; 1580 DBusMessageIter iter; 1581 char *method_name = NULL; 1582 1583 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1584 1585 /** @todo sanity check incoming params */ 1586 switch (type) { 1587 case DBUS_TYPE_INVALID: 1588 method_name = "RemoveProperty"; 1589 break; 1590 case DBUS_TYPE_STRING: 1591 method_name = "SetPropertyString"; 1592 break; 1593 case DBUS_TYPE_INT32: 1594 case DBUS_TYPE_UINT64: 1595 method_name = "SetPropertyInteger"; 1596 break; 1597 case DBUS_TYPE_DOUBLE: 1598 method_name = "SetPropertyDouble"; 1599 break; 1600 case DBUS_TYPE_BOOLEAN: 1601 method_name = "SetPropertyBoolean"; 1602 break; 1603 1604 default: 1605 /* cannot happen; is not callable from outside this file */ 1606 break; 1607 } 1608 1609 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1610 "org.freedesktop.Hal.Device", 1611 method_name); 1612 if (message == NULL) { 1613 fprintf (stderr, 1614 "%s %d : Couldn't allocate D-BUS message\n", 1615 __FILE__, __LINE__); 1616 return FALSE; 1617 } 1618 1619 dbus_message_iter_init_append (message, &iter); 1620 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1621 switch (type) { 1622 case DBUS_TYPE_STRING: 1623 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str_value); 1624 break; 1625 case DBUS_TYPE_INT32: 1626 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &int_value); 1627 break; 1628 case DBUS_TYPE_UINT64: 1629 dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &uint64_value); 1630 break; 1631 case DBUS_TYPE_DOUBLE: 1632 dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &double_value); 1633 break; 1634 case DBUS_TYPE_BOOLEAN: 1635 dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bool_value); 1636 break; 1637 } 1638 1639 1640 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1641 message, -1, 1642 error); 1643 1644 dbus_message_unref (message); 1645 1646 if (error != NULL && dbus_error_is_set (error)) { 1647 return FALSE; 1648 } 1649 if (reply == NULL) { 1650 return FALSE; 1651 } 1652 1653 dbus_message_unref (reply); 1654 1655 return TRUE; 1656 } 1657 1658 /** 1659 * libhal_device_set_property_string: 1660 * @ctx: the context for the connection to hald 1661 * @udi: the Unique Device Id 1662 * @key: name of the property 1663 * @value: value of the property; a UTF8 string 1664 * @error: pointer to an initialized dbus error object for returning errors or NULL 1665 * 1666 * Set a property of type string. 1667 * 1668 * Returns: TRUE if the property was set, FALSE if the device didn't 1669 * exist or the property had a different type. 1670 */ 1671 dbus_bool_t 1672 libhal_device_set_property_string (LibHalContext *ctx, 1673 const char *udi, 1674 const char *key, 1675 const char *value, 1676 DBusError *error) 1677 { 1678 return libhal_device_set_property_helper (ctx, udi, key, 1679 DBUS_TYPE_STRING, 1680 value, 0, 0, 0.0f, FALSE, error); 1681 } 1682 1683 /** 1684 * libhal_device_set_property_int: 1685 * @ctx: the context for the connection to hald 1686 * @udi: the Unique Device Id 1687 * @key: name of the property 1688 * @value: value of the property 1689 * @error: pointer to an initialized dbus error object for returning errors or NULL 1690 * 1691 * Set a property of type signed integer. 1692 * 1693 * Returns: TRUE if the property was set, FALSE if the device didn't 1694 * exist or the property had a different type. 1695 */ 1696 dbus_bool_t 1697 libhal_device_set_property_int (LibHalContext *ctx, const char *udi, 1698 const char *key, dbus_int32_t value, DBusError *error) 1699 { 1700 return libhal_device_set_property_helper (ctx, udi, key, 1701 DBUS_TYPE_INT32, 1702 NULL, value, 0, 0.0f, FALSE, error); 1703 } 1704 1705 /** 1706 * libhal_device_set_property_uint64: 1707 * @ctx: the context for the connection to hald 1708 * @udi: the Unique Device Id 1709 * @key: name of the property 1710 * @value: value of the property 1711 * @error: pointer to an initialized dbus error object for returning errors or NULL 1712 * 1713 * Set a property of type unsigned integer. 1714 * 1715 * Returns: TRUE if the property was set, FALSE if the device didn't 1716 * exist or the property had a different type. 1717 */ 1718 dbus_bool_t 1719 libhal_device_set_property_uint64 (LibHalContext *ctx, const char *udi, 1720 const char *key, dbus_uint64_t value, DBusError *error) 1721 { 1722 return libhal_device_set_property_helper (ctx, udi, key, 1723 DBUS_TYPE_UINT64, 1724 NULL, 0, value, 0.0f, FALSE, error); 1725 } 1726 1727 /** 1728 * libhal_device_set_property_double: 1729 * @ctx: the context for the connection to hald 1730 * @udi: the Unique Device Id 1731 * @key: name of the property 1732 * @value: value of the property 1733 * @error: pointer to an initialized dbus error object for returning errors or NULL 1734 * 1735 * Set a property of type double. 1736 * 1737 * Returns: TRUE if the property was set, FALSE if the device didn't 1738 * exist or the property had a different type. 1739 */ 1740 dbus_bool_t 1741 libhal_device_set_property_double (LibHalContext *ctx, const char *udi, 1742 const char *key, double value, DBusError *error) 1743 { 1744 return libhal_device_set_property_helper (ctx, udi, key, 1745 DBUS_TYPE_DOUBLE, 1746 NULL, 0, 0, value, FALSE, error); 1747 } 1748 1749 /** 1750 * libhal_device_set_property_bool: 1751 * @ctx: the context for the connection to hald 1752 * @udi: the Unique Device Id 1753 * @key: name of the property 1754 * @value: value of the property 1755 * @error: pointer to an initialized dbus error object for returning errors or NULL 1756 * 1757 * Set a property of type bool. 1758 * 1759 * Returns: TRUE if the property was set, FALSE if the device didn't 1760 * exist or the property had a different type. 1761 */ 1762 dbus_bool_t 1763 libhal_device_set_property_bool (LibHalContext *ctx, const char *udi, 1764 const char *key, dbus_bool_t value, DBusError *error) 1765 { 1766 return libhal_device_set_property_helper (ctx, udi, key, 1767 DBUS_TYPE_BOOLEAN, 1768 NULL, 0, 0, 0.0f, value, error); 1769 } 1770 1771 1772 /** 1773 * libhal_device_remove_property: 1774 * @ctx: the context for the connection to hald 1775 * @udi: the Unique Device Id 1776 * @key: name of the property 1777 * @error: pointer to an initialized dbus error object for returning errors or NULL 1778 * 1779 * Remove a property. 1780 * 1781 * Returns: TRUE if the property was set, FALSE if the device didn't 1782 * exist 1783 */ 1784 dbus_bool_t 1785 libhal_device_remove_property (LibHalContext *ctx, 1786 const char *udi, const char *key, DBusError *error) 1787 { 1788 return libhal_device_set_property_helper (ctx, udi, key, DBUS_TYPE_INVALID, 1789 /* DBUS_TYPE_INVALID means remove */ 1790 NULL, 0, 0, 0.0f, FALSE, error); 1791 } 1792 1793 /** 1794 * libhal_device_property_strlist_append: 1795 * @ctx: the context for the connection to hald 1796 * @udi: the Unique Device Id 1797 * @key: name of the property 1798 * @value: value to append to property 1799 * @error: pointer to an initialized dbus error object for returning errors or NULL 1800 * 1801 * Append to a property of type strlist. 1802 * 1803 * Returns: TRUE if the value was appended, FALSE if the device didn't 1804 * exist or the property had a different type. 1805 */ 1806 dbus_bool_t 1807 libhal_device_property_strlist_append (LibHalContext *ctx, 1808 const char *udi, 1809 const char *key, 1810 const char *value, 1811 DBusError *error) 1812 { 1813 DBusMessage *message; 1814 DBusMessage *reply; 1815 DBusMessageIter iter; 1816 1817 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1818 1819 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1820 "org.freedesktop.Hal.Device", 1821 "StringListAppend"); 1822 if (message == NULL) { 1823 fprintf (stderr, 1824 "%s %d : Couldn't allocate D-BUS message\n", 1825 __FILE__, __LINE__); 1826 return FALSE; 1827 } 1828 dbus_message_iter_init_append (message, &iter); 1829 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1830 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); 1831 1832 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1833 message, -1, 1834 error); 1835 1836 dbus_message_unref (message); 1837 1838 if (error != NULL && dbus_error_is_set (error)) { 1839 return FALSE; 1840 } 1841 if (reply == NULL) { 1842 return FALSE; 1843 } 1844 1845 dbus_message_unref (reply); 1846 return TRUE; 1847 } 1848 1849 /** 1850 * libhal_device_property_strlist_prepend: 1851 * @ctx: the context for the connection to hald 1852 * @udi: the Unique Device Id 1853 * @key: name of the property 1854 * @value: value to prepend to property 1855 * @error: pointer to an initialized dbus error object for returning errors or NULL 1856 * 1857 * Prepend to a property of type strlist. 1858 * 1859 * Returns: TRUE if the value was prepended, FALSE if the device 1860 * didn't exist or the property had a different type. 1861 */ 1862 dbus_bool_t 1863 libhal_device_property_strlist_prepend (LibHalContext *ctx, 1864 const char *udi, 1865 const char *key, 1866 const char *value, 1867 DBusError *error) 1868 { 1869 DBusMessage *message; 1870 DBusMessage *reply; 1871 DBusMessageIter iter; 1872 1873 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1874 1875 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1876 "org.freedesktop.Hal.Device", 1877 "StringListPrepend"); 1878 if (message == NULL) { 1879 fprintf (stderr, 1880 "%s %d : Couldn't allocate D-BUS message\n", 1881 __FILE__, __LINE__); 1882 return FALSE; 1883 } 1884 dbus_message_iter_init_append (message, &iter); 1885 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1886 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); 1887 1888 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1889 message, -1, 1890 error); 1891 1892 dbus_message_unref (message); 1893 1894 if (error != NULL && dbus_error_is_set (error)) { 1895 return FALSE; 1896 } 1897 if (reply == NULL) { 1898 return FALSE; 1899 } 1900 1901 dbus_message_unref (reply); 1902 return TRUE; 1903 } 1904 1905 /** 1906 * libhal_device_property_strlist_remove_index: 1907 * @ctx: the context for the connection to hald 1908 * @udi: the Unique Device Id 1909 * @key: name of the property 1910 * @idx: index of string to remove in the strlist 1911 * @error: pointer to an initialized dbus error object for returning errors or NULL 1912 * 1913 * Remove a specified string from a property of type strlist. 1914 * 1915 * Returns: TRUE if the string was removed, FALSE if the device didn't 1916 * exist or the property had a different type. 1917 */ 1918 dbus_bool_t 1919 libhal_device_property_strlist_remove_index (LibHalContext *ctx, 1920 const char *udi, 1921 const char *key, 1922 unsigned int idx, 1923 DBusError *error) 1924 { 1925 DBusMessage *message; 1926 DBusMessage *reply; 1927 DBusMessageIter iter; 1928 1929 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1930 1931 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1932 "org.freedesktop.Hal.Device", 1933 "StringListRemoveIndex"); 1934 if (message == NULL) { 1935 fprintf (stderr, 1936 "%s %d : Couldn't allocate D-BUS message\n", 1937 __FILE__, __LINE__); 1938 return FALSE; 1939 } 1940 dbus_message_iter_init_append (message, &iter); 1941 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1942 dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &idx); 1943 1944 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 1945 message, -1, 1946 error); 1947 1948 dbus_message_unref (message); 1949 1950 if (error != NULL && dbus_error_is_set (error)) { 1951 return FALSE; 1952 } 1953 if (reply == NULL) { 1954 return FALSE; 1955 } 1956 1957 dbus_message_unref (reply); 1958 return TRUE; 1959 } 1960 1961 /** 1962 * libhal_device_property_strlist_remove: 1963 * @ctx: the context for the connection to hald 1964 * @udi: the Unique Device Id 1965 * @key: name of the property 1966 * @value: the string to remove 1967 * @error: pointer to an initialized dbus error object for returning errors or NULL 1968 * 1969 * Remove a specified string from a property of type strlist. 1970 * 1971 * Returns: TRUE if the string was removed, FALSE if the device didn't 1972 * exist or the property had a different type. 1973 */ 1974 dbus_bool_t 1975 libhal_device_property_strlist_remove (LibHalContext *ctx, 1976 const char *udi, 1977 const char *key, 1978 const char *value, DBusError *error) 1979 { 1980 DBusMessage *message; 1981 DBusMessage *reply; 1982 DBusMessageIter iter; 1983 1984 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 1985 1986 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 1987 "org.freedesktop.Hal.Device", 1988 "StringListRemove"); 1989 if (message == NULL) { 1990 fprintf (stderr, 1991 "%s %d : Couldn't allocate D-BUS message\n", 1992 __FILE__, __LINE__); 1993 return FALSE; 1994 } 1995 dbus_message_iter_init_append (message, &iter); 1996 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 1997 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); 1998 1999 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2000 message, -1, 2001 error); 2002 2003 dbus_message_unref (message); 2004 2005 if (error != NULL && dbus_error_is_set (error)) { 2006 return FALSE; 2007 } 2008 if (reply == NULL) { 2009 return FALSE; 2010 } 2011 2012 dbus_message_unref (reply); 2013 return TRUE; 2014 } 2015 2016 2017 /** 2018 * libhal_device_lock: 2019 * @ctx: the context for the connection to hald 2020 * @udi: the Unique Device Id 2021 * @reason_to_lock: a user-presentable reason why the device is locked. 2022 * @reason_why_locked: a pointer to store the reason why the device cannot be locked on failure, or NULL 2023 * @error: pointer to an initialized dbus error object for returning errors or NULL 2024 * 2025 * Take an advisory lock on the device. 2026 * 2027 * Returns: TRUE if the lock was obtained, FALSE otherwise 2028 */ 2029 dbus_bool_t 2030 libhal_device_lock (LibHalContext *ctx, 2031 const char *udi, 2032 const char *reason_to_lock, 2033 char **reason_why_locked, DBusError *error) 2034 { 2035 DBusMessage *message; 2036 DBusMessageIter iter; 2037 DBusMessage *reply; 2038 2039 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2040 2041 if (reason_why_locked != NULL) 2042 *reason_why_locked = NULL; 2043 2044 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2045 udi, 2046 "org.freedesktop.Hal.Device", 2047 "Lock"); 2048 2049 if (message == NULL) { 2050 fprintf (stderr, 2051 "%s %d : Couldn't allocate D-BUS message\n", 2052 __FILE__, __LINE__); 2053 return FALSE; 2054 } 2055 2056 dbus_message_iter_init_append (message, &iter); 2057 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reason_to_lock); 2058 2059 2060 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2061 message, -1, 2062 error); 2063 2064 dbus_message_unref (message); 2065 2066 if (error != NULL && dbus_error_is_set (error)) { 2067 if (strcmp (error->name, 2068 "org.freedesktop.Hal.DeviceAlreadyLocked") == 0) { 2069 if (reason_why_locked != NULL) { 2070 *reason_why_locked = 2071 dbus_malloc0 (strlen (error->message) + 1); 2072 if (*reason_why_locked == NULL) 2073 return FALSE; 2074 strcpy (*reason_why_locked, error->message); 2075 } 2076 } 2077 2078 return FALSE; 2079 } 2080 if (reply == NULL) 2081 return FALSE; 2082 2083 dbus_message_unref (reply); 2084 2085 return TRUE; 2086 } 2087 2088 /** 2089 * libhal_device_unlock: 2090 * @ctx: the context for the connection to hald 2091 * @udi: the Unique Device Id 2092 * @error: pointer to an initialized dbus error object for returning errors or NULL 2093 * 2094 * Release an advisory lock on the device. 2095 * 2096 * Returns: TRUE if the device was successfully unlocked, 2097 * FALSE otherwise 2098 */ 2099 dbus_bool_t 2100 libhal_device_unlock (LibHalContext *ctx, 2101 const char *udi, DBusError *error) 2102 { 2103 DBusMessage *message; 2104 DBusMessage *reply; 2105 2106 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2107 2108 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2109 udi, 2110 "org.freedesktop.Hal.Device", 2111 "Unlock"); 2112 2113 if (message == NULL) { 2114 fprintf (stderr, 2115 "%s %d : Couldn't allocate D-BUS message\n", 2116 __FILE__, __LINE__); 2117 return FALSE; 2118 } 2119 2120 2121 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2122 message, -1, 2123 error); 2124 2125 dbus_message_unref (message); 2126 2127 if (error != NULL && dbus_error_is_set (error)) { 2128 return FALSE; 2129 } 2130 if (reply == NULL) 2131 return FALSE; 2132 2133 dbus_message_unref (reply); 2134 2135 return TRUE; 2136 } 2137 2138 2139 /** 2140 * libhal_new_device: 2141 * @ctx: the context for the connection to hald 2142 * @error: pointer to an initialized dbus error object for returning errors or NULL 2143 * 2144 * Create a new device object which will be hidden from applications 2145 * until the CommitToGdl(), ie. libhal_device_commit_to_gdl(), method 2146 * is called. Note that the program invoking this method needs to run 2147 * with super user privileges. 2148 * 2149 * Returns: Temporary device unique id or NULL if there was a 2150 * problem. This string must be freed by the caller. 2151 */ 2152 char * 2153 libhal_new_device (LibHalContext *ctx, DBusError *error) 2154 { 2155 DBusMessage *message; 2156 DBusMessage *reply; 2157 DBusMessageIter reply_iter; 2158 char *value; 2159 char *dbus_str; 2160 2161 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 2162 2163 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2164 "/org/freedesktop/Hal/Manager", 2165 "org.freedesktop.Hal.Manager", 2166 "NewDevice"); 2167 if (message == NULL) { 2168 fprintf (stderr, 2169 "%s %d : Couldn't allocate D-BUS message\n", 2170 __FILE__, __LINE__); 2171 return NULL; 2172 } 2173 2174 2175 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2176 message, -1, 2177 error); 2178 2179 dbus_message_unref (message); 2180 2181 if (error != NULL && dbus_error_is_set (error)) { 2182 return NULL; 2183 } 2184 if (reply == NULL) { 2185 return NULL; 2186 } 2187 2188 dbus_message_iter_init (reply, &reply_iter); 2189 2190 /* now analyze reply */ 2191 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_STRING) { 2192 fprintf (stderr, 2193 "%s %d : expected a string in reply to NewDevice\n", 2194 __FILE__, __LINE__); 2195 dbus_message_unref (reply); 2196 return NULL; 2197 } 2198 2199 dbus_message_iter_get_basic (&reply_iter, &dbus_str); 2200 value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL); 2201 if (value == NULL) { 2202 fprintf (stderr, "%s %d : error allocating memory\n", 2203 __FILE__, __LINE__); 2204 } 2205 2206 dbus_message_unref (reply); 2207 return value; 2208 } 2209 2210 2211 /** 2212 * libhal_device_commit_to_gdl: 2213 * @ctx: the context for the connection to hald 2214 * @temp_udi: the temporary unique device id as returned by libhal_new_device() 2215 * @udi: the new unique device id. 2216 * @error: pointer to an initialized dbus error object for returning errors or NULL 2217 * 2218 * When a hidden device has been built using the NewDevice method, 2219 * ie. libhal_new_device(), and the org.freedesktop.Hal.Device 2220 * interface this function will commit it to the global device list. 2221 * 2222 * This means that the device object will be visible to applications 2223 * and the HAL daemon will possibly attempt to boot the device 2224 * (depending on the property RequireEnable). 2225 * 2226 * Note that the program invoking this method needs to run with super 2227 * user privileges. 2228 * 2229 * Returns: FALSE if the given unique device id is already in use. 2230 */ 2231 dbus_bool_t 2232 libhal_device_commit_to_gdl (LibHalContext *ctx, 2233 const char *temp_udi, const char *udi, DBusError *error) 2234 { 2235 DBusMessage *message; 2236 DBusMessage *reply; 2237 DBusMessageIter iter; 2238 2239 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2240 2241 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2242 "/org/freedesktop/Hal/Manager", 2243 "org.freedesktop.Hal.Manager", 2244 "CommitToGdl"); 2245 if (message == NULL) { 2246 fprintf (stderr, 2247 "%s %d : Couldn't allocate D-BUS message\n", 2248 __FILE__, __LINE__); 2249 return FALSE; 2250 } 2251 2252 dbus_message_iter_init_append (message, &iter); 2253 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &temp_udi); 2254 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); 2255 2256 2257 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2258 message, -1, 2259 error); 2260 2261 dbus_message_unref (message); 2262 2263 if (error != NULL && dbus_error_is_set (error)) { 2264 return FALSE; 2265 } 2266 if (reply == NULL) { 2267 return FALSE; 2268 } 2269 2270 dbus_message_unref (reply); 2271 return TRUE; 2272 } 2273 2274 /** 2275 * libhal_remove_device: 2276 * @ctx: the context for the connection to hald 2277 * @udi: the Unique device id. 2278 * @error: pointer to an initialized dbus error object for returning errors or NULL 2279 * 2280 * This method can be invoked when a device is removed. The HAL daemon 2281 * will shut down the device. Note that the device may still be in the 2282 * device list if the Persistent property is set to true. 2283 * 2284 * Note that the program invoking this method needs to run with super 2285 * user privileges. 2286 * 2287 * Returns: TRUE if the device was removed, FALSE otherwise 2288 */ 2289 dbus_bool_t 2290 libhal_remove_device (LibHalContext *ctx, const char *udi, DBusError *error) 2291 { 2292 DBusMessage *message; 2293 DBusMessage *reply; 2294 DBusMessageIter iter; 2295 2296 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2297 2298 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2299 "/org/freedesktop/Hal/Manager", 2300 "org.freedesktop.Hal.Manager", 2301 "Remove"); 2302 if (message == NULL) { 2303 fprintf (stderr, 2304 "%s %d : Couldn't allocate D-BUS message\n", 2305 __FILE__, __LINE__); 2306 return FALSE; 2307 } 2308 2309 dbus_message_iter_init_append (message, &iter); 2310 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); 2311 2312 2313 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2314 message, -1, 2315 error); 2316 2317 dbus_message_unref (message); 2318 2319 if (error != NULL && dbus_error_is_set (error)) { 2320 return FALSE; 2321 } 2322 if (reply == NULL) { 2323 return FALSE; 2324 } 2325 2326 dbus_message_unref (reply); 2327 return TRUE; 2328 } 2329 2330 /** 2331 * libhal_device_exists: 2332 * @ctx: the context for the connection to hald 2333 * @udi: the Unique device id. 2334 * @error: pointer to an initialized dbus error object for returning errors or NULL 2335 * 2336 * Determine if a device exists. 2337 * 2338 * Returns: TRUE if the device exists 2339 */ 2340 dbus_bool_t 2341 libhal_device_exists (LibHalContext *ctx, const char *udi, DBusError *error) 2342 { 2343 DBusMessage *message; 2344 DBusMessage *reply; 2345 DBusMessageIter iter, reply_iter; 2346 dbus_bool_t value; 2347 DBusError _error; 2348 2349 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2350 2351 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2352 "/org/freedesktop/Hal/Manager", 2353 "org.freedesktop.Hal.Manager", 2354 "DeviceExists"); 2355 if (message == NULL) { 2356 fprintf (stderr, 2357 "%s %d : Couldn't allocate D-BUS message\n", 2358 __FILE__, __LINE__); 2359 return FALSE; 2360 } 2361 2362 dbus_message_iter_init_append (message, &iter); 2363 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); 2364 2365 dbus_error_init (&_error); 2366 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2367 message, -1, 2368 &_error); 2369 2370 dbus_message_unref (message); 2371 2372 dbus_move_error (&_error, error); 2373 if (error != NULL && dbus_error_is_set (error)) { 2374 return FALSE; 2375 } 2376 if (reply == NULL) { 2377 return FALSE; 2378 } 2379 2380 dbus_message_iter_init (reply, &reply_iter); 2381 2382 /* now analyze reply */ 2383 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { 2384 fprintf (stderr, 2385 "%s %d : expected a bool in reply to DeviceExists\n", 2386 __FILE__, __LINE__); 2387 dbus_message_unref (reply); 2388 return FALSE; 2389 } 2390 2391 dbus_message_iter_get_basic (&reply_iter, &value); 2392 2393 dbus_message_unref (reply); 2394 return value; 2395 } 2396 2397 /** 2398 * libhal_device_property_exists: 2399 * @ctx: the context for the connection to hald 2400 * @udi: the Unique device id. 2401 * @key: name of the property 2402 * @error: pointer to an initialized dbus error object for returning errors or NULL 2403 * 2404 * Determine if a property on a device exists. 2405 * 2406 * Returns: TRUE if the device exists, FALSE otherwise 2407 */ 2408 dbus_bool_t 2409 libhal_device_property_exists (LibHalContext *ctx, 2410 const char *udi, const char *key, DBusError *error) 2411 { 2412 DBusMessage *message; 2413 DBusMessage *reply; 2414 DBusMessageIter iter, reply_iter; 2415 dbus_bool_t value; 2416 DBusError _error; 2417 2418 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2419 2420 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 2421 "org.freedesktop.Hal.Device", 2422 "PropertyExists"); 2423 if (message == NULL) { 2424 fprintf (stderr, 2425 "%s %d : Couldn't allocate D-BUS message\n", 2426 __FILE__, __LINE__); 2427 return FALSE; 2428 } 2429 2430 dbus_message_iter_init_append (message, &iter); 2431 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 2432 2433 dbus_error_init (&_error); 2434 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2435 message, -1, 2436 &_error); 2437 2438 dbus_message_unref (message); 2439 2440 dbus_move_error (&_error, error); 2441 if (error != NULL && dbus_error_is_set (error)) { 2442 return FALSE; 2443 } 2444 if (reply == NULL) { 2445 return FALSE; 2446 } 2447 2448 dbus_message_iter_init (reply, &reply_iter); 2449 2450 /* now analyse reply */ 2451 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { 2452 fprintf (stderr, "%s %d : expected a bool in reply to " 2453 "PropertyExists\n", __FILE__, __LINE__); 2454 dbus_message_unref (reply); 2455 return FALSE; 2456 } 2457 2458 dbus_message_iter_get_basic (&reply_iter, &value); 2459 2460 dbus_message_unref (reply); 2461 return value; 2462 } 2463 2464 /** 2465 * libhal_merge_properties: 2466 * @ctx: the context for the connection to hald 2467 * @target_udi: the Unique device id of target device to merge to 2468 * @source_udi: the Unique device id of device to merge from 2469 * @error: pointer to an initialized dbus error object for returning errors or NULL 2470 * 2471 * Merge properties from one device to another. 2472 * 2473 * Returns: TRUE if the properties were merged, FALSE otherwise 2474 */ 2475 dbus_bool_t 2476 libhal_merge_properties (LibHalContext *ctx, 2477 const char *target_udi, const char *source_udi, DBusError *error) 2478 { 2479 DBusMessage *message; 2480 DBusMessage *reply; 2481 DBusMessageIter iter; 2482 2483 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2484 2485 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2486 "/org/freedesktop/Hal/Manager", 2487 "org.freedesktop.Hal.Manager", 2488 "MergeProperties"); 2489 if (message == NULL) { 2490 fprintf (stderr, 2491 "%s %d : Couldn't allocate D-BUS message\n", 2492 __FILE__, __LINE__); 2493 return FALSE; 2494 } 2495 2496 dbus_message_iter_init_append (message, &iter); 2497 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &target_udi); 2498 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &source_udi); 2499 2500 2501 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2502 message, -1, 2503 error); 2504 2505 dbus_message_unref (message); 2506 2507 if (error != NULL && dbus_error_is_set (error)) { 2508 return FALSE; 2509 } 2510 if (reply == NULL) { 2511 return FALSE; 2512 } 2513 2514 dbus_message_unref (reply); 2515 return TRUE; 2516 } 2517 2518 /** 2519 * libhal_device_matches: 2520 * @ctx: the context for the connection to hald 2521 * @udi1: the Unique Device Id for device 1 2522 * @udi2: the Unique Device Id for device 2 2523 * @property_namespace: the namespace for set of devices, e.g. "usb" 2524 * @error: pointer to an initialized dbus error object for returning errors or NULL 2525 * 2526 * Check a set of properties for two devices matches. 2527 * 2528 * Checks that all properties where keys, starting with a given value 2529 * (namespace), of the first device is in the second device and that 2530 * they got the same value and type. 2531 * 2532 * Note that the other inclusion isn't tested, so there could be 2533 * properties (from the given namespace) in the second device not 2534 * present in the first device. 2535 * 2536 * Returns: TRUE if all properties starting with the given namespace 2537 * parameter from one device is in the other and have the same value. 2538 */ 2539 dbus_bool_t 2540 libhal_device_matches (LibHalContext *ctx, 2541 const char *udi1, const char *udi2, 2542 const char *property_namespace, DBusError *error) 2543 { 2544 DBusMessage *message; 2545 DBusMessage *reply; 2546 DBusMessageIter iter, reply_iter; 2547 dbus_bool_t value; 2548 DBusError _error; 2549 2550 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2551 2552 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2553 "/org/freedesktop/Hal/Manager", 2554 "org.freedesktop.Hal.Manager", 2555 "DeviceMatches"); 2556 if (message == NULL) { 2557 fprintf (stderr, 2558 "%s %d : Couldn't allocate D-BUS message\n", 2559 __FILE__, __LINE__); 2560 return FALSE; 2561 } 2562 2563 dbus_message_iter_init_append (message, &iter); 2564 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi1); 2565 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi2); 2566 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, property_namespace); 2567 2568 dbus_error_init (&_error); 2569 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2570 message, -1, 2571 &_error); 2572 2573 dbus_message_unref (message); 2574 2575 dbus_move_error (&_error, error); 2576 if (error != NULL && dbus_error_is_set (error)) { 2577 return FALSE; 2578 } 2579 if (reply == NULL) { 2580 return FALSE; 2581 } 2582 /* now analyse reply */ 2583 dbus_message_iter_init (reply, &reply_iter); 2584 2585 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { 2586 fprintf (stderr, 2587 "%s %d : expected a bool in reply to DeviceMatches\n", 2588 __FILE__, __LINE__); 2589 dbus_message_unref (reply); 2590 return FALSE; 2591 } 2592 2593 dbus_message_iter_get_basic (&reply_iter, &value); 2594 2595 dbus_message_unref (reply); 2596 return value; 2597 } 2598 2599 /** 2600 * libhal_device_print: 2601 * @ctx: the context for the connection to hald 2602 * @udi: the Unique Device Id 2603 * @error: pointer to an initialized dbus error object for returning errors or NULL 2604 * 2605 * Print a device to stdout; useful for debugging. 2606 * 2607 * Returns: TRUE if device's information could be obtained, FALSE otherwise 2608 */ 2609 dbus_bool_t 2610 libhal_device_print (LibHalContext *ctx, const char *udi, DBusError *error) 2611 { 2612 int type; 2613 char *key; 2614 LibHalPropertySet *pset; 2615 LibHalPropertySetIterator i; 2616 2617 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2618 2619 printf ("device_id = %s\n", udi); 2620 2621 if ((pset = libhal_device_get_all_properties (ctx, udi, error)) == NULL) 2622 return FALSE; 2623 2624 for (libhal_psi_init (&i, pset); libhal_psi_has_more (&i); 2625 libhal_psi_next (&i)) { 2626 type = libhal_psi_get_type (&i); 2627 key = libhal_psi_get_key (&i); 2628 2629 switch (type) { 2630 case LIBHAL_PROPERTY_TYPE_STRING: 2631 printf (" %s = '%s' (string)\n", key, 2632 libhal_psi_get_string (&i)); 2633 break; 2634 case LIBHAL_PROPERTY_TYPE_INT32: 2635 printf (" %s = %d = 0x%x (int)\n", key, 2636 libhal_psi_get_int (&i), 2637 libhal_psi_get_int (&i)); 2638 break; 2639 case LIBHAL_PROPERTY_TYPE_UINT64: 2640 printf (" %s = %llu = 0x%llx (uint64)\n", key, 2641 (long long unsigned int) libhal_psi_get_uint64 (&i), 2642 (long long unsigned int) libhal_psi_get_uint64 (&i)); 2643 break; 2644 case LIBHAL_PROPERTY_TYPE_BOOLEAN: 2645 printf (" %s = %s (bool)\n", key, 2646 (libhal_psi_get_bool (&i) ? "true" : 2647 "false")); 2648 break; 2649 case LIBHAL_PROPERTY_TYPE_DOUBLE: 2650 printf (" %s = %g (double)\n", key, 2651 libhal_psi_get_double (&i)); 2652 break; 2653 case LIBHAL_PROPERTY_TYPE_STRLIST: 2654 { 2655 unsigned int j; 2656 char **str_list; 2657 2658 str_list = libhal_psi_get_strlist (&i); 2659 printf (" %s = [", key); 2660 for (j = 0; str_list[j] != NULL; j++) { 2661 printf ("'%s'", str_list[j]); 2662 if (str_list[j+1] != NULL) 2663 printf (", "); 2664 } 2665 printf ("] (string list)\n"); 2666 2667 break; 2668 } 2669 default: 2670 printf (" *** unknown type for key %s\n", key); 2671 break; 2672 } 2673 } 2674 2675 libhal_free_property_set (pset); 2676 2677 return TRUE; 2678 } 2679 2680 /** 2681 * libhal_manager_find_device_string_match: 2682 * @ctx: the context for the connection to hald 2683 * @key: name of the property 2684 * @value: the value to match 2685 * @num_devices: pointer to store number of devices 2686 * @error: pointer to an initialized dbus error object for returning errors or NULL 2687 * 2688 * Find a device in the GDL where a single string property matches a 2689 * given value. 2690 * 2691 * Returns: UDI of devices; free with libhal_free_string_array() 2692 */ 2693 char ** 2694 libhal_manager_find_device_string_match (LibHalContext *ctx, 2695 const char *key, 2696 const char *value, int *num_devices, DBusError *error) 2697 { 2698 DBusMessage *message; 2699 DBusMessage *reply; 2700 DBusMessageIter iter, iter_array, reply_iter; 2701 char **hal_device_names; 2702 DBusError _error; 2703 2704 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 2705 2706 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2707 "/org/freedesktop/Hal/Manager", 2708 "org.freedesktop.Hal.Manager", 2709 "FindDeviceStringMatch"); 2710 if (message == NULL) { 2711 fprintf (stderr, 2712 "%s %d : Couldn't allocate D-BUS message\n", 2713 __FILE__, __LINE__); 2714 return NULL; 2715 } 2716 2717 dbus_message_iter_init_append (message, &iter); 2718 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); 2719 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); 2720 2721 dbus_error_init (&_error); 2722 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2723 message, -1, 2724 &_error); 2725 2726 dbus_message_unref (message); 2727 2728 dbus_move_error (&_error, error); 2729 if (error != NULL && dbus_error_is_set (error)) { 2730 return NULL; 2731 } 2732 if (reply == NULL) { 2733 return NULL; 2734 } 2735 /* now analyse reply */ 2736 dbus_message_iter_init (reply, &reply_iter); 2737 2738 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { 2739 fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); 2740 return NULL; 2741 } 2742 2743 dbus_message_iter_recurse (&reply_iter, &iter_array); 2744 2745 hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); 2746 2747 dbus_message_unref (reply); 2748 return hal_device_names; 2749 } 2750 2751 2752 /** 2753 * libhal_device_add_capability: 2754 * @ctx: the context for the connection to hald 2755 * @udi: the Unique Device Id 2756 * @capability: the capability name to add 2757 * @error: pointer to an initialized dbus error object for returning errors or NULL 2758 * 2759 * Assign a capability to a device. 2760 * 2761 * Returns: TRUE if the capability was added, FALSE if the device didn't exist 2762 */ 2763 dbus_bool_t 2764 libhal_device_add_capability (LibHalContext *ctx, 2765 const char *udi, const char *capability, DBusError *error) 2766 { 2767 DBusMessage *message; 2768 DBusMessage *reply; 2769 DBusMessageIter iter; 2770 2771 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2772 2773 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 2774 "org.freedesktop.Hal.Device", 2775 "AddCapability"); 2776 if (message == NULL) { 2777 fprintf (stderr, 2778 "%s %d : Couldn't allocate D-BUS message\n", 2779 __FILE__, __LINE__); 2780 return FALSE; 2781 } 2782 2783 dbus_message_iter_init_append (message, &iter); 2784 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability); 2785 2786 2787 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2788 message, -1, 2789 error); 2790 2791 dbus_message_unref (message); 2792 2793 if (error != NULL && dbus_error_is_set (error)) { 2794 return FALSE; 2795 } 2796 if (reply == NULL) { 2797 return FALSE; 2798 } 2799 2800 dbus_message_unref (reply); 2801 return TRUE; 2802 } 2803 2804 /** 2805 * libhal_device_query_capability: 2806 * @ctx: the context for the connection to hald 2807 * @udi: the Unique Device Id 2808 * @capability: the capability name 2809 * @error: pointer to an initialized dbus error object for returning errors or NULL 2810 * 2811 * Check if a device has a capability. The result is undefined if the 2812 * device doesn't exist. 2813 * 2814 * Returns: TRUE if the device has the capability, otherwise FALSE 2815 */ 2816 dbus_bool_t 2817 libhal_device_query_capability (LibHalContext *ctx, const char *udi, const char *capability, DBusError *error) 2818 { 2819 char **caps; 2820 unsigned int i; 2821 dbus_bool_t ret; 2822 2823 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2824 2825 ret = FALSE; 2826 2827 caps = libhal_device_get_property_strlist (ctx, udi, "info.capabilities", error); 2828 if (caps != NULL) { 2829 for (i = 0; caps[i] != NULL; i++) { 2830 if (strcmp (caps[i], capability) == 0) { 2831 ret = TRUE; 2832 break; 2833 } 2834 } 2835 libhal_free_string_array (caps); 2836 } 2837 2838 return ret; 2839 } 2840 2841 /** 2842 * libhal_find_device_by_capability: 2843 * @ctx: the context for the connection to hald 2844 * @capability: the capability name 2845 * @num_devices: pointer to store number of devices 2846 * @error: pointer to an initialized dbus error object for returning errors or NULL 2847 * 2848 * Find devices with a given capability. 2849 * 2850 * Returns: UDI of devices; free with libhal_free_string_array() 2851 */ 2852 char ** 2853 libhal_find_device_by_capability (LibHalContext *ctx, 2854 const char *capability, int *num_devices, DBusError *error) 2855 { 2856 DBusMessage *message; 2857 DBusMessage *reply; 2858 DBusMessageIter iter, iter_array, reply_iter; 2859 char **hal_device_names; 2860 DBusError _error; 2861 2862 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 2863 2864 message = dbus_message_new_method_call ("org.freedesktop.Hal", 2865 "/org/freedesktop/Hal/Manager", 2866 "org.freedesktop.Hal.Manager", 2867 "FindDeviceByCapability"); 2868 if (message == NULL) { 2869 fprintf (stderr, 2870 "%s %d : Couldn't allocate D-BUS message\n", 2871 __FILE__, __LINE__); 2872 return NULL; 2873 } 2874 2875 dbus_message_iter_init_append (message, &iter); 2876 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability); 2877 2878 dbus_error_init (&_error); 2879 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 2880 message, -1, 2881 &_error); 2882 2883 dbus_message_unref (message); 2884 2885 dbus_move_error (&_error, error); 2886 if (error != NULL && dbus_error_is_set (error)) { 2887 return NULL; 2888 } 2889 if (reply == NULL) { 2890 return NULL; 2891 } 2892 /* now analyse reply */ 2893 dbus_message_iter_init (reply, &reply_iter); 2894 2895 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { 2896 fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); 2897 return NULL; 2898 } 2899 2900 dbus_message_iter_recurse (&reply_iter, &iter_array); 2901 2902 hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); 2903 2904 dbus_message_unref (reply); 2905 return hal_device_names; 2906 } 2907 2908 /** 2909 * libhal_device_property_watch_all: 2910 * @ctx: the context for the connection to hald 2911 * @error: pointer to an initialized dbus error object for returning errors or NULL 2912 * 2913 * Watch all devices, ie. the device_property_changed callback is 2914 * invoked when the properties on any device changes. 2915 * 2916 * Returns: TRUE only if the operation succeeded 2917 */ 2918 dbus_bool_t 2919 libhal_device_property_watch_all (LibHalContext *ctx, DBusError *error) 2920 { 2921 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2922 2923 dbus_bus_add_match (ctx->connection, 2924 "type='signal'," 2925 "interface='org.freedesktop.Hal.Device'," 2926 "sender='org.freedesktop.Hal'", error); 2927 if (error != NULL && dbus_error_is_set (error)) { 2928 return FALSE; 2929 } 2930 return TRUE; 2931 } 2932 2933 2934 /** 2935 * libhal_device_add_property_watch: 2936 * @ctx: the context for the connection to hald 2937 * @udi: the Unique Device Id 2938 * @error: pointer to an initialized dbus error object for returning errors or NULL 2939 * 2940 * Add a watch on a device, so the device_property_changed callback is 2941 * invoked when the properties on the given device changes. 2942 * 2943 * The application itself is responsible for deleting the watch, using 2944 * libhal_device_remove_property_watch, if the device is removed. 2945 * 2946 * Returns: TRUE only if the operation succeeded 2947 */ 2948 dbus_bool_t 2949 libhal_device_add_property_watch (LibHalContext *ctx, const char *udi, DBusError *error) 2950 { 2951 char buf[512]; 2952 2953 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2954 2955 snprintf (buf, 512, 2956 "type='signal'," 2957 "interface='org.freedesktop.Hal.Device'," 2958 "sender='org.freedesktop.Hal'," "path=%s", udi); 2959 2960 dbus_bus_add_match (ctx->connection, buf, error); 2961 if (error != NULL && dbus_error_is_set (error)) { 2962 return FALSE; 2963 } 2964 return TRUE; 2965 } 2966 2967 2968 /** 2969 * libhal_device_remove_property_watch: 2970 * @ctx: the context for the connection to hald 2971 * @udi: the Unique Device Id 2972 * @error: pointer to an initialized dbus error object for returning errors or NULL 2973 * 2974 * Remove a watch on a device. 2975 * 2976 * Returns: TRUE only if the operation succeeded 2977 */ 2978 dbus_bool_t 2979 libhal_device_remove_property_watch (LibHalContext *ctx, const char *udi, DBusError *error) 2980 { 2981 char buf[512]; 2982 2983 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 2984 2985 snprintf (buf, 512, 2986 "type='signal'," 2987 "interface='org.freedesktop.Hal.Device'," 2988 "sender='org.freedesktop.Hal'," "path=%s", udi); 2989 2990 dbus_bus_remove_match (ctx->connection, buf, error); 2991 if (error != NULL && dbus_error_is_set (error)) { 2992 return FALSE; 2993 } 2994 return TRUE; 2995 } 2996 2997 2998 /** 2999 * libhal_ctx_new: 3000 * 3001 * Create a new LibHalContext 3002 * 3003 * Returns: a new uninitialized LibHalContext object 3004 */ 3005 LibHalContext * 3006 libhal_ctx_new (void) 3007 { 3008 LibHalContext *ctx; 3009 3010 if (!libhal_already_initialized_once) { 3011 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 3012 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 3013 3014 libhal_already_initialized_once = TRUE; 3015 } 3016 3017 ctx = calloc (1, sizeof (LibHalContext)); 3018 if (ctx == NULL) { 3019 fprintf (stderr, 3020 "%s %d : Failed to allocate %lu bytes\n", 3021 __FILE__, __LINE__, (unsigned long) sizeof (LibHalContext)); 3022 return NULL; 3023 } 3024 3025 ctx->is_initialized = FALSE; 3026 ctx->is_shutdown = FALSE; 3027 ctx->connection = NULL; 3028 ctx->is_direct = FALSE; 3029 3030 return ctx; 3031 } 3032 3033 /** 3034 * libhal_ctx_set_cache: 3035 * @ctx: context to enable/disable cache for 3036 * @use_cache: whether or not to use cache 3037 * 3038 * Enable or disable caching. Note: Caching is not actually 3039 * implemented yet. 3040 * 3041 * Returns: TRUE if cache was successfully enabled/disabled, FALSE otherwise 3042 */ 3043 dbus_bool_t 3044 libhal_ctx_set_cache (LibHalContext *ctx, dbus_bool_t use_cache) 3045 { 3046 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3047 3048 ctx->cache_enabled = use_cache; 3049 return TRUE; 3050 } 3051 3052 /** 3053 * libhal_ctx_set_dbus_connection: 3054 * @ctx: context to set connection for 3055 * @conn: DBus connection to use 3056 * 3057 * Set DBus connection to use to talk to hald. 3058 * 3059 * Returns: TRUE if connection was successfully set, FALSE otherwise 3060 */ 3061 dbus_bool_t 3062 libhal_ctx_set_dbus_connection (LibHalContext *ctx, DBusConnection *conn) 3063 { 3064 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3065 3066 if (conn == NULL) 3067 return FALSE; 3068 3069 ctx->connection = conn; 3070 return TRUE; 3071 } 3072 3073 /** 3074 * libhal_ctx_get_dbus_connection: 3075 * @ctx: context to get connection for 3076 * 3077 * Get DBus connection used for talking to hald. 3078 * 3079 * Returns: DBus connection to use or NULL 3080 */ 3081 DBusConnection * 3082 libhal_ctx_get_dbus_connection (LibHalContext *ctx) 3083 { 3084 LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); 3085 3086 return ctx->connection; 3087 } 3088 3089 3090 /** 3091 * libhal_ctx_init: 3092 * @ctx: Context for connection to hald (D-BUS connection should be set with libhal_ctx_set_dbus_connection) 3093 * @error: pointer to an initialized dbus error object for returning errors or NULL 3094 * 3095 * Initialize the connection to hald. 3096 * 3097 * Returns: TRUE if initialization succeeds, FALSE otherwise 3098 */ 3099 dbus_bool_t 3100 libhal_ctx_init (LibHalContext *ctx, DBusError *error) 3101 { 3102 DBusError _error; 3103 dbus_bool_t hald_exists; 3104 3105 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3106 3107 if (ctx->connection == NULL) 3108 return FALSE; 3109 3110 dbus_error_init (&_error); 3111 hald_exists = dbus_bus_name_has_owner (ctx->connection, "org.freedesktop.Hal", &_error); 3112 dbus_move_error (&_error, error); 3113 if (error != NULL && dbus_error_is_set (error)) { 3114 return FALSE; 3115 } 3116 3117 if (!hald_exists) { 3118 return FALSE; 3119 } 3120 3121 3122 if (!dbus_connection_add_filter (ctx->connection, filter_func, ctx, NULL)) { 3123 return FALSE; 3124 } 3125 3126 dbus_bus_add_match (ctx->connection, 3127 "type='signal'," 3128 "interface='org.freedesktop.Hal.Manager'," 3129 "sender='org.freedesktop.Hal'," 3130 "path='/org/freedesktop/Hal/Manager'", &_error); 3131 dbus_move_error (&_error, error); 3132 if (error != NULL && dbus_error_is_set (error)) { 3133 return FALSE; 3134 } 3135 ctx->is_initialized = TRUE; 3136 ctx->is_direct = FALSE; 3137 3138 return TRUE; 3139 } 3140 3141 /** 3142 * libhal_ctx_init_direct: 3143 * @error: pointer to an initialized dbus error object for returning errors or NULL 3144 * 3145 * Create an already initialized connection to hald. This function should only be used by HAL helpers. 3146 * 3147 * Returns: A pointer to an already initialized LibHalContext 3148 */ 3149 LibHalContext * 3150 libhal_ctx_init_direct (DBusError *error) 3151 { 3152 char *hald_addr; 3153 LibHalContext *ctx; 3154 DBusError _error; 3155 3156 ctx = libhal_ctx_new (); 3157 if (ctx == NULL) 3158 goto out; 3159 3160 if (((hald_addr = getenv ("HALD_DIRECT_ADDR"))) == NULL) { 3161 libhal_ctx_free (ctx); 3162 ctx = NULL; 3163 goto out; 3164 } 3165 3166 dbus_error_init (&_error); 3167 ctx->connection = dbus_connection_open (hald_addr, &_error); 3168 dbus_move_error (&_error, error); 3169 if (error != NULL && dbus_error_is_set (error)) { 3170 libhal_ctx_free (ctx); 3171 ctx = NULL; 3172 goto out; 3173 } 3174 3175 ctx->is_initialized = TRUE; 3176 ctx->is_direct = TRUE; 3177 3178 out: 3179 return ctx; 3180 } 3181 3182 /** 3183 * libhal_ctx_shutdown: 3184 * @ctx: the context for the connection to hald 3185 * @error: pointer to an initialized dbus error object for returning errors or NULL 3186 * 3187 * Shut down a connection to hald. 3188 * 3189 * Returns: TRUE if connection successfully shut down, FALSE otherwise 3190 */ 3191 dbus_bool_t 3192 libhal_ctx_shutdown (LibHalContext *ctx, DBusError *error) 3193 { 3194 DBusError myerror; 3195 3196 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3197 3198 if (ctx->is_direct) { 3199 /* for some reason dbus_connection_set_exit_on_disconnect doesn't work yet so don't unref */ 3200 /*dbus_connection_unref (ctx->connection);*/ 3201 } else { 3202 dbus_error_init (&myerror); 3203 dbus_bus_remove_match (ctx->connection, 3204 "type='signal'," 3205 "interface='org.freedesktop.Hal.Manager'," 3206 "sender='org.freedesktop.Hal'," 3207 "path='/org/freedesktop/Hal/Manager'", &myerror); 3208 dbus_move_error (&myerror, error); 3209 if (error != NULL && dbus_error_is_set (error)) { 3210 fprintf (stderr, "%s %d : Error unsubscribing to signals, error=%s\n", 3211 __FILE__, __LINE__, error->message); 3212 /** @todo clean up */ 3213 } 3214 3215 /* TODO: remove other matches */ 3216 3217 dbus_connection_remove_filter (ctx->connection, filter_func, ctx); 3218 } 3219 3220 ctx->is_initialized = FALSE; 3221 3222 return TRUE; 3223 } 3224 3225 /** 3226 * libhal_ctx_free: 3227 * @ctx: pointer to a LibHalContext 3228 * 3229 * Free a LibHalContext resource. 3230 * 3231 * Returns: TRUE 3232 */ 3233 dbus_bool_t 3234 libhal_ctx_free (LibHalContext *ctx) 3235 { 3236 free (ctx); 3237 return TRUE; 3238 } 3239 3240 /** 3241 * libhal_ctx_set_device_added: 3242 * @ctx: the context for the connection to hald 3243 * @callback: the function to call when a device is added 3244 * 3245 * Set the callback for when a device is added 3246 * 3247 * Returns: TRUE if callback was successfully set, FALSE otherwise 3248 */ 3249 dbus_bool_t 3250 libhal_ctx_set_device_added (LibHalContext *ctx, LibHalDeviceAdded callback) 3251 { 3252 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3253 3254 ctx->device_added = callback; 3255 return TRUE; 3256 } 3257 3258 /** 3259 * libhal_ctx_set_device_removed: 3260 * @ctx: the context for the connection to hald 3261 * @callback: the function to call when a device is removed 3262 * 3263 * Set the callback for when a device is removed. 3264 * 3265 * Returns: TRUE if callback was successfully set, FALSE otherwise 3266 */ 3267 dbus_bool_t 3268 libhal_ctx_set_device_removed (LibHalContext *ctx, LibHalDeviceRemoved callback) 3269 { 3270 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3271 3272 ctx->device_removed = callback; 3273 return TRUE; 3274 } 3275 3276 /** 3277 * libhal_ctx_set_device_new_capability: 3278 * @ctx: the context for the connection to hald 3279 * @callback: the function to call when a device gains a new capability 3280 * 3281 * Set the callback for when a device gains a new capability. 3282 * 3283 * Returns: TRUE if callback was successfully set, FALSE otherwise 3284 */ 3285 dbus_bool_t 3286 libhal_ctx_set_device_new_capability (LibHalContext *ctx, LibHalDeviceNewCapability callback) 3287 { 3288 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3289 3290 ctx->device_new_capability = callback; 3291 return TRUE; 3292 } 3293 3294 /** 3295 * libhal_ctx_set_device_lost_capability: 3296 * @ctx: the context for the connection to hald 3297 * @callback: the function to call when a device loses a capability 3298 * 3299 * Set the callback for when a device loses a capability 3300 * 3301 * Returns: TRUE if callback was successfully set, FALSE otherwise 3302 */ 3303 dbus_bool_t 3304 libhal_ctx_set_device_lost_capability (LibHalContext *ctx, LibHalDeviceLostCapability callback) 3305 { 3306 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3307 3308 ctx->device_lost_capability = callback; 3309 return TRUE; 3310 } 3311 3312 /** 3313 * libhal_ctx_set_device_property_modified: 3314 * @ctx: the context for the connection to hald 3315 * @callback: the function to call when a property is modified on a device 3316 * 3317 * Set the callback for when a property is modified on a device. 3318 * 3319 * Returns: TRUE if callback was successfully set, FALSE otherwise 3320 */ 3321 dbus_bool_t 3322 libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibHalDevicePropertyModified callback) 3323 { 3324 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3325 3326 ctx->device_property_modified = callback; 3327 return TRUE; 3328 } 3329 3330 /** 3331 * libhal_ctx_set_device_condition: 3332 * @ctx: the context for the connection to hald 3333 * @callback: the function to call when a device emits a condition 3334 * 3335 * Set the callback for when a device emits a condition 3336 * 3337 * Returns: TRUE if callback was successfully set, FALSE otherwise 3338 */ 3339 dbus_bool_t 3340 libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback) 3341 { 3342 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3343 3344 ctx->device_condition = callback; 3345 return TRUE; 3346 } 3347 3348 /** 3349 * libhal_string_array_length: 3350 * @str_array: array of strings to consider 3351 * 3352 * Get the length of an array of strings. 3353 * 3354 * Returns: Number of strings in array 3355 */ 3356 unsigned int 3357 libhal_string_array_length (char **str_array) 3358 { 3359 unsigned int i; 3360 3361 if (str_array == NULL) 3362 return 0; 3363 3364 for (i = 0; str_array[i] != NULL; i++) 3365 ; 3366 3367 return i; 3368 } 3369 3370 3371 /** 3372 * libhal_device_rescan: 3373 * @ctx: the context for the connection to hald 3374 * @udi: the Unique id of device 3375 * @error: pointer to an initialized dbus error object for returning errors or NULL 3376 * 3377 * TODO document me. 3378 * 3379 * Returns: Whether the operation succeeded 3380 */ 3381 dbus_bool_t 3382 libhal_device_rescan (LibHalContext *ctx, const char *udi, DBusError *error) 3383 { 3384 DBusMessage *message; 3385 DBusMessageIter reply_iter; 3386 DBusMessage *reply; 3387 dbus_bool_t result; 3388 3389 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3390 3391 message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, 3392 "org.freedesktop.Hal.Device", 3393 "Rescan"); 3394 3395 if (message == NULL) { 3396 fprintf (stderr, 3397 "%s %d : Couldn't allocate D-BUS message\n", 3398 __FILE__, __LINE__); 3399 return FALSE; 3400 } 3401 3402 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 3403 message, -1, 3404 error); 3405 3406 dbus_message_unref (message); 3407 3408 if (error != NULL && dbus_error_is_set (error)) { 3409 return FALSE; 3410 } 3411 if (reply == NULL) 3412 return FALSE; 3413 3414 dbus_message_iter_init (reply, &reply_iter); 3415 if (dbus_message_iter_get_arg_type (&reply_iter) != 3416 DBUS_TYPE_BOOLEAN) { 3417 dbus_message_unref (reply); 3418 return FALSE; 3419 } 3420 dbus_message_iter_get_basic (&reply_iter, &result); 3421 3422 dbus_message_unref (reply); 3423 3424 return result; 3425 } 3426 3427 /** 3428 * libhal_device_reprobe: 3429 * @ctx: the context for the connection to hald 3430 * @udi: the Unique id of device 3431 * @error: pointer to an initialized dbus error object for returning errors or NULL 3432 * 3433 * TODO document me. 3434 * 3435 * Returns: Whether the operation succeeded 3436 */ 3437 dbus_bool_t 3438 libhal_device_reprobe (LibHalContext *ctx, const char *udi, DBusError *error) 3439 { 3440 DBusMessage *message; 3441 DBusMessageIter reply_iter; 3442 DBusMessage *reply; 3443 dbus_bool_t result; 3444 3445 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3446 3447 message = dbus_message_new_method_call ("org.freedesktop.Hal", 3448 udi, 3449 "org.freedesktop.Hal.Device", 3450 "Reprobe"); 3451 3452 if (message == NULL) { 3453 fprintf (stderr, 3454 "%s %d : Couldn't allocate D-BUS message\n", 3455 __FILE__, __LINE__); 3456 return FALSE; 3457 } 3458 3459 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 3460 message, -1, 3461 error); 3462 3463 dbus_message_unref (message); 3464 3465 if (error != NULL && dbus_error_is_set (error)) { 3466 return FALSE; 3467 } 3468 if (reply == NULL) 3469 return FALSE; 3470 3471 dbus_message_iter_init (reply, &reply_iter); 3472 if (dbus_message_iter_get_arg_type (&reply_iter) != 3473 DBUS_TYPE_BOOLEAN) { 3474 dbus_message_unref (reply); 3475 return FALSE; 3476 } 3477 dbus_message_iter_get_basic (&reply_iter, &result); 3478 3479 dbus_message_unref (reply); 3480 3481 return result; 3482 } 3483 3484 /** 3485 * libhal_device_emit_condition: 3486 * @ctx: the context for the connection to hald 3487 * @udi: the Unique Device Id 3488 * @condition_name: user-readable name of condition 3489 * @condition_details: user-readable details of condition 3490 * @error: pointer to an initialized dbus error object for returning errors or NULL 3491 * 3492 * Emit a condition from a device. Can only be used from hald helpers. 3493 * 3494 * Returns: TRUE if condition successfully emitted, 3495 * FALSE otherwise 3496 */ 3497 dbus_bool_t libhal_device_emit_condition (LibHalContext *ctx, 3498 const char *udi, 3499 const char *condition_name, 3500 const char *condition_details, 3501 DBusError *error) 3502 { 3503 DBusMessage *message; 3504 DBusMessageIter iter; 3505 DBusMessageIter reply_iter; 3506 DBusMessage *reply; 3507 dbus_bool_t result; 3508 3509 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3510 3511 message = dbus_message_new_method_call ("org.freedesktop.Hal", 3512 udi, 3513 "org.freedesktop.Hal.Device", 3514 "EmitCondition"); 3515 3516 if (message == NULL) { 3517 fprintf (stderr, 3518 "%s %d : Couldn't allocate D-BUS message\n", 3519 __FILE__, __LINE__); 3520 return FALSE; 3521 } 3522 3523 dbus_message_iter_init_append (message, &iter); 3524 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_name); 3525 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_details); 3526 3527 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 3528 message, -1, 3529 error); 3530 3531 dbus_message_unref (message); 3532 3533 if (error != NULL && dbus_error_is_set (error)) { 3534 fprintf (stderr, 3535 "%s %d : Failure sending D-BUS message: %s: %s\n", 3536 __FILE__, __LINE__, error->name, error->message); 3537 return FALSE; 3538 } 3539 3540 if (reply == NULL) { 3541 fprintf (stderr, 3542 "%s %d : Got no reply\n", 3543 __FILE__, __LINE__); 3544 return FALSE; 3545 } 3546 3547 dbus_message_iter_init (reply, &reply_iter); 3548 if (dbus_message_iter_get_arg_type (&reply_iter) != 3549 DBUS_TYPE_BOOLEAN) { 3550 dbus_message_unref (reply); 3551 fprintf (stderr, 3552 "%s %d : Malformed reply\n", 3553 __FILE__, __LINE__); 3554 return FALSE; 3555 } 3556 dbus_message_iter_get_basic (&reply_iter, &result); 3557 3558 dbus_message_unref (reply); 3559 3560 return result; 3561 } 3562 3563 /** 3564 * libhal_device_addon_is_ready: 3565 * @ctx: the context for the connection to hald 3566 * @udi: the Unique Device Id 3567 * @error: pointer to an initialized dbus error object for returning errors or NULL 3568 * 3569 * HAL addon's must call this method when they are done initializing the device object. The HAL 3570 * daemon will wait for all addon's to call this. 3571 * 3572 * Can only be used from hald helpers. 3573 * 3574 * Returns: TRUE if the HAL daemon received the message, FALSE otherwise 3575 */ 3576 dbus_bool_t 3577 libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error) 3578 { 3579 DBusMessage *message; 3580 DBusMessageIter iter; 3581 DBusMessageIter reply_iter; 3582 DBusMessage *reply; 3583 dbus_bool_t result; 3584 3585 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3586 3587 message = dbus_message_new_method_call ("org.freedesktop.Hal", 3588 udi, 3589 "org.freedesktop.Hal.Device", 3590 "AddonIsReady"); 3591 3592 if (message == NULL) { 3593 fprintf (stderr, 3594 "%s %d : Couldn't allocate D-BUS message\n", 3595 __FILE__, __LINE__); 3596 return FALSE; 3597 } 3598 3599 dbus_message_iter_init_append (message, &iter); 3600 3601 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 3602 message, -1, 3603 error); 3604 3605 dbus_message_unref (message); 3606 3607 if (error != NULL && dbus_error_is_set (error)) { 3608 return FALSE; 3609 } 3610 if (reply == NULL) 3611 return FALSE; 3612 3613 dbus_message_iter_init (reply, &reply_iter); 3614 if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { 3615 dbus_message_unref (reply); 3616 return FALSE; 3617 } 3618 dbus_message_iter_get_basic (&reply_iter, &result); 3619 3620 dbus_message_unref (reply); 3621 return result; 3622 } 3623 3624 /** 3625 * libhal_device_claim_interface: 3626 * @ctx: the context for the connection to hald 3627 * @udi: the Unique Device Id 3628 * @interface_name: Name of interface to claim, e.g. org.freedesktop.Hal.Device.FoobarKindOfThing 3629 * @introspection_xml: Introspection XML containing what would be inside the interface XML tag 3630 * @error: pointer to an initialized dbus error object for returning errors or NULL 3631 * 3632 * Claim an interface for a device. All messages to this interface 3633 * will be forwarded to the helper. Can only be used from hald 3634 * helpers. 3635 * 3636 * Returns: TRUE if interface was claimed, FALSE otherwise 3637 */ 3638 dbus_bool_t 3639 libhal_device_claim_interface (LibHalContext *ctx, 3640 const char *udi, 3641 const char *interface_name, 3642 const char *introspection_xml, 3643 DBusError *error) 3644 { 3645 DBusMessage *message; 3646 DBusMessageIter iter; 3647 DBusMessageIter reply_iter; 3648 DBusMessage *reply; 3649 dbus_bool_t result; 3650 3651 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 3652 3653 message = dbus_message_new_method_call ("org.freedesktop.Hal", 3654 udi, 3655 "org.freedesktop.Hal.Device", 3656 "ClaimInterface"); 3657 3658 if (message == NULL) { 3659 fprintf (stderr, 3660 "%s %d : Couldn't allocate D-BUS message\n", 3661 __FILE__, __LINE__); 3662 return FALSE; 3663 } 3664 3665 dbus_message_iter_init_append (message, &iter); 3666 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); 3667 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &introspection_xml); 3668 3669 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 3670 message, -1, 3671 error); 3672 3673 dbus_message_unref (message); 3674 3675 if (error != NULL && dbus_error_is_set (error)) { 3676 return FALSE; 3677 } 3678 if (reply == NULL) 3679 return FALSE; 3680 3681 dbus_message_iter_init (reply, &reply_iter); 3682 if (dbus_message_iter_get_arg_type (&reply_iter) != 3683 DBUS_TYPE_BOOLEAN) { 3684 dbus_message_unref (reply); 3685 return FALSE; 3686 } 3687 dbus_message_iter_get_basic (&reply_iter, &result); 3688 3689 dbus_message_unref (reply); 3690 3691 return result; 3692 } 3693 3694 3695 3696 struct LibHalChangeSetElement_s; 3697 3698 typedef struct LibHalChangeSetElement_s LibHalChangeSetElement; 3699 3700 struct LibHalChangeSetElement_s { 3701 char *key; 3702 int change_type; 3703 union { 3704 char *val_str; 3705 dbus_int32_t val_int; 3706 dbus_uint64_t val_uint64; 3707 double val_double; 3708 dbus_bool_t val_bool; 3709 char **val_strlist; 3710 } value; 3711 LibHalChangeSetElement *next; 3712 LibHalChangeSetElement *prev; 3713 }; 3714 3715 struct LibHalChangeSet_s { 3716 char *udi; 3717 LibHalChangeSetElement *head; 3718 LibHalChangeSetElement *tail; 3719 }; 3720 3721 /** 3722 * libhal_device_new_changeset: 3723 * @udi: unique device identifier 3724 * 3725 * Request a new changeset object. Used for changing multiple properties at once. Useful when 3726 * performance is critical and also for atomically updating several properties. 3727 * 3728 * Returns: A new changeset object or NULL on error 3729 */ 3730 LibHalChangeSet * 3731 libhal_device_new_changeset (const char *udi) 3732 { 3733 LibHalChangeSet *changeset; 3734 3735 changeset = calloc (1, sizeof (LibHalChangeSet)); 3736 if (changeset == NULL) 3737 goto out; 3738 3739 changeset->udi = strdup (udi); 3740 if (changeset->udi == NULL) { 3741 free (changeset); 3742 changeset = NULL; 3743 goto out; 3744 } 3745 3746 changeset->head = NULL; 3747 changeset->tail = NULL; 3748 3749 out: 3750 return changeset; 3751 } 3752 3753 static void 3754 libhal_changeset_append (LibHalChangeSet *changeset, LibHalChangeSetElement *elem) 3755 { 3756 if (changeset->head == NULL) { 3757 changeset->head = elem; 3758 changeset->tail = elem; 3759 elem->next = NULL; 3760 elem->prev = NULL; 3761 } else { 3762 elem->prev = changeset->tail; 3763 elem->next = NULL; 3764 elem->prev->next = elem; 3765 changeset->tail = elem; 3766 } 3767 } 3768 3769 3770 /** 3771 * libhal_changeset_set_property_string: 3772 * @changeset: the changeset 3773 * @key: key of property 3774 * @value: the value to set 3775 * 3776 * Set a property. 3777 * 3778 * Returns: FALSE on OOM 3779 */ 3780 dbus_bool_t 3781 libhal_changeset_set_property_string (LibHalChangeSet *changeset, const char *key, const char *value) 3782 { 3783 LibHalChangeSetElement *elem; 3784 3785 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3786 if (elem == NULL) 3787 goto out; 3788 elem->key = strdup (key); 3789 if (elem->key == NULL) { 3790 free (elem); 3791 elem = NULL; 3792 goto out; 3793 } 3794 3795 elem->change_type = LIBHAL_PROPERTY_TYPE_STRING; 3796 elem->value.val_str = strdup (value); 3797 if (elem->value.val_str == NULL) { 3798 free (elem->key); 3799 free (elem); 3800 elem = NULL; 3801 goto out; 3802 } 3803 3804 libhal_changeset_append (changeset, elem); 3805 out: 3806 return elem != NULL; 3807 } 3808 3809 /** 3810 * libhal_changeset_set_property_int: 3811 * @changeset: the changeset 3812 * @key: key of property 3813 * @value: the value to set 3814 * 3815 * Set a property. 3816 * 3817 * Returns: FALSE on OOM 3818 */ 3819 dbus_bool_t 3820 libhal_changeset_set_property_int (LibHalChangeSet *changeset, const char *key, dbus_int32_t value) 3821 { 3822 LibHalChangeSetElement *elem; 3823 3824 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3825 if (elem == NULL) 3826 goto out; 3827 elem->key = strdup (key); 3828 if (elem->key == NULL) { 3829 free (elem); 3830 elem = NULL; 3831 goto out; 3832 } 3833 3834 elem->change_type = LIBHAL_PROPERTY_TYPE_INT32; 3835 elem->value.val_int = value; 3836 3837 libhal_changeset_append (changeset, elem); 3838 out: 3839 return elem != NULL; 3840 } 3841 3842 /** 3843 * libhal_changeset_set_property_uint64: 3844 * @changeset: the changeset 3845 * @key: key of property 3846 * @value: the value to set 3847 * 3848 * Set a property. 3849 * 3850 * Returns: FALSE on OOM 3851 */ 3852 dbus_bool_t 3853 libhal_changeset_set_property_uint64 (LibHalChangeSet *changeset, const char *key, dbus_uint64_t value) 3854 { 3855 LibHalChangeSetElement *elem; 3856 3857 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3858 if (elem == NULL) 3859 goto out; 3860 elem->key = strdup (key); 3861 if (elem->key == NULL) { 3862 free (elem); 3863 elem = NULL; 3864 goto out; 3865 } 3866 3867 elem->change_type = LIBHAL_PROPERTY_TYPE_UINT64; 3868 elem->value.val_uint64 = value; 3869 3870 libhal_changeset_append (changeset, elem); 3871 out: 3872 return elem != NULL; 3873 } 3874 3875 /** 3876 * libhal_changeset_set_property_double: 3877 * @changeset: the changeset 3878 * @key: key of property 3879 * @value: the value to set 3880 * 3881 * Set a property. 3882 * 3883 * Returns: FALSE on OOM 3884 */ 3885 dbus_bool_t 3886 libhal_changeset_set_property_double (LibHalChangeSet *changeset, const char *key, double value) 3887 { 3888 LibHalChangeSetElement *elem; 3889 3890 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3891 if (elem == NULL) 3892 goto out; 3893 elem->key = strdup (key); 3894 if (elem->key == NULL) { 3895 free (elem); 3896 elem = NULL; 3897 goto out; 3898 } 3899 3900 elem->change_type = LIBHAL_PROPERTY_TYPE_DOUBLE; 3901 elem->value.val_double = value; 3902 3903 libhal_changeset_append (changeset, elem); 3904 out: 3905 return elem != NULL; 3906 } 3907 3908 /** 3909 * libhal_changeset_set_property_bool: 3910 * @changeset: the changeset 3911 * @key: key of property 3912 * @value: the value to set 3913 * 3914 * Set a property. 3915 * 3916 * Returns: FALSE on OOM 3917 */ 3918 dbus_bool_t 3919 libhal_changeset_set_property_bool (LibHalChangeSet *changeset, const char *key, dbus_bool_t value) 3920 { 3921 LibHalChangeSetElement *elem; 3922 3923 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3924 if (elem == NULL) 3925 goto out; 3926 elem->key = strdup (key); 3927 if (elem->key == NULL) { 3928 free (elem); 3929 elem = NULL; 3930 goto out; 3931 } 3932 3933 elem->change_type = LIBHAL_PROPERTY_TYPE_BOOLEAN; 3934 elem->value.val_bool = value; 3935 3936 libhal_changeset_append (changeset, elem); 3937 out: 3938 return elem != NULL; 3939 } 3940 3941 /** 3942 * libhal_changeset_set_property_strlist: 3943 * @changeset: the changeset 3944 * @key: key of property 3945 * @value: the value to set - NULL terminated array of strings 3946 * 3947 * Set a property. 3948 * 3949 * Returns: FALSE on OOM 3950 */ 3951 dbus_bool_t 3952 libhal_changeset_set_property_strlist (LibHalChangeSet *changeset, const char *key, const char **value) 3953 { 3954 LibHalChangeSetElement *elem; 3955 char **value_copy; 3956 int len; 3957 int i, j; 3958 3959 elem = calloc (1, sizeof (LibHalChangeSetElement)); 3960 if (elem == NULL) 3961 goto out; 3962 elem->key = strdup (key); 3963 if (elem->key == NULL) { 3964 free (elem); 3965 elem = NULL; 3966 goto out; 3967 } 3968 3969 for (i = 0; value[i] != NULL; i++) 3970 ; 3971 len = i; 3972 3973 value_copy = calloc (len + 1, sizeof (char *)); 3974 if (value_copy == NULL) { 3975 free (elem->key); 3976 free (elem); 3977 elem = NULL; 3978 goto out; 3979 } 3980 3981 for (i = 0; i < len; i++) { 3982 value_copy[i] = strdup (value[i]); 3983 if (value_copy[i] == NULL) { 3984 for (j = 0; j < i; j++) { 3985 free (value_copy[j]); 3986 } 3987 free (value_copy); 3988 free (elem->key); 3989 free (elem); 3990 elem = NULL; 3991 goto out; 3992 } 3993 } 3994 value_copy[i] = NULL; 3995 3996 elem->change_type = LIBHAL_PROPERTY_TYPE_STRLIST; 3997 elem->value.val_strlist = value_copy; 3998 3999 libhal_changeset_append (changeset, elem); 4000 out: 4001 return elem != NULL; 4002 } 4003 4004 /** 4005 * libhal_device_commit_changeset: 4006 * @ctx: the context for the connection to hald 4007 * @changeset: the changeset to commit 4008 * @error: pointer to an initialized dbus error object for returning errors or NULL 4009 * 4010 * Commit a changeset to the daemon. 4011 * 4012 * Returns: True if the changeset was committed on the daemon side 4013 */ 4014 dbus_bool_t 4015 libhal_device_commit_changeset (LibHalContext *ctx, LibHalChangeSet *changeset, DBusError *error) 4016 { 4017 LibHalChangeSetElement *elem; 4018 DBusMessage *message; 4019 DBusMessage *reply; 4020 DBusError _error; 4021 DBusMessageIter iter; 4022 DBusMessageIter sub; 4023 DBusMessageIter sub2; 4024 DBusMessageIter sub3; 4025 DBusMessageIter sub4; 4026 int i; 4027 4028 LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); 4029 4030 if (changeset->head == NULL) { 4031 return TRUE; 4032 } 4033 4034 message = dbus_message_new_method_call ("org.freedesktop.Hal", changeset->udi, 4035 "org.freedesktop.Hal.Device", 4036 "SetMultipleProperties"); 4037 4038 if (message == NULL) { 4039 fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__); 4040 return FALSE; 4041 } 4042 4043 dbus_message_iter_init_append (message, &iter); 4044 4045 dbus_message_iter_open_container (&iter, 4046 DBUS_TYPE_ARRAY, 4047 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 4048 DBUS_TYPE_STRING_AS_STRING 4049 DBUS_TYPE_VARIANT_AS_STRING 4050 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, 4051 &sub); 4052 4053 for (elem = changeset->head; elem != NULL; elem = elem->next) { 4054 dbus_message_iter_open_container (&sub, 4055 DBUS_TYPE_DICT_ENTRY, 4056 NULL, 4057 &sub2); 4058 dbus_message_iter_append_basic (&sub2, DBUS_TYPE_STRING, &(elem->key)); 4059 4060 switch (elem->change_type) { 4061 case LIBHAL_PROPERTY_TYPE_STRING: 4062 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub3); 4063 dbus_message_iter_append_basic (&sub3, DBUS_TYPE_STRING, &(elem->value.val_str)); 4064 dbus_message_iter_close_container (&sub2, &sub3); 4065 break; 4066 case LIBHAL_PROPERTY_TYPE_STRLIST: 4067 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, 4068 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, &sub3); 4069 dbus_message_iter_open_container (&sub3, DBUS_TYPE_ARRAY, 4070 DBUS_TYPE_STRING_AS_STRING, &sub4); 4071 for (i = 0; elem->value.val_strlist[i] != NULL; i++) { 4072 dbus_message_iter_append_basic (&sub4, DBUS_TYPE_STRING, 4073 &(elem->value.val_strlist[i])); 4074 } 4075 dbus_message_iter_close_container (&sub3, &sub4); 4076 dbus_message_iter_close_container (&sub2, &sub3); 4077 break; 4078 case LIBHAL_PROPERTY_TYPE_INT32: 4079 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub3); 4080 dbus_message_iter_append_basic (&sub3, DBUS_TYPE_INT32, &(elem->value.val_int)); 4081 dbus_message_iter_close_container (&sub2, &sub3); 4082 break; 4083 case LIBHAL_PROPERTY_TYPE_UINT64: 4084 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT64_AS_STRING, &sub3); 4085 dbus_message_iter_append_basic (&sub3, DBUS_TYPE_UINT64, &(elem->value.val_uint64)); 4086 dbus_message_iter_close_container (&sub2, &sub3); 4087 break; 4088 case LIBHAL_PROPERTY_TYPE_DOUBLE: 4089 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub3); 4090 dbus_message_iter_append_basic (&sub3, DBUS_TYPE_DOUBLE, &(elem->value.val_double)); 4091 dbus_message_iter_close_container (&sub2, &sub3); 4092 break; 4093 case LIBHAL_PROPERTY_TYPE_BOOLEAN: 4094 dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING,&sub3); 4095 dbus_message_iter_append_basic (&sub3, DBUS_TYPE_BOOLEAN, &(elem->value.val_bool)); 4096 dbus_message_iter_close_container (&sub2, &sub3); 4097 break; 4098 default: 4099 fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type); 4100 break; 4101 } 4102 dbus_message_iter_close_container (&sub, &sub2); 4103 } 4104 4105 dbus_message_iter_close_container (&iter, &sub); 4106 4107 4108 dbus_error_init (&_error); 4109 reply = dbus_connection_send_with_reply_and_block (ctx->connection, 4110 message, -1, 4111 &_error); 4112 4113 dbus_message_unref (message); 4114 4115 dbus_move_error (&_error, error); 4116 if (error != NULL && dbus_error_is_set (error)) { 4117 fprintf (stderr, 4118 "%s %d : %s\n", 4119 __FILE__, __LINE__, error->message); 4120 4121 return FALSE; 4122 } 4123 if (reply == NULL) { 4124 return FALSE; 4125 } 4126 4127 dbus_message_unref (reply); 4128 return TRUE; 4129 } 4130 4131 /** 4132 * libhal_device_free_changeset: 4133 * @changeset: the changeset to free 4134 * 4135 * Free a changeset. 4136 */ 4137 void 4138 libhal_device_free_changeset (LibHalChangeSet *changeset) 4139 { 4140 LibHalChangeSetElement *elem; 4141 LibHalChangeSetElement *elem2; 4142 4143 for (elem = changeset->head; elem != NULL; elem = elem2) { 4144 elem2 = elem->next; 4145 4146 switch (elem->change_type) { 4147 case LIBHAL_PROPERTY_TYPE_STRING: 4148 free (elem->value.val_str); 4149 break; 4150 case LIBHAL_PROPERTY_TYPE_STRLIST: 4151 libhal_free_string_array (elem->value.val_strlist); 4152 break; 4153 /* explicit fallthrough */ 4154 case LIBHAL_PROPERTY_TYPE_INT32: 4155 case LIBHAL_PROPERTY_TYPE_UINT64: 4156 case LIBHAL_PROPERTY_TYPE_DOUBLE: 4157 case LIBHAL_PROPERTY_TYPE_BOOLEAN: 4158 break; 4159 default: 4160 fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type); 4161 break; 4162 } 4163 free (elem->key); 4164 free (elem); 4165 } 4166 4167 free (changeset->udi); 4168 free (changeset); 4169 } 4170