From 30eb2c6e3c314ab4205d8648805d62efd1a2356c Mon Sep 17 00:00:00 2001 From: aluzzardi Date: Tue, 19 Apr 2011 21:47:54 +0200 Subject: [PATCH] Embedded libhal --- deps/libhal-storage.c | 2137 +++++++++++++++++ deps/libhal-storage.h | 374 +++ deps/libhal.c | 5228 +++++++++++++++++++++++++++++++++++++++++ deps/libhal.h | 793 +++++++ deps/uthash.h | 605 +++++ 5 files changed, 9137 insertions(+) create mode 100644 deps/libhal-storage.c create mode 100644 deps/libhal-storage.h create mode 100644 deps/libhal.c create mode 100644 deps/libhal.h create mode 100644 deps/uthash.h diff --git a/deps/libhal-storage.c b/deps/libhal-storage.c new file mode 100644 index 0000000..4e95c49 --- /dev/null +++ b/deps/libhal-storage.c @@ -0,0 +1,2137 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * libhal-storage.c : HAL convenience library for storage devices and volumes + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Author: David Zeuthen + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include "libhal-storage.h" + + +#ifdef ENABLE_NLS +# include +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +/* Stubs that do something close enough. */ +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +typedef struct IconMappingEntry_s { + LibHalStoragePolicyIcon icon; + char *path; + struct IconMappingEntry_s *next; +} IconMappingEntry; + +struct LibHalStoragePolicy_s { + IconMappingEntry *icon_mappings; +}; + +LibHalStoragePolicy * +libhal_storage_policy_new (void) +{ + LibHalStoragePolicy *p; + + p = malloc (sizeof (LibHalStoragePolicy)); + if (p == NULL) + goto out; + + p->icon_mappings = NULL; +out: + return p; +} + +void +libhal_storage_policy_free (LibHalStoragePolicy *policy) +{ + IconMappingEntry *i; + IconMappingEntry *j; + + /* free all icon mappings */ + for (i = policy->icon_mappings; i != NULL; i = j) { + j = i->next; + free (i->path); + free (i); + } + + free (policy); +} + +void +libhal_storage_policy_set_icon_path (LibHalStoragePolicy *policy, LibHalStoragePolicyIcon icon, const char *path) +{ + IconMappingEntry *i; + + /* see if it already exist */ + for (i = policy->icon_mappings; i != NULL; i = i->next) { + if (i->icon == icon) { + free (i->path); + i->path = strdup (path); + goto out; + } + } + + i = malloc (sizeof (IconMappingEntry)); + if (i == NULL) + goto out; + i->icon = icon; + i->path = strdup (path); + i->next = policy->icon_mappings; + policy->icon_mappings = i; + +out: + return; +} + +void +libhal_storage_policy_set_icon_mapping (LibHalStoragePolicy *policy, LibHalStoragePolicyIconPair *pairs) +{ + LibHalStoragePolicyIconPair *i; + + for (i = pairs; i->icon != 0x00; i++) { + libhal_storage_policy_set_icon_path (policy, i->icon, i->icon_path); + } +} + +const char * +libhal_storage_policy_lookup_icon (LibHalStoragePolicy *policy, LibHalStoragePolicyIcon icon) +{ + IconMappingEntry *i; + const char *path; + + path = NULL; + for (i = policy->icon_mappings; i != NULL; i = i->next) { + if (i->icon == icon) { + path = i->path; + goto out; + } + } +out: + return path; +} + + +#define MAX_STRING_SZ 256 + +char * +libhal_volume_policy_compute_size_as_string (LibHalVolume *volume) +{ + dbus_uint64_t size; + char *result; + char* sizes_str[] = {"K", "M", "G", "T", NULL}; + dbus_uint64_t cur = 1000L; + dbus_uint64_t base = 10L; + dbus_uint64_t step = 10L*10L*10L; + int cur_str = 0; + char buf[MAX_STRING_SZ]; + + result = NULL; + + size = libhal_volume_get_size (volume); + + do { + if (sizes_str[cur_str+1] == NULL || size < cur*step) { + /* found the unit, display a comma number if result is a single digit */ + if (size < cur*base) { + snprintf (buf, MAX_STRING_SZ, "%.01f%s", + ((double)size)/((double)cur), sizes_str[cur_str]); + result = strdup (buf); + } else { + snprintf (buf, MAX_STRING_SZ, "%llu%s", (long long unsigned int) size / cur, sizes_str[cur_str]); + result = strdup (buf); + } + goto out; + } + + cur *= step; + cur_str++; + } while (1); + +out: + return result; +} + +/* volume may be NULL (e.g. if drive supports removable media) */ +char * +libhal_drive_policy_compute_display_name (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + char *name; + char *size_str; + char *vendormodel_str; + const char *model; + const char *vendor; + LibHalDriveType drive_type; + dbus_bool_t drive_is_hotpluggable; + dbus_bool_t drive_is_removable; + LibHalDriveCdromCaps drive_cdrom_caps; + char buf[MAX_STRING_SZ]; + + model = libhal_drive_get_model (drive); + vendor = libhal_drive_get_vendor (drive); + drive_type = libhal_drive_get_type (drive); + drive_is_hotpluggable = libhal_drive_is_hotpluggable (drive); + drive_is_removable = libhal_drive_uses_removable_media (drive); + drive_cdrom_caps = libhal_drive_get_cdrom_caps (drive); + + if (volume != NULL) + size_str = libhal_volume_policy_compute_size_as_string (volume); + else + size_str = NULL; + + if (vendor == NULL || strlen (vendor) == 0) { + if (model == NULL || strlen (model) == 0) + vendormodel_str = strdup (""); + else + vendormodel_str = strdup (model); + } else { + if (model == NULL || strlen (model) == 0) + vendormodel_str = strdup (vendor); + else { + snprintf (buf, MAX_STRING_SZ, "%s %s", vendor, model); + vendormodel_str = strdup (buf); + } + } + + if (drive_type==LIBHAL_DRIVE_TYPE_CDROM) { + + /* Optical drive handling */ + char *first; + char *second; + + + first = "CD-ROM"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_CDR) + first = "CD-R"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_CDRW) + first = "CD-RW"; + + second = ""; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDROM) + second = "/DVD-ROM"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR) + second = "/DVD+R"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW) + second = "/DVD+RW"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDR) + second = "/DVD-R"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDRW) + second = "/DVD-RW"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDRAM) + second = "/DVD-RAM"; + if ((drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDR) && + (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR)) { + if(drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL) + second = "/DVD±R DL"; + else + second = "/DVD±R"; + } + if ((drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDRW) && + (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW)) { + if(drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL || + drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRWDL) + second = "/DVD±RW DL"; + else + second = "/DVD±RW"; + } + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_BDROM) + second = "/BD-ROM"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_BDR) + second = "/BD-R"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_BDRE) + second = "/BD-RE"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_HDDVDROM) + second = "/HD DVD-ROM"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_HDDVDR) + second = "/HD DVD-R"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_HDDVDRW) + second = "/HD DVD-RW"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_MRW) + second = "/MRW"; + if (drive_cdrom_caps & LIBHAL_DRIVE_CDROM_CAPS_MRWW) + second = "/MRW-W"; + + if (drive_is_hotpluggable) { + snprintf (buf, MAX_STRING_SZ, _("External %s%s Drive"), first, second); + name = strdup (buf); + } else { + snprintf (buf, MAX_STRING_SZ, _("%s%s Drive"), first, second); + name = strdup (buf); + } + + } else if (drive_type==LIBHAL_DRIVE_TYPE_MO) { + + if (drive_is_hotpluggable) + name = strdup (_("External Magneto Optical Drive")); + else + name = strdup (_("Magneto Optical Drive")); + } else if (drive_type==LIBHAL_DRIVE_TYPE_FLOPPY) { + + /* Floppy Drive handling */ + + if (drive_is_hotpluggable) + name = strdup (_("External Floppy Drive")); + else + name = strdup (_("Floppy Drive")); + } else if (drive_type==LIBHAL_DRIVE_TYPE_DISK && !drive_is_removable) { + + /* Harddisks */ + + if (size_str != NULL) { + if (drive_is_hotpluggable) { + snprintf (buf, MAX_STRING_SZ, _("%s External Hard Drive"), size_str); + name = strdup (buf); + } else { + snprintf (buf, MAX_STRING_SZ, _("%s Hard Drive"), size_str); + name = strdup (buf); + } + } else { + if (drive_is_hotpluggable) + name = strdup (_("External Hard Drive")); + else + name = strdup (_("Hard Drive")); + } + } else { + + /* The rest - includes drives with removable Media */ + + if (strlen (vendormodel_str) > 0) + name = strdup (vendormodel_str); + else + name = strdup (_("Drive")); + } + + free (vendormodel_str); + free (size_str); + + return name; +} + +char * +libhal_volume_policy_compute_display_name (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + char *name; + char *size_str; + const char *volume_label; + LibHalDriveType drive_type; + dbus_bool_t drive_is_removable; + char buf[MAX_STRING_SZ]; + + name = NULL; + + volume_label = libhal_volume_get_label (volume); + drive_type = libhal_drive_get_type (drive); + drive_is_removable = libhal_drive_uses_removable_media (drive); + + size_str = libhal_volume_policy_compute_size_as_string (volume); + + /* If the volume label is available use that + * + * TODO: If label is a fully-qualified UNIX path don't use that + */ + if (volume_label != NULL) { + name = strdup (volume_label); + goto out; + } + + /* Handle media in optical drives */ + if (drive_type==LIBHAL_DRIVE_TYPE_CDROM) { + switch (libhal_volume_get_disc_type (volume)) { + + default: + /* explict fallthrough */ + case LIBHAL_VOLUME_DISC_TYPE_CDROM: + name = strdup (_("CD-ROM ")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_CDR: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank CD-R")); + else + name = strdup (_("CD-R")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_CDRW: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank CD-RW")); + else + name = strdup (_("CD-RW")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDROM: + name = strdup (_("DVD-ROM")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDRAM: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD-RAM")); + else + name = strdup (_("DVD-RAM")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDR: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD-R")); + else + name = strdup (_("DVD-R")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDR_DL: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD-R Dual-Layer")); + else + name = strdup (_("DVD-R Dual-Layer")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDRW: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD-RW")); + else + name = strdup (_("DVD-RW")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD+R")); + else + name = strdup (_("DVD+R")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD+RW")); + else + name = strdup (_("DVD+RW")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR_DL: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank DVD+R Dual-Layer")); + else + name = strdup (_("DVD+R Dual-Layer")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_BDROM: + name = strdup (_("BD-ROM")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_BDR: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank BD-R")); + else + name = strdup (_("BD-R")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_BDRE: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank BD-RE")); + else + name = strdup (_("BD-RE")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_HDDVDROM: + name = strdup (_("HD DVD-ROM")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_HDDVDR: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank HD DVD-R")); + else + name = strdup (_("HD DVD-R")); + break; + + case LIBHAL_VOLUME_DISC_TYPE_HDDVDRW: + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank HD DVD-RW")); + else + name = strdup (_("HD DVD-RW")); + break; + + } + + /* Special case for pure audio disc */ + if (libhal_volume_disc_has_audio (volume) && !libhal_volume_disc_has_data (volume)) { + free (name); + name = strdup (_("Audio CD")); + } + + goto out; + } else if (drive_type==LIBHAL_DRIVE_TYPE_MO) { + if (libhal_volume_get_disc_type (volume) == LIBHAL_VOLUME_DISC_TYPE_MO) { + if (libhal_volume_disc_is_blank (volume)) + name = strdup (_("Blank Magneto Optical")); + else + name = strdup (_("Magneto Optical")); + } + + goto out; + } + + /* Fallback: size of media */ + if (drive_is_removable) { + snprintf (buf, MAX_STRING_SZ, _("%s Removable Media"), size_str); + name = strdup (buf); + } else { + snprintf (buf, MAX_STRING_SZ, _("%s Media"), size_str); + name = strdup (buf); + } + + /* Fallback: Use drive name */ + /*name = libhal_drive_policy_compute_display_name (drive, volume);*/ + +out: + free (size_str); + return name; +} + +char * +libhal_drive_policy_compute_icon_name (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + const char *name; + LibHalDriveBus bus; + LibHalDriveType drive_type; + + bus = libhal_drive_get_bus (drive); + drive_type = libhal_drive_get_type (drive); + + /* by design, the enums are laid out so we can do easy computations */ + + switch (drive_type) { + case LIBHAL_DRIVE_TYPE_REMOVABLE_DISK: + case LIBHAL_DRIVE_TYPE_DISK: + case LIBHAL_DRIVE_TYPE_CDROM: + case LIBHAL_DRIVE_TYPE_MO: + case LIBHAL_DRIVE_TYPE_FLOPPY: + name = libhal_storage_policy_lookup_icon (policy, 0x10000 + drive_type*0x100 + bus); + break; + + default: + name = libhal_storage_policy_lookup_icon (policy, 0x10000 + drive_type*0x100); + } + + if (name != NULL) + return strdup (name); + else + return NULL; +} + +char * +libhal_volume_policy_compute_icon_name (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + const char *name; + LibHalDriveBus bus; + LibHalDriveType drive_type; + LibHalVolumeDiscType disc_type; + + /* by design, the enums are laid out so we can do easy computations */ + + if (libhal_volume_is_disc (volume)) { + disc_type = libhal_volume_get_disc_type (volume); + name = libhal_storage_policy_lookup_icon (policy, 0x30000 + disc_type); + goto out; + } + + if (drive == NULL) { + name = libhal_storage_policy_lookup_icon (policy, LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK); + goto out; + } + + bus = libhal_drive_get_bus (drive); + drive_type = libhal_drive_get_type (drive); + + switch (drive_type) { + case LIBHAL_DRIVE_TYPE_REMOVABLE_DISK: + case LIBHAL_DRIVE_TYPE_DISK: + case LIBHAL_DRIVE_TYPE_CDROM: + case LIBHAL_DRIVE_TYPE_MO: + case LIBHAL_DRIVE_TYPE_FLOPPY: + name = libhal_storage_policy_lookup_icon (policy, 0x20000 + drive_type*0x100 + bus); + break; + + default: + name = libhal_storage_policy_lookup_icon (policy, 0x20000 + drive_type*0x100); + } +out: + if (name != NULL) + return strdup (name); + else + return NULL; +} + +/** + * libhal_volume_policy_should_be_visible: + * @drive: Drive that the volume is stemming from + * @volume: Volume + * @policy: Policy object + * @target_mount_point: The mount point that the volume is expected to + * be mounted at if not already mounted. This may + * e.g. stem from /etc/fstab. If this is NULL the + * then mount point isn't taking into account when + * evaluating whether the volume should be visible + * Returns: Whether the volume should be shown in a desktop + * environment. + * Policy function to determine if a volume should be visible in a desktop + * environment. This is useful to hide certain system volumes as bootstrap + * partitions, the /usr partition, swap partitions and other volumes that + * a unprivileged desktop user shouldn't know even exists. + */ +dbus_bool_t +libhal_volume_policy_should_be_visible (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy, + const char *target_mount_point) +{ + unsigned int i; + dbus_bool_t is_visible; + const char *label; + const char *mount_point; + const char *fstype; + const char *fhs23_toplevel_mount_points[] = { + "/", + "/bin", + "/boot", + "/dev", + "/etc", + "/home", + "/lib", + "/lib64", + "/media", + "/mnt", + "/opt", + "/root", + "/sbin", + "/srv", + "/tmp", + "/usr", + "/var", + "/proc", + "/sbin", + NULL + }; + + is_visible = FALSE; + + /* skip if hal says it's not used as a filesystem */ + if (libhal_volume_get_fsusage (volume) != LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM) + goto out; + + label = libhal_volume_get_label (volume); + mount_point = libhal_volume_get_mount_point (volume); + fstype = libhal_volume_get_fstype (volume); + + /* use target mount point if we're not mounted yet */ + if (mount_point == NULL) + mount_point = target_mount_point; + + /* bail out if we don't know the filesystem */ + if (fstype == NULL) + goto out; + + /* blacklist fhs2.3 top level mount points */ + if (mount_point != NULL) { + for (i = 0; fhs23_toplevel_mount_points[i] != NULL; i++) { + if (strcmp (mount_point, fhs23_toplevel_mount_points[i]) == 0) + goto out; + } + } + + /* blacklist partitions with name 'bootstrap' of type HFS (Apple uses that) */ + if (label != NULL && strcmp (label, "bootstrap") == 0 && strcmp (fstype, "hfs") == 0) + goto out; + + /* only the real lucky mount points will make it this far :-) */ + is_visible = TRUE; + +out: + return is_visible; +} + +/*************************************************************************/ + +#define MOUNT_OPTIONS_SIZE 256 + +struct LibHalDrive_s { + char *udi; + + int device_major; + int device_minor; + char *device_file; + + LibHalDriveBus bus; + char *vendor; /* may be "", is never NULL */ + char *model; /* may be "", is never NULL */ + dbus_bool_t is_hotpluggable; + dbus_bool_t is_removable; + dbus_bool_t is_media_detected; + dbus_bool_t is_media_detection_automatic; + dbus_bool_t requires_eject; + + LibHalDriveType type; + char *type_textual; + + char *physical_device; /* UDI of physical device, e.g. the + * IDE, USB, IEEE1394 device */ + + char *dedicated_icon_drive; + char *dedicated_icon_volume; + + char *serial; + char *firmware_version; + LibHalDriveCdromCaps cdrom_caps; + + char *desired_mount_point; + char *mount_filesystem; + dbus_bool_t should_mount; + + dbus_bool_t no_partitions_hint; + + dbus_uint64_t drive_size; + dbus_uint64_t drive_media_size; + char *partition_scheme; + + LibHalContext *hal_ctx; + + char **capabilities; + + char mount_options[MOUNT_OPTIONS_SIZE]; +}; + +struct LibHalVolume_s { + char *udi; + + int device_major; + int device_minor; + char *device_file; + char *volume_label; /* may be NULL, is never "" */ + dbus_bool_t is_mounted; + dbus_bool_t is_mounted_read_only; /* TRUE iff is_mounted and r/o fs */ + char *mount_point; /* NULL iff !is_mounted */ + char *fstype; /* NULL iff !is_mounted or unknown */ + char *fsversion; + char *uuid; + char *storage_device; + + LibHalVolumeUsage fsusage; + + dbus_bool_t is_partition; + unsigned int partition_number; + char *partition_scheme; + char *partition_type; + char *partition_label; + char *partition_uuid; + char **partition_flags; + + int msdos_part_table_type; + dbus_uint64_t msdos_part_table_start; + dbus_uint64_t msdos_part_table_size; + + dbus_bool_t is_disc; + LibHalVolumeDiscType disc_type; + dbus_bool_t disc_has_audio; + dbus_bool_t disc_has_data; + dbus_bool_t disc_is_appendable; + dbus_bool_t disc_is_blank; + dbus_bool_t disc_is_rewritable; + + unsigned int block_size; + dbus_uint64_t num_blocks; + + char *desired_mount_point; + char *mount_filesystem; + dbus_bool_t should_mount; + + dbus_bool_t ignore_volume; + + char *crypto_backing_volume; + + char mount_options[MOUNT_OPTIONS_SIZE]; + + dbus_uint64_t volume_size; + dbus_uint64_t disc_capacity; + + dbus_uint64_t partition_start_offset; + dbus_uint64_t partition_media_size; +}; + +const char * +libhal_drive_get_dedicated_icon_drive (LibHalDrive *drive) +{ + return drive->dedicated_icon_drive; +} + +const char * +libhal_drive_get_dedicated_icon_volume (LibHalDrive *drive) +{ + return drive->dedicated_icon_volume; +} + +/** + * libhal_drive_free: + * @drive: Object to free + * + * Free all resources used by a LibHalDrive object. + */ +void +libhal_drive_free (LibHalDrive *drive) +{ + if (drive == NULL ) + return; + + free (drive->udi); + libhal_free_string (drive->device_file); + libhal_free_string (drive->vendor); + libhal_free_string (drive->model); + libhal_free_string (drive->type_textual); + libhal_free_string (drive->physical_device); + libhal_free_string (drive->dedicated_icon_drive); + libhal_free_string (drive->dedicated_icon_volume); + libhal_free_string (drive->serial); + libhal_free_string (drive->firmware_version); + libhal_free_string (drive->desired_mount_point); + libhal_free_string (drive->mount_filesystem); + libhal_free_string_array (drive->capabilities); + libhal_free_string (drive->partition_scheme); + + free (drive); +} + + +/** + * libhal_volume_free: + * @volume: Object to free + * + * Free all resources used by a LibHalVolume object. + */ +void +libhal_volume_free (LibHalVolume *volume) +{ + if (volume == NULL ) + return; + + free (volume->udi); + libhal_free_string (volume->device_file); + libhal_free_string (volume->volume_label); + libhal_free_string (volume->fstype); + libhal_free_string (volume->mount_point); + libhal_free_string (volume->fsversion); + libhal_free_string (volume->uuid); + libhal_free_string (volume->desired_mount_point); + libhal_free_string (volume->mount_filesystem); + libhal_free_string (volume->crypto_backing_volume); + libhal_free_string (volume->storage_device); + + libhal_free_string (volume->partition_scheme); + libhal_free_string (volume->partition_type); + libhal_free_string (volume->partition_label); + libhal_free_string (volume->partition_uuid); + libhal_free_string_array (volume->partition_flags); + + free (volume); +} + + +static char ** +my_strvdup (char **strv) +{ + unsigned int num_elems; + unsigned int i; + char **res; + + for (num_elems = 0; strv[num_elems] != NULL; num_elems++) + ; + + res = calloc (num_elems + 1, sizeof (char*)); + if (res == NULL) + goto out; + + for (i = 0; i < num_elems; i++) + res[i] = strdup (strv[i]); + res[i] = NULL; + +out: + return res; +} + +/* ok, hey, so this is a bit ugly */ + +#define LIBHAL_PROP_EXTRACT_BEGIN if (FALSE) +#define LIBHAL_PROP_EXTRACT_END ; +#define LIBHAL_PROP_EXTRACT_INT(_property_, _where_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_INT32) _where_ = libhal_psi_get_int (&it) +#define LIBHAL_PROP_EXTRACT_UINT64(_property_, _where_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_UINT64) _where_ = libhal_psi_get_uint64 (&it) +#define LIBHAL_PROP_EXTRACT_STRING(_property_, _where_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_STRING) _where_ = (libhal_psi_get_string (&it) != NULL && strlen (libhal_psi_get_string (&it)) > 0) ? strdup (libhal_psi_get_string (&it)) : NULL +#define LIBHAL_PROP_EXTRACT_BOOL(_property_, _where_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_BOOLEAN) _where_ = libhal_psi_get_bool (&it) +#define LIBHAL_PROP_EXTRACT_BOOL_BITFIELD(_property_, _where_, _field_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_BOOLEAN) _where_ |= libhal_psi_get_bool (&it) ? _field_ : 0 +#define LIBHAL_PROP_EXTRACT_STRLIST(_property_, _where_) else if (strcmp (key, _property_) == 0 && type == LIBHAL_PROPERTY_TYPE_STRLIST) _where_ = my_strvdup (libhal_psi_get_strlist (&it)) + +/** + * libhal_drive_from_udi: + * @hal_ctx: libhal context + * @udi: HAL UDI + * + * Returns: LibHalDrive object or NULL if UDI is invalid + * + * Given a UDI for a HAL device of capability 'storage', this + * function retrieves all the relevant properties into convenient + * in-process data structures. + */ +LibHalDrive * +libhal_drive_from_udi (LibHalContext *hal_ctx, const char *udi) +{ + char *bus_textual; + LibHalDrive *drive; + LibHalPropertySet *properties; + LibHalPropertySetIterator it; + DBusError error; + unsigned int i; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + drive = NULL; + properties = NULL; + bus_textual = NULL; + + dbus_error_init (&error); + if (!libhal_device_query_capability (hal_ctx, udi, "storage", &error)) + goto error; + + drive = malloc (sizeof (LibHalDrive)); + if (drive == NULL) + goto error; + memset (drive, 0x00, sizeof (LibHalDrive)); + + drive->hal_ctx = hal_ctx; + + drive->udi = strdup (udi); + if (drive->udi == NULL) + goto error; + + properties = libhal_device_get_all_properties (hal_ctx, udi, &error); + if (properties == NULL) + goto error; + + /* we can count on hal to give us all these properties */ + for (libhal_psi_init (&it, properties); libhal_psi_has_more (&it); libhal_psi_next (&it)) { + int type; + char *key; + + type = libhal_psi_get_type (&it); + key = libhal_psi_get_key (&it); + + LIBHAL_PROP_EXTRACT_BEGIN; + + LIBHAL_PROP_EXTRACT_INT ("block.minor", drive->device_minor); + LIBHAL_PROP_EXTRACT_INT ("block.major", drive->device_major); + LIBHAL_PROP_EXTRACT_STRING ("block.device", drive->device_file); + LIBHAL_PROP_EXTRACT_STRING ("storage.bus", bus_textual); + LIBHAL_PROP_EXTRACT_STRING ("storage.vendor", drive->vendor); + LIBHAL_PROP_EXTRACT_STRING ("storage.model", drive->model); + LIBHAL_PROP_EXTRACT_STRING ("storage.drive_type", drive->type_textual); + LIBHAL_PROP_EXTRACT_UINT64 ("storage.size", drive->drive_size); + + LIBHAL_PROP_EXTRACT_STRING ("storage.icon.drive", drive->dedicated_icon_drive); + LIBHAL_PROP_EXTRACT_STRING ("storage.icon.volume", drive->dedicated_icon_volume); + + LIBHAL_PROP_EXTRACT_BOOL ("storage.hotpluggable", drive->is_hotpluggable); + LIBHAL_PROP_EXTRACT_BOOL ("storage.removable", drive->is_removable); + LIBHAL_PROP_EXTRACT_BOOL ("storage.removable.media_available", drive->is_media_detected); + LIBHAL_PROP_EXTRACT_BOOL ("storage.media_check_enabled", drive->is_media_detection_automatic); + LIBHAL_PROP_EXTRACT_UINT64 ("storage.removable.media_size", drive->drive_media_size); + LIBHAL_PROP_EXTRACT_BOOL ("storage.requires_eject", drive->requires_eject); + + LIBHAL_PROP_EXTRACT_STRING ("storage.partitioning_scheme", drive->partition_scheme); + + LIBHAL_PROP_EXTRACT_STRING ("storage.originating_device", drive->physical_device); + LIBHAL_PROP_EXTRACT_STRING ("storage.firmware_version", drive->firmware_version); + LIBHAL_PROP_EXTRACT_STRING ("storage.serial", drive->serial); + + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.cdr", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_CDR); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.cdrw", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_CDRW); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvd", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDROM); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdplusr", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdplusrw", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdplusrwdl", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRWDL); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdplusrdl", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdr", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDR); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdrw", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDRW); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.dvdram", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_DVDRAM); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.bd", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_BDROM); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.bdr", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_BDR); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.bdre", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_BDRE); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.hddvd", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_HDDVDROM); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.hddvdr", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_HDDVDR); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.hddvdrw", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_HDDVDRW); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.mo", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_MO); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.mrw", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_MRW); + LIBHAL_PROP_EXTRACT_BOOL_BITFIELD ("storage.cdrom.mrw_w", drive->cdrom_caps, LIBHAL_DRIVE_CDROM_CAPS_MRWW); + + LIBHAL_PROP_EXTRACT_BOOL ("storage.policy.should_mount", drive->should_mount); + LIBHAL_PROP_EXTRACT_STRING ("storage.policy.desired_mount_point", drive->desired_mount_point); + LIBHAL_PROP_EXTRACT_STRING ("storage.policy.mount_filesystem", drive->mount_filesystem); + + LIBHAL_PROP_EXTRACT_BOOL ("storage.no_partitions_hint", drive->no_partitions_hint); + + LIBHAL_PROP_EXTRACT_STRLIST ("info.capabilities", drive->capabilities); + + LIBHAL_PROP_EXTRACT_END; + } + + if (drive->type_textual != NULL) { + if (strcmp (drive->type_textual, "cdrom") == 0) { + drive->cdrom_caps |= LIBHAL_DRIVE_CDROM_CAPS_CDROM; + drive->type = LIBHAL_DRIVE_TYPE_CDROM; + } else if (strcmp (drive->type_textual, "optical") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_MO; + } else if (strcmp (drive->type_textual, "floppy") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_FLOPPY; + } else if (strcmp (drive->type_textual, "disk") == 0) { + if (drive->is_removable) + drive->type = LIBHAL_DRIVE_TYPE_REMOVABLE_DISK; + else + drive->type = LIBHAL_DRIVE_TYPE_DISK; + } else if (strcmp (drive->type_textual, "tape") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_TAPE; + } else if (strcmp (drive->type_textual, "compact_flash") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_COMPACT_FLASH; + } else if (strcmp (drive->type_textual, "memory_stick") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_MEMORY_STICK; + } else if (strcmp (drive->type_textual, "smart_media") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_SMART_MEDIA; + } else if (strcmp (drive->type_textual, "sd_mmc") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_SD_MMC; + } else if (strcmp (drive->type_textual, "zip") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_ZIP; + } else if (strcmp (drive->type_textual, "jaz") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_JAZ; + } else if (strcmp (drive->type_textual, "flashkey") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_FLASHKEY; + } else { + drive->type = LIBHAL_DRIVE_TYPE_DISK; + } + + } + + if (drive->capabilities != NULL) { + for (i = 0; drive->capabilities[i] != NULL; i++) { + if (strcmp (drive->capabilities[i], "portable_audio_player") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_PORTABLE_AUDIO_PLAYER; + break; + } else if (strcmp (drive->capabilities[i], "camera") == 0) { + drive->type = LIBHAL_DRIVE_TYPE_CAMERA; + break; + } + } + } + + if (bus_textual != NULL) { + if (strcmp (bus_textual, "usb") == 0) { + drive->bus = LIBHAL_DRIVE_BUS_USB; + } else if (strcmp (bus_textual, "ieee1394") == 0) { + drive->bus = LIBHAL_DRIVE_BUS_IEEE1394; + } else if (strcmp (bus_textual, "ide") == 0) { + drive->bus = LIBHAL_DRIVE_BUS_IDE; + } else if (strcmp (bus_textual, "scsi") == 0) { + drive->bus = LIBHAL_DRIVE_BUS_SCSI; + } else if (strcmp (bus_textual, "ccw") == 0) { + drive->bus = LIBHAL_DRIVE_BUS_CCW; + } + } + + libhal_free_string (bus_textual); + libhal_free_property_set (properties); + + return drive; + +error: + LIBHAL_FREE_DBUS_ERROR(&error); + libhal_free_string (bus_textual); + libhal_free_property_set (properties); + libhal_drive_free (drive); + return NULL; +} + +const char * +libhal_volume_get_storage_device_udi (LibHalVolume *volume) +{ + return volume->storage_device; +} + +const char *libhal_drive_get_physical_device_udi (LibHalDrive *drive) +{ + return drive->physical_device; +} + +dbus_bool_t +libhal_drive_requires_eject (LibHalDrive *drive) +{ + return drive->requires_eject; +} + +/** + * libhal_volume_from_udi: + * @hal_ctx: libhal context + * @udi: HAL UDI + * + * Returns: LibHalVolume object or NULL if UDI is invalid + * + * Given a UDI for a LIBHAL device of capability 'volume', this + * function retrieves all the relevant properties into convenient + * in-process data structures. + */ +LibHalVolume * +libhal_volume_from_udi (LibHalContext *hal_ctx, const char *udi) +{ + char *disc_type_textual; + char *vol_fsusage_textual; + LibHalVolume *vol; + LibHalPropertySet *properties; + LibHalPropertySetIterator it; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + vol = NULL; + properties = NULL; + disc_type_textual = NULL; + vol_fsusage_textual = NULL; + + dbus_error_init (&error); + if (!libhal_device_query_capability (hal_ctx, udi, "volume", &error)) + goto error; + + vol = malloc (sizeof (LibHalVolume)); + if (vol == NULL) + goto error; + memset (vol, 0x00, sizeof (LibHalVolume)); + + vol->udi = strdup (udi); + + properties = libhal_device_get_all_properties (hal_ctx, udi, &error); + if (properties == NULL) + goto error; + + /* we can count on hal to give us all these properties */ + for (libhal_psi_init (&it, properties); libhal_psi_has_more (&it); libhal_psi_next (&it)) { + int type; + char *key; + + type = libhal_psi_get_type (&it); + key = libhal_psi_get_key (&it); + + LIBHAL_PROP_EXTRACT_BEGIN; + + LIBHAL_PROP_EXTRACT_BOOL ("volume.is_partition", vol->is_partition); + LIBHAL_PROP_EXTRACT_INT ("volume.partition.number", vol->partition_number); + LIBHAL_PROP_EXTRACT_STRING ("volume.partition.scheme", vol->partition_scheme); + LIBHAL_PROP_EXTRACT_STRING ("volume.partition.type", vol->partition_type); + LIBHAL_PROP_EXTRACT_STRING ("volume.partition.label", vol->partition_label); + LIBHAL_PROP_EXTRACT_STRING ("volume.partition.uuid", vol->partition_uuid); + LIBHAL_PROP_EXTRACT_STRLIST ("volume.partition.flags", vol->partition_flags); + + LIBHAL_PROP_EXTRACT_UINT64 ("volume.partition.start", vol->partition_start_offset); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.partition.media_size", vol->partition_media_size); + LIBHAL_PROP_EXTRACT_INT ("volume.partition.msdos_part_table_type", vol->msdos_part_table_type); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.partition.msdos_part_table_start", vol->msdos_part_table_start); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.partition.msdos_part_table_size", vol->msdos_part_table_size); + + LIBHAL_PROP_EXTRACT_INT ("block.minor", vol->device_minor); + LIBHAL_PROP_EXTRACT_INT ("block.major", vol->device_major); + LIBHAL_PROP_EXTRACT_STRING ("block.device", vol->device_file); + + LIBHAL_PROP_EXTRACT_STRING ("block.storage_device", vol->storage_device); + + LIBHAL_PROP_EXTRACT_STRING ("volume.crypto_luks.clear.backing_volume", vol->crypto_backing_volume); + + LIBHAL_PROP_EXTRACT_INT ("volume.block_size", vol->block_size); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.num_blocks", vol->num_blocks); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.size", vol->volume_size); + LIBHAL_PROP_EXTRACT_STRING ("volume.label", vol->volume_label); + LIBHAL_PROP_EXTRACT_STRING ("volume.mount_point", vol->mount_point); + LIBHAL_PROP_EXTRACT_STRING ("volume.fstype", vol->fstype); + LIBHAL_PROP_EXTRACT_STRING ("volume.fsversion", vol->fsversion); + LIBHAL_PROP_EXTRACT_BOOL ("volume.is_mounted", vol->is_mounted); + LIBHAL_PROP_EXTRACT_BOOL ("volume.is_mounted_read_only", vol->is_mounted_read_only); + LIBHAL_PROP_EXTRACT_STRING ("volume.fsusage", vol_fsusage_textual); + LIBHAL_PROP_EXTRACT_STRING ("volume.uuid", vol->uuid); + + LIBHAL_PROP_EXTRACT_BOOL ("volume.ignore", vol->ignore_volume); + + LIBHAL_PROP_EXTRACT_BOOL ("volume.is_disc", vol->is_disc); + LIBHAL_PROP_EXTRACT_STRING ("volume.disc.type", disc_type_textual); + LIBHAL_PROP_EXTRACT_BOOL ("volume.disc.has_audio", vol->disc_has_audio); + LIBHAL_PROP_EXTRACT_BOOL ("volume.disc.has_data", vol->disc_has_data); + LIBHAL_PROP_EXTRACT_BOOL ("volume.disc.is_appendable", vol->disc_is_appendable); + LIBHAL_PROP_EXTRACT_BOOL ("volume.disc.is_blank", vol->disc_is_blank); + LIBHAL_PROP_EXTRACT_BOOL ("volume.disc.is_rewritable", vol->disc_is_rewritable); + LIBHAL_PROP_EXTRACT_UINT64 ("volume.disc.capacity", vol->disc_capacity); + + LIBHAL_PROP_EXTRACT_BOOL ("volume.policy.should_mount", vol->should_mount); + LIBHAL_PROP_EXTRACT_STRING ("volume.policy.desired_mount_point", vol->desired_mount_point); + LIBHAL_PROP_EXTRACT_STRING ("volume.policy.mount_filesystem", vol->mount_filesystem); + + LIBHAL_PROP_EXTRACT_END; + } + + if (disc_type_textual != NULL) { + if (strcmp (disc_type_textual, "cd_rom") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_CDROM; + } else if (strcmp (disc_type_textual, "cd_r") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_CDR; + } else if (strcmp (disc_type_textual, "cd_rw") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_CDRW; + } else if (strcmp (disc_type_textual, "dvd_rom") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDROM; + } else if (strcmp (disc_type_textual, "dvd_ram") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDRAM; + } else if (strcmp (disc_type_textual, "dvd_r") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDR; + } else if (strcmp (disc_type_textual, "dvd_rw") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDRW; + } else if (strcmp (disc_type_textual, "dvd_r_dl") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDR_DL; + } else if (strcmp (disc_type_textual, "dvd_plus_r") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR; + } else if (strcmp (disc_type_textual, "dvd_plus_rw") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW; + } else if (strcmp (disc_type_textual, "dvd_plus_r_dl") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR_DL; + } else if (strcmp (disc_type_textual, "bd_rom") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_BDROM; + } else if (strcmp (disc_type_textual, "bd_r") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_BDR; + } else if (strcmp (disc_type_textual, "bd_re") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_BDRE; + } else if (strcmp (disc_type_textual, "hddvd_rom") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_HDDVDROM; + } else if (strcmp (disc_type_textual, "hddvd_r") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_HDDVDR; + } else if (strcmp (disc_type_textual, "hddvd_rw") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_HDDVDRW; + } else if (strcmp (disc_type_textual, "mo") == 0) { + vol->disc_type = LIBHAL_VOLUME_DISC_TYPE_MO; + } + } + + vol->fsusage = LIBHAL_VOLUME_USAGE_UNKNOWN; + if (vol_fsusage_textual != NULL) { + if (strcmp (vol_fsusage_textual, "filesystem") == 0) { + vol->fsusage = LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM; + } else if (strcmp (vol_fsusage_textual, "partitiontable") == 0) { + vol->fsusage = LIBHAL_VOLUME_USAGE_PARTITION_TABLE; + } else if (strcmp (vol_fsusage_textual, "raid") == 0) { + vol->fsusage = LIBHAL_VOLUME_USAGE_RAID_MEMBER; + } else if (strcmp (vol_fsusage_textual, "crypto") == 0) { + vol->fsusage = LIBHAL_VOLUME_USAGE_CRYPTO; + } else if (strcmp (vol_fsusage_textual, "other") == 0) { + vol->fsusage = LIBHAL_VOLUME_USAGE_OTHER; + } else { + vol->fsusage = LIBHAL_VOLUME_USAGE_UNKNOWN; + } + } + + libhal_free_string (vol_fsusage_textual); + libhal_free_string (disc_type_textual); + libhal_free_property_set (properties); + return vol; +error: + if (dbus_error_is_set (&error)) { + dbus_error_free (&error); + } + libhal_free_string (vol_fsusage_textual); + libhal_free_string (disc_type_textual); + libhal_free_property_set (properties); + libhal_volume_free (vol); + return NULL; +} + + +/** + * libhal_volume_get_msdos_part_table_type: + * @volume: Volume object + * + * Returns: The partition type or -1 if volume is not + * a partition or the media the volume stems from + * isn't partition with a MS DOS style table + * + * If the volume is on a drive with a MSDOS style partition table, return + * the partition table id. + */ +int +libhal_volume_get_msdos_part_table_type (LibHalVolume *volume) +{ + return volume->msdos_part_table_type; +} + +/** + * libhal_volume_get_msdos_part_table_start: + * @volume: Volume object + * + * Returns: The partition start offset or -1 if volume isnt + * a partition or the media the volume stems from + * isn't partition with a MS DOS style table + * + * If the volume is on a drive with a MSDOS style partition table, return + * the partition start offset according to the partition table. + */ +dbus_uint64_t +libhal_volume_get_msdos_part_table_start (LibHalVolume *volume) +{ + return volume->msdos_part_table_start; +} + +/** + * libhal_volume_get_msdos_part_table_size: + * @volume: Volume object + * + * Returns: The partition size or -1 if volume is not + * a partition or the media the volume stems from + * isn't partition with a MS DOS style table + * + * If the volume is on a drive with a MSDOS style partition table, return + * the partition size according to the partition table. + */ +dbus_uint64_t +libhal_volume_get_msdos_part_table_size (LibHalVolume *volume) +{ + return volume->msdos_part_table_size; +} + +/***********************************************************************/ + +/** + * libhal_drive_from_device_file: + * @hal_ctx: libhal context to use + * @device_file: Name of special device file, e.g. '/dev/hdc' + * + * Returns: LibHalDrive object or NULL if it doesn't exist + * + * Get the drive object that either is (when given e.g. /dev/sdb) or contains + * (when given e.g. /dev/sdb1) the given device file. + */ +LibHalDrive * +libhal_drive_from_device_file (LibHalContext *hal_ctx, const char *device_file) +{ + int i; + char **hal_udis; + int num_hal_udis; + LibHalDrive *result; + char *found_udi; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + result = NULL; + found_udi = NULL; + + dbus_error_init (&error); + if ((hal_udis = libhal_manager_find_device_string_match (hal_ctx, "block.device", + device_file, &num_hal_udis, &error)) == NULL) { + LIBHAL_FREE_DBUS_ERROR(&error); + goto out; + } + + for (i = 0; i < num_hal_udis; i++) { + char *udi; + char *storage_udi; + DBusError err1; + DBusError err2; + udi = hal_udis[i]; + + dbus_error_init (&err1); + dbus_error_init (&err2); + if (libhal_device_query_capability (hal_ctx, udi, "volume", &err1)) { + + storage_udi = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", &err1); + if (storage_udi == NULL) + continue; + found_udi = strdup (storage_udi); + libhal_free_string (storage_udi); + break; + } else if (libhal_device_query_capability (hal_ctx, udi, "storage", &err2)) { + found_udi = strdup (udi); + } + LIBHAL_FREE_DBUS_ERROR(&err1); + LIBHAL_FREE_DBUS_ERROR(&err2); + } + + libhal_free_string_array (hal_udis); + + if (found_udi != NULL) + result = libhal_drive_from_udi (hal_ctx, found_udi); + + free (found_udi); +out: + return result; +} + + +/** + * libhal_volume_from_mount_point: + * @hal_ctx: libhal context to use + * @mount_point: Name of mount point without terminting slash, e.g. '/media/disk' + * + * Returns: LibHalVolume object or NULL if it doesn't exist + * + * Get the volume object for a given mount point + */ +LibHalVolume * +libhal_volume_from_mount_point (LibHalContext *hal_ctx, + const char *mount_point) +{ + int i; + char **hal_udis; + int num_hal_udis; + LibHalVolume *result; + char *found_udi; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + result = NULL; + found_udi = NULL; + + dbus_error_init (&error); + if ((hal_udis = libhal_manager_find_device_string_match (hal_ctx, "volume.mount_point", + mount_point, &num_hal_udis, &error)) == NULL) + goto out; + + for (i = 0; i < num_hal_udis; i++) { + char *udi; + udi = hal_udis[i]; + if (libhal_device_query_capability (hal_ctx, udi, "volume", &error)) { + found_udi = strdup (udi); + break; + } + } + + libhal_free_string_array (hal_udis); + + if (found_udi != NULL) + result = libhal_volume_from_udi (hal_ctx, found_udi); + + free (found_udi); +out: + LIBHAL_FREE_DBUS_ERROR(&error); + return result; +} + +/** + * libhal_volume_from_device_file: + * @hal_ctx: libhal context to use + * @device_file: Name of special device file, e.g. '/dev/hda5' + * + * Returns: LibHalVolume object or NULL if it doesn't exist + * + * Get the volume object for a given device file. + */ +LibHalVolume * +libhal_volume_from_device_file (LibHalContext *hal_ctx, const char *device_file) +{ + int i; + char **hal_udis; + int num_hal_udis; + LibHalVolume *result; + char *found_udi; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + result = NULL; + found_udi = NULL; + + dbus_error_init (&error); + if ((hal_udis = libhal_manager_find_device_string_match (hal_ctx, "block.device", + device_file, &num_hal_udis, &error)) == NULL) + goto out; + + for (i = 0; i < num_hal_udis; i++) { + char *udi; + udi = hal_udis[i]; + if (libhal_device_query_capability (hal_ctx, udi, "volume", &error)) { + found_udi = strdup (udi); + break; + } + } + + libhal_free_string_array (hal_udis); + + if (found_udi != NULL) + result = libhal_volume_from_udi (hal_ctx, found_udi); + + free (found_udi); +out: + LIBHAL_FREE_DBUS_ERROR(&error); + return result; +} + +dbus_uint64_t +libhal_volume_get_size (LibHalVolume *volume) +{ + if (volume->volume_size > 0) + return volume->volume_size; + else + return ((dbus_uint64_t)volume->block_size) * volume->num_blocks; +} + +dbus_uint64_t +libhal_volume_get_disc_capacity (LibHalVolume *volume) +{ + return volume->disc_capacity; +} + + +dbus_bool_t +libhal_drive_is_hotpluggable (LibHalDrive *drive) +{ + return drive->is_hotpluggable; +} + +dbus_bool_t +libhal_drive_uses_removable_media (LibHalDrive *drive) +{ + return drive->is_removable; +} + +dbus_bool_t +libhal_drive_is_media_detected (LibHalDrive *drive) +{ + return drive->is_media_detected; +} + +dbus_bool_t +libhal_drive_is_media_detection_automatic (LibHalDrive *drive) +{ + return drive->is_media_detection_automatic; +} + +dbus_uint64_t +libhal_drive_get_size (LibHalDrive *drive) +{ + return drive->drive_size; +} + +dbus_uint64_t +libhal_drive_get_media_size (LibHalDrive *drive) +{ + return drive->drive_media_size; +} + +const char * +libhal_drive_get_partition_scheme (LibHalDrive *drive) +{ + return drive->partition_scheme; +} + + +LibHalDriveType +libhal_drive_get_type (LibHalDrive *drive) +{ + return drive->type; +} + +LibHalDriveBus +libhal_drive_get_bus (LibHalDrive *drive) +{ + return drive->bus; +} + +LibHalDriveCdromCaps +libhal_drive_get_cdrom_caps (LibHalDrive *drive) +{ + return drive->cdrom_caps; +} + +unsigned int +libhal_drive_get_device_major (LibHalDrive *drive) +{ + return drive->device_major; +} + +unsigned int +libhal_drive_get_device_minor (LibHalDrive *drive) +{ + return drive->device_minor; +} + +const char * +libhal_drive_get_type_textual (LibHalDrive *drive) +{ + return drive->type_textual; +} + +const char * +libhal_drive_get_device_file (LibHalDrive *drive) +{ + return drive->device_file; +} + +const char * +libhal_drive_get_udi (LibHalDrive *drive) +{ + return drive->udi; +} + +const char * +libhal_drive_get_serial (LibHalDrive *drive) +{ + return drive->serial; +} + +const char * +libhal_drive_get_firmware_version (LibHalDrive *drive) +{ + return drive->firmware_version; +} + +const char * +libhal_drive_get_model (LibHalDrive *drive) +{ + return drive->model; +} + +const char * +libhal_drive_get_vendor (LibHalDrive *drive) +{ + return drive->vendor; +} + +/*****************************************************************************/ + +const char * +libhal_volume_get_udi (LibHalVolume *volume) +{ + return volume->udi; +} + +const char * +libhal_volume_get_device_file (LibHalVolume *volume) +{ + return volume->device_file; +} + +unsigned int libhal_volume_get_device_major (LibHalVolume *volume) +{ + return volume->device_major; +} + +unsigned int libhal_volume_get_device_minor (LibHalVolume *volume) +{ + return volume->device_minor; +} + +const char * +libhal_volume_get_fstype (LibHalVolume *volume) +{ + return volume->fstype; +} + +const char * +libhal_volume_get_fsversion (LibHalVolume *volume) +{ + return volume->fsversion; +} + +LibHalVolumeUsage +libhal_volume_get_fsusage (LibHalVolume *volume) +{ + return volume->fsusage; +} + +dbus_bool_t +libhal_volume_is_mounted (LibHalVolume *volume) +{ + return volume->is_mounted; +} + +dbus_bool_t +libhal_volume_is_mounted_read_only (LibHalVolume *volume) +{ + return volume->is_mounted_read_only; +} + +dbus_bool_t +libhal_volume_is_partition (LibHalVolume *volume) +{ + return volume->is_partition; +} + +dbus_bool_t +libhal_volume_is_disc (LibHalVolume *volume) +{ + return volume->is_disc; +} + +unsigned int +libhal_volume_get_partition_number (LibHalVolume *volume) +{ + return volume->partition_number; +} + +const char * +libhal_volume_get_partition_scheme (LibHalVolume *volume) +{ + return volume->partition_scheme; +} + +const char * +libhal_volume_get_partition_type (LibHalVolume *volume) +{ + return volume->partition_type; +} + +const char * +libhal_volume_get_partition_label (LibHalVolume *volume) +{ + return volume->partition_label; +} + +const char * +libhal_volume_get_partition_uuid (LibHalVolume *volume) +{ + return volume->partition_uuid; +} + +const char ** +libhal_volume_get_partition_flags (LibHalVolume *volume) +{ + return (const char **) volume->partition_flags; +} + + +dbus_uint64_t +libhal_volume_get_partition_start_offset (LibHalVolume *volume) +{ + return volume->partition_start_offset; +} + +dbus_uint64_t +libhal_volume_get_partition_media_size (LibHalVolume *volume) +{ + return volume->partition_media_size; +} + +const char * +libhal_volume_get_label (LibHalVolume *volume) +{ + return volume->volume_label; +} + +const char * +libhal_volume_get_mount_point (LibHalVolume *volume) +{ + return volume->mount_point; +} + +const char * +libhal_volume_get_uuid (LibHalVolume *volume) +{ + return volume->uuid; +} + +dbus_bool_t +libhal_volume_disc_has_audio (LibHalVolume *volume) +{ + return volume->disc_has_audio; +} + +dbus_bool_t +libhal_volume_disc_has_data (LibHalVolume *volume) +{ + return volume->disc_has_data; +} + +dbus_bool_t +libhal_volume_disc_is_blank (LibHalVolume *volume) +{ + return volume->disc_is_blank; +} + +dbus_bool_t +libhal_volume_disc_is_rewritable (LibHalVolume *volume) +{ + return volume->disc_is_rewritable; +} + +dbus_bool_t +libhal_volume_disc_is_appendable (LibHalVolume *volume) +{ + return volume->disc_is_appendable; +} + +LibHalVolumeDiscType +libhal_volume_get_disc_type (LibHalVolume *volume) +{ + return volume->disc_type; +} + +dbus_bool_t +libhal_volume_should_ignore (LibHalVolume *volume) +{ + return volume->ignore_volume; +} + +char ** +libhal_drive_find_all_volumes (LibHalContext *hal_ctx, LibHalDrive *drive, int *num_volumes) +{ + int i; + char **udis; + int num_udis; + const char *drive_udi; + char **result; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + udis = NULL; + result = NULL; + *num_volumes = 0; + + drive_udi = libhal_drive_get_udi (drive); + if (drive_udi == NULL) + goto out; + + /* get initial list... */ + dbus_error_init (&error); + if ((udis = libhal_manager_find_device_string_match (hal_ctx, "block.storage_device", + drive_udi, &num_udis, &error)) == NULL) { + LIBHAL_FREE_DBUS_ERROR(&error); + goto out; + } + + result = malloc (sizeof (char *) * num_udis); + if (result == NULL) + goto out; + + /* ...and filter out the single UDI that is the drive itself */ + for (i = 0; i < num_udis; i++) { + if (strcmp (udis[i], drive_udi) == 0) + continue; + result[*num_volumes] = strdup (udis[i]); + *num_volumes = (*num_volumes) + 1; + } + /* set last element (above removed UDI) to NULL for libhal_free_string_array()*/ + result[*num_volumes] = NULL; + +out: + libhal_free_string_array (udis); + return result; +} + +const char * +libhal_volume_crypto_get_backing_volume_udi (LibHalVolume *volume) +{ + return volume->crypto_backing_volume; +} + +char * +libhal_volume_crypto_get_clear_volume_udi (LibHalContext *hal_ctx, LibHalVolume *volume) +{ + DBusError error; + char **clear_devices; + int num_clear_devices; + char *result; + + result = NULL; + + LIBHAL_CHECK_LIBHALCONTEXT (hal_ctx, NULL); + + dbus_error_init (&error); + clear_devices = libhal_manager_find_device_string_match (hal_ctx, + "volume.crypto_luks.clear.backing_volume", + volume->udi, + &num_clear_devices, + &error); + if (clear_devices != NULL) { + + if (num_clear_devices >= 1) { + result = strdup (clear_devices[0]); + } + libhal_free_string_array (clear_devices); + } + + return result; +} + + +/*************************************************************************/ + +char * +libhal_drive_policy_default_get_mount_root (LibHalContext *hal_ctx) +{ + char *result; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + dbus_error_init (&error); + if ((result = libhal_device_get_property_string (hal_ctx, "/org/freedesktop/Hal/devices/computer", + "storage.policy.default.mount_root", &error)) == NULL) + LIBHAL_FREE_DBUS_ERROR(&error); + + return result; +} + +dbus_bool_t +libhal_drive_policy_default_use_managed_keyword (LibHalContext *hal_ctx) +{ + dbus_bool_t result; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, FALSE); + + dbus_error_init (&error); + if ((result = libhal_device_get_property_bool (hal_ctx, "/org/freedesktop/Hal/devices/computer", + "storage.policy.default.use_managed_keyword", &error)) == FALSE) + LIBHAL_FREE_DBUS_ERROR(&error); + + return result; +} + +char * +libhal_drive_policy_default_get_managed_keyword_primary (LibHalContext *hal_ctx) +{ + char *result; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + dbus_error_init (&error); + if ((result = libhal_device_get_property_string (hal_ctx, "/org/freedesktop/Hal/devices/computer", + "storage.policy.default.managed_keyword.primary", &error)) == NULL) + LIBHAL_FREE_DBUS_ERROR(&error); + + return result; +} + +char * +libhal_drive_policy_default_get_managed_keyword_secondary (LibHalContext *hal_ctx) +{ + char *result; + DBusError error; + + LIBHAL_CHECK_LIBHALCONTEXT(hal_ctx, NULL); + + dbus_error_init (&error); + if ((result = libhal_device_get_property_string (hal_ctx, "/org/freedesktop/Hal/devices/computer", + "storage.policy.default.managed_keyword.secondary", &error)) == NULL) + LIBHAL_FREE_DBUS_ERROR(&error); + + return result; +} + +/*************************************************************************/ + +dbus_bool_t +libhal_drive_policy_is_mountable (LibHalDrive *drive, LibHalStoragePolicy *policy) +{ + printf ("should_mount=%u, no_partitions_hint=%u\n", drive->should_mount, drive->no_partitions_hint); + + return drive->should_mount && drive->no_partitions_hint; +} + +const char * +libhal_drive_policy_get_desired_mount_point (LibHalDrive *drive, LibHalStoragePolicy *policy) +{ + return drive->desired_mount_point; +} + +/* safely strcat() at most the remaining space in 'dst' */ +#define strcat_len(dst, src, dstmaxlen) do { \ + dst[dstmaxlen - 1] = '\0'; \ + strncat (dst, src, dstmaxlen - strlen (dst) - 1); \ +} while(0) + + +static void +mopts_collect (LibHalContext *hal_ctx, const char *namespace, int namespace_len, + const char *udi, char *options_string, size_t options_max_len, dbus_bool_t only_collect_imply_opts) +{ + LibHalPropertySet *properties; + LibHalPropertySetIterator it; + DBusError error; + + if(hal_ctx == NULL) { + fprintf (stderr,"%s %d : LibHalContext *ctx is NULL\n",__FILE__, __LINE__); + return; + } + + dbus_error_init (&error); + + /* first collect from root computer device */ + properties = libhal_device_get_all_properties (hal_ctx, udi, &error); + if (properties == NULL ) { + LIBHAL_FREE_DBUS_ERROR(&error); + return; + } + + for (libhal_psi_init (&it, properties); libhal_psi_has_more (&it); libhal_psi_next (&it)) { + char *key; + + key = libhal_psi_get_key (&it); + if (libhal_psi_get_type (&it) == LIBHAL_PROPERTY_TYPE_BOOLEAN && + strncmp (key, namespace, namespace_len - 1) == 0) { + const char *option = key + namespace_len - 1; + char *location; + dbus_bool_t is_imply_opt; + + is_imply_opt = FALSE; + if (strcmp (option, "user") == 0 || + strcmp (option, "users") == 0 || + strcmp (option, "defaults") == 0 || + strcmp (option, "pamconsole") == 0) + is_imply_opt = TRUE; + + + if (only_collect_imply_opts) { + if (!is_imply_opt) + continue; + } else { + if (is_imply_opt) + continue; + } + + if (libhal_psi_get_bool (&it)) { + /* see if option is already there */ + location = strstr (options_string, option); + if (location == NULL) { + if (strlen (options_string) > 0) + strcat_len (options_string, ",", options_max_len); + strcat_len (options_string, option, options_max_len); + } + } else { + /* remove option if already there */ + location = strstr (options_string, option); + if (location != NULL) { + char *end; + + end = strchr (location, ','); + if (end == NULL) { + location[0] = '\0'; + } else { + strcpy (location, end + 1); /* skip the extra comma */ + } + } + + } + } + } + + libhal_free_property_set (properties); +} + + +const char * +libhal_drive_policy_get_mount_options (LibHalDrive *drive, LibHalStoragePolicy *policy) +{ + const char *result; + char stor_mount_option_default_begin[] = "storage.policy.default.mount_option."; + char stor_mount_option_begin[] = "storage.policy.mount_option."; + + result = NULL; + drive->mount_options[0] = '\0'; + + /* collect options != ('pamconsole', 'user', 'users', 'defaults' options that imply other options) */ + mopts_collect (drive->hal_ctx, stor_mount_option_default_begin, sizeof (stor_mount_option_default_begin), + "/org/freedesktop/Hal/devices/computer", drive->mount_options, MOUNT_OPTIONS_SIZE, TRUE); + mopts_collect (drive->hal_ctx, stor_mount_option_begin, sizeof (stor_mount_option_begin), + drive->udi, drive->mount_options, MOUNT_OPTIONS_SIZE, TRUE); + /* ensure ('pamconsole', 'user', 'users', 'defaults' options that imply other options), are first */ + mopts_collect (drive->hal_ctx, stor_mount_option_default_begin, sizeof (stor_mount_option_default_begin), + "/org/freedesktop/Hal/devices/computer", drive->mount_options, MOUNT_OPTIONS_SIZE, FALSE); + mopts_collect (drive->hal_ctx, stor_mount_option_begin, sizeof (stor_mount_option_begin), + drive->udi, drive->mount_options, MOUNT_OPTIONS_SIZE, FALSE); + + result = drive->mount_options; + + return result; +} + +const char * +libhal_drive_policy_get_mount_fs (LibHalDrive *drive, LibHalStoragePolicy *policy) +{ + return drive->mount_filesystem; +} + + +dbus_bool_t +libhal_volume_policy_is_mountable (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + return drive->should_mount && volume->should_mount; +} + +const char *libhal_volume_policy_get_desired_mount_point (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + return volume->desired_mount_point; +} + +const char *libhal_volume_policy_get_mount_options (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + const char *result; + char stor_mount_option_default_begin[] = "storage.policy.default.mount_option."; + char vol_mount_option_begin[] = "volume.policy.mount_option."; + + result = NULL; + volume->mount_options[0] = '\0'; + + /* ensure ('pamconsole', 'user', 'users', 'defaults' options that imply other options), are first */ + mopts_collect (drive->hal_ctx, stor_mount_option_default_begin, sizeof (stor_mount_option_default_begin), + "/org/freedesktop/Hal/devices/computer", volume->mount_options, MOUNT_OPTIONS_SIZE, TRUE); + mopts_collect (drive->hal_ctx, vol_mount_option_begin, sizeof (vol_mount_option_begin), + volume->udi, volume->mount_options, MOUNT_OPTIONS_SIZE, TRUE); + /* collect options != ('pamconsole', 'user', 'users', 'defaults' options that imply other options) */ + mopts_collect (drive->hal_ctx, stor_mount_option_default_begin, sizeof (stor_mount_option_default_begin), + "/org/freedesktop/Hal/devices/computer", volume->mount_options, MOUNT_OPTIONS_SIZE, FALSE); + mopts_collect (drive->hal_ctx, vol_mount_option_begin, sizeof (vol_mount_option_begin), + volume->udi, volume->mount_options, MOUNT_OPTIONS_SIZE, FALSE); + + result = volume->mount_options; + + return result; +} + +const char *libhal_volume_policy_get_mount_fs (LibHalDrive *drive, LibHalVolume *volume, LibHalStoragePolicy *policy) +{ + return volume->mount_filesystem; +} + +dbus_bool_t +libhal_drive_no_partitions_hint (LibHalDrive *drive) +{ + return drive->no_partitions_hint; +} diff --git a/deps/libhal-storage.h b/deps/libhal-storage.h new file mode 100644 index 0000000..d4ee015 --- /dev/null +++ b/deps/libhal-storage.h @@ -0,0 +1,374 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * libhal-storage.h : HAL convenience library for storage devices and volumes + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Author: David Zeuthen + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifndef LIBHAL_STORAGE_H +#define LIBHAL_STORAGE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#if 0 +} /* shut up emacs indenting */ +#endif +#endif + +struct LibHalDrive_s; +typedef struct LibHalDrive_s LibHalDrive; +struct LibHalVolume_s; +typedef struct LibHalVolume_s LibHalVolume; +struct LibHalStoragePolicy_s; +typedef struct LibHalStoragePolicy_s LibHalStoragePolicy; + + +typedef enum { + LIBHAL_STORAGE_ICON_DRIVE_REMOVABLE_DISK = 0x10000, + LIBHAL_STORAGE_ICON_DRIVE_REMOVABLE_DISK_IDE = 0x10001, + LIBHAL_STORAGE_ICON_DRIVE_REMOVABLE_DISK_SCSI = 0x10002, + LIBHAL_STORAGE_ICON_DRIVE_REMOVABLE_DISK_USB = 0x10003, + LIBHAL_STORAGE_ICON_DRIVE_REMOVABLE_DISK_IEEE1394 = 0x10004, + LIBHAL_STORAGE_ICON_DRIVE_DISK = 0x10100, + LIBHAL_STORAGE_ICON_DRIVE_DISK_IDE = 0x10101, + LIBHAL_STORAGE_ICON_DRIVE_DISK_SCSI = 0x10102, + LIBHAL_STORAGE_ICON_DRIVE_DISK_USB = 0x10103, + LIBHAL_STORAGE_ICON_DRIVE_DISK_IEEE1394 = 0x10104, + LIBHAL_STORAGE_ICON_DRIVE_CDROM = 0x10200, + LIBHAL_STORAGE_ICON_DRIVE_CDROM_IDE = 0x10201, + LIBHAL_STORAGE_ICON_DRIVE_CDROM_SCSI = 0x10202, + LIBHAL_STORAGE_ICON_DRIVE_CDROM_USB = 0x10203, + LIBHAL_STORAGE_ICON_DRIVE_CDROM_IEEE1394 = 0x10204, + LIBHAL_STORAGE_ICON_DRIVE_FLOPPY = 0x10300, + LIBHAL_STORAGE_ICON_DRIVE_FLOPPY_IDE = 0x10301, + LIBHAL_STORAGE_ICON_DRIVE_FLOPPY_SCSI = 0x10302, + LIBHAL_STORAGE_ICON_DRIVE_FLOPPY_USB = 0x10303, + LIBHAL_STORAGE_ICON_DRIVE_FLOPPY_IEEE1394 = 0x10304, + LIBHAL_STORAGE_ICON_DRIVE_TAPE = 0x10400, + LIBHAL_STORAGE_ICON_DRIVE_COMPACT_FLASH = 0x10500, + LIBHAL_STORAGE_ICON_DRIVE_MEMORY_STICK = 0x10600, + LIBHAL_STORAGE_ICON_DRIVE_SMART_MEDIA = 0x10700, + LIBHAL_STORAGE_ICON_DRIVE_SD_MMC = 0x10800, + LIBHAL_STORAGE_ICON_DRIVE_CAMERA = 0x10900, + LIBHAL_STORAGE_ICON_DRIVE_PORTABLE_AUDIO_PLAYER = 0x10a00, + LIBHAL_STORAGE_ICON_DRIVE_ZIP = 0x10b00, + LIBHAL_STORAGE_ICON_DRIVE_JAZ = 0x10c00, + LIBHAL_STORAGE_ICON_DRIVE_FLASH_KEY = 0x10d00, + + LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK = 0x20000, + LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK_IDE = 0x20001, + LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK_SCSI = 0x20002, + LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK_USB = 0x20003, + LIBHAL_STORAGE_ICON_VOLUME_REMOVABLE_DISK_IEEE1394 = 0x20004, + LIBHAL_STORAGE_ICON_VOLUME_DISK = 0x20100, + LIBHAL_STORAGE_ICON_VOLUME_DISK_IDE = 0x20101, + LIBHAL_STORAGE_ICON_VOLUME_DISK_SCSI = 0x20102, + LIBHAL_STORAGE_ICON_VOLUME_DISK_USB = 0x20103, + LIBHAL_STORAGE_ICON_VOLUME_DISK_IEEE1394 = 0x20104, + LIBHAL_STORAGE_ICON_VOLUME_CDROM = 0x20200, + LIBHAL_STORAGE_ICON_VOLUME_CDROM_IDE = 0x20201, + LIBHAL_STORAGE_ICON_VOLUME_CDROM_SCSI = 0x20202, + LIBHAL_STORAGE_ICON_VOLUME_CDROM_USB = 0x20203, + LIBHAL_STORAGE_ICON_VOLUME_CDROM_IEEE1394 = 0x20204, + LIBHAL_STORAGE_ICON_VOLUME_FLOPPY = 0x20300, + LIBHAL_STORAGE_ICON_VOLUME_FLOPPY_IDE = 0x20301, + LIBHAL_STORAGE_ICON_VOLUME_FLOPPY_SCSI = 0x20302, + LIBHAL_STORAGE_ICON_VOLUME_FLOPPY_USB = 0x20303, + LIBHAL_STORAGE_ICON_VOLUME_FLOPPY_IEEE1394 = 0x20304, + LIBHAL_STORAGE_ICON_VOLUME_TAPE = 0x20400, + LIBHAL_STORAGE_ICON_VOLUME_COMPACT_FLASH = 0x20500, + LIBHAL_STORAGE_ICON_VOLUME_MEMORY_STICK = 0x20600, + LIBHAL_STORAGE_ICON_VOLUME_SMART_MEDIA = 0x20700, + LIBHAL_STORAGE_ICON_VOLUME_SD_MMC = 0x20800, + LIBHAL_STORAGE_ICON_VOLUME_CAMERA = 0x20900, + LIBHAL_STORAGE_ICON_VOLUME_PORTABLE_AUDIO_PLAYER = 0x20a00, + LIBHAL_STORAGE_ICON_VOLUME_ZIP = 0x20b00, + LIBHAL_STORAGE_ICON_VOLUME_JAZ = 0x20c00, + LIBHAL_STORAGE_ICON_VOLUME_FLASH_KEY = 0x20d00, + + LIBHAL_STORAGE_ICON_DISC_CDROM = 0x30000, + LIBHAL_STORAGE_ICON_DISC_CDR = 0x30001, + LIBHAL_STORAGE_ICON_DISC_CDRW = 0x30002, + LIBHAL_STORAGE_ICON_DISC_DVDROM = 0x30003, + LIBHAL_STORAGE_ICON_DISC_DVDRAM = 0x30004, + LIBHAL_STORAGE_ICON_DISC_DVDR = 0x30005, + LIBHAL_STORAGE_ICON_DISC_DVDRW = 0x30006, + LIBHAL_STORAGE_ICON_DISC_DVDPLUSR = 0x30007, + LIBHAL_STORAGE_ICON_DISC_DVDPLUSRW = 0x30008, + LIBHAL_STORAGE_ICON_DISC_DVDPLUSRWDL = 0x30009, + LIBHAL_STORAGE_ICON_DISC_BDROM = 0x3000a, + LIBHAL_STORAGE_ICON_DISC_BDR = 0x3000b, + LIBHAL_STORAGE_ICON_DISC_BDRE = 0x3000c, + LIBHAL_STORAGE_ICON_DISC_HDDVDROM = 0x3000d, + LIBHAL_STORAGE_ICON_DISC_HDDVDR = 0x3000e, + LIBHAL_STORAGE_ICON_DISC_HDDVDRW = 0x3000f, + LIBHAL_STORAGE_ICON_DISC_MRW = 0x30010, + LIBHAL_STORAGE_ICON_DISC_MRWW = 0x30011, + LIBHAL_STORAGE_ICON_DISC_MO = 0x30012 +} LibHalStoragePolicyIcon; + +typedef struct { + LibHalStoragePolicyIcon icon; + const char *icon_path; +} LibHalStoragePolicyIconPair; + +LibHalStoragePolicy *libhal_storage_policy_new (void) LIBHAL_DEPRECATED; +void libhal_storage_policy_free (LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; + +void libhal_storage_policy_set_icon_path (LibHalStoragePolicy *policy, + LibHalStoragePolicyIcon icon, + const char *path) LIBHAL_DEPRECATED; + +void libhal_storage_policy_set_icon_mapping (LibHalStoragePolicy *policy, + LibHalStoragePolicyIconPair *pairs) LIBHAL_DEPRECATED; +const char *libhal_storage_policy_lookup_icon (LibHalStoragePolicy *policy, + LibHalStoragePolicyIcon icon) LIBHAL_DEPRECATED; + +typedef enum { + LIBHAL_DRIVE_BUS_UNKNOWN = 0x00, + LIBHAL_DRIVE_BUS_IDE = 0x01, + LIBHAL_DRIVE_BUS_SCSI = 0x02, + LIBHAL_DRIVE_BUS_USB = 0x03, + LIBHAL_DRIVE_BUS_IEEE1394 = 0x04, + LIBHAL_DRIVE_BUS_CCW = 0x05 +} LibHalDriveBus; + +typedef enum { + LIBHAL_DRIVE_TYPE_REMOVABLE_DISK = 0x00, + LIBHAL_DRIVE_TYPE_DISK = 0x01, + LIBHAL_DRIVE_TYPE_CDROM = 0x02, + LIBHAL_DRIVE_TYPE_FLOPPY = 0x03, + LIBHAL_DRIVE_TYPE_TAPE = 0x04, + LIBHAL_DRIVE_TYPE_COMPACT_FLASH = 0x05, + LIBHAL_DRIVE_TYPE_MEMORY_STICK = 0x06, + LIBHAL_DRIVE_TYPE_SMART_MEDIA = 0x07, + LIBHAL_DRIVE_TYPE_SD_MMC = 0x08, + LIBHAL_DRIVE_TYPE_CAMERA = 0x09, + LIBHAL_DRIVE_TYPE_PORTABLE_AUDIO_PLAYER = 0x0a, + LIBHAL_DRIVE_TYPE_ZIP = 0x0b, + LIBHAL_DRIVE_TYPE_JAZ = 0x0c, + LIBHAL_DRIVE_TYPE_FLASHKEY = 0x0d, + LIBHAL_DRIVE_TYPE_MO = 0x0e +} LibHalDriveType; + +typedef enum { + LIBHAL_DRIVE_CDROM_CAPS_CDROM = 0x00001, + LIBHAL_DRIVE_CDROM_CAPS_CDR = 0x00002, + LIBHAL_DRIVE_CDROM_CAPS_CDRW = 0x00004, + LIBHAL_DRIVE_CDROM_CAPS_DVDRAM = 0x00008, + LIBHAL_DRIVE_CDROM_CAPS_DVDROM = 0x00010, + LIBHAL_DRIVE_CDROM_CAPS_DVDR = 0x00020, + LIBHAL_DRIVE_CDROM_CAPS_DVDRW = 0x00040, + LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR = 0x00080, + LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW = 0x00100, + LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL = 0x00200, + LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRWDL = 0x00400, + LIBHAL_DRIVE_CDROM_CAPS_BDROM = 0x00800, + LIBHAL_DRIVE_CDROM_CAPS_BDR = 0x01000, + LIBHAL_DRIVE_CDROM_CAPS_BDRE = 0x02000, + LIBHAL_DRIVE_CDROM_CAPS_HDDVDROM = 0x04000, + LIBHAL_DRIVE_CDROM_CAPS_HDDVDR = 0x08000, + LIBHAL_DRIVE_CDROM_CAPS_HDDVDRW = 0x10000, + LIBHAL_DRIVE_CDROM_CAPS_MRW = 0x20000, + LIBHAL_DRIVE_CDROM_CAPS_MRWW = 0x40000, + LIBHAL_DRIVE_CDROM_CAPS_MO = 0x80000 +} LibHalDriveCdromCaps; + +LibHalDrive *libhal_drive_from_udi (LibHalContext *hal_ctx, + const char *udi); +LibHalDrive *libhal_drive_from_device_file (LibHalContext *hal_ctx, + const char *device_file); +void libhal_drive_free (LibHalDrive *drive); + +dbus_bool_t libhal_drive_is_hotpluggable (LibHalDrive *drive); +dbus_bool_t libhal_drive_uses_removable_media (LibHalDrive *drive); +dbus_bool_t libhal_drive_is_media_detected (LibHalDrive *drive); +dbus_bool_t libhal_drive_is_media_detection_automatic (LibHalDrive *drive); +dbus_uint64_t libhal_drive_get_size (LibHalDrive *drive); +dbus_uint64_t libhal_drive_get_media_size (LibHalDrive *drive); +const char *libhal_drive_get_partition_scheme (LibHalDrive *drive); +dbus_bool_t libhal_drive_no_partitions_hint (LibHalDrive *drive); +dbus_bool_t libhal_drive_requires_eject (LibHalDrive *drive); +LibHalDriveType libhal_drive_get_type (LibHalDrive *drive); +LibHalDriveBus libhal_drive_get_bus (LibHalDrive *drive); +LibHalDriveCdromCaps libhal_drive_get_cdrom_caps (LibHalDrive *drive); +unsigned int libhal_drive_get_device_major (LibHalDrive *drive); +unsigned int libhal_drive_get_device_minor (LibHalDrive *drive); +const char *libhal_drive_get_type_textual (LibHalDrive *drive); +const char *libhal_drive_get_device_file (LibHalDrive *drive); +const char *libhal_drive_get_udi (LibHalDrive *drive); +const char *libhal_drive_get_serial (LibHalDrive *drive); +const char *libhal_drive_get_firmware_version (LibHalDrive *drive); +const char *libhal_drive_get_model (LibHalDrive *drive); +const char *libhal_drive_get_vendor (LibHalDrive *drive); +const char *libhal_drive_get_physical_device_udi (LibHalDrive *drive); + +const char *libhal_drive_get_dedicated_icon_drive (LibHalDrive *drive); +const char *libhal_drive_get_dedicated_icon_volume (LibHalDrive *drive); + +char *libhal_drive_policy_compute_display_name (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +char *libhal_drive_policy_compute_icon_name (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; + +dbus_bool_t libhal_drive_policy_is_mountable (LibHalDrive *drive, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_drive_policy_get_desired_mount_point (LibHalDrive *drive, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_drive_policy_get_mount_options (LibHalDrive *drive, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_drive_policy_get_mount_fs (LibHalDrive *drive, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; + +char **libhal_drive_find_all_volumes (LibHalContext *hal_ctx, + LibHalDrive *drive, + int *num_volumes); + + +char *libhal_drive_policy_default_get_mount_root (LibHalContext *hal_ctx) LIBHAL_DEPRECATED; +dbus_bool_t libhal_drive_policy_default_use_managed_keyword (LibHalContext *hal_ctx) LIBHAL_DEPRECATED; +char *libhal_drive_policy_default_get_managed_keyword_primary (LibHalContext *hal_ctx) LIBHAL_DEPRECATED; +char *libhal_drive_policy_default_get_managed_keyword_secondary (LibHalContext *hal_ctx) LIBHAL_DEPRECATED; + + +typedef enum { + LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM, + LIBHAL_VOLUME_USAGE_PARTITION_TABLE, + LIBHAL_VOLUME_USAGE_RAID_MEMBER, + LIBHAL_VOLUME_USAGE_CRYPTO, + LIBHAL_VOLUME_USAGE_UNKNOWN, + LIBHAL_VOLUME_USAGE_OTHER +} LibHalVolumeUsage; + +typedef enum { + LIBHAL_VOLUME_DISC_TYPE_CDROM = 0x00, + LIBHAL_VOLUME_DISC_TYPE_CDR = 0x01, + LIBHAL_VOLUME_DISC_TYPE_CDRW = 0x02, + LIBHAL_VOLUME_DISC_TYPE_DVDROM = 0x03, + LIBHAL_VOLUME_DISC_TYPE_DVDRAM = 0x04, + LIBHAL_VOLUME_DISC_TYPE_DVDR = 0x05, + LIBHAL_VOLUME_DISC_TYPE_DVDRW = 0x06, + LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR = 0x07, + LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW = 0x08, + LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR_DL = 0x09, + LIBHAL_VOLUME_DISC_TYPE_BDROM = 0x0a, + LIBHAL_VOLUME_DISC_TYPE_BDR = 0x0b, + LIBHAL_VOLUME_DISC_TYPE_BDRE = 0x0c, + LIBHAL_VOLUME_DISC_TYPE_HDDVDROM = 0x0d, + LIBHAL_VOLUME_DISC_TYPE_HDDVDR = 0x0e, + LIBHAL_VOLUME_DISC_TYPE_HDDVDRW = 0x0f, + LIBHAL_VOLUME_DISC_TYPE_MO = 0x10, + LIBHAL_VOLUME_DISC_TYPE_DVDR_DL = 0x11 +} LibHalVolumeDiscType; + +LibHalVolume *libhal_volume_from_udi (LibHalContext *hal_ctx, + const char *udi); +LibHalVolume *libhal_volume_from_device_file (LibHalContext *hal_ctx, + const char *device_file); +LibHalVolume *libhal_volume_from_mount_point (LibHalContext *hal_ctx, + const char *mount_point); +void libhal_volume_free (LibHalVolume *volume); +dbus_uint64_t libhal_volume_get_size (LibHalVolume *volume); +dbus_uint64_t libhal_volume_get_disc_capacity (LibHalVolume *volume); + +const char *libhal_volume_get_udi (LibHalVolume *volume); +const char *libhal_volume_get_device_file (LibHalVolume *volume); +unsigned int libhal_volume_get_device_major (LibHalVolume *volume); +unsigned int libhal_volume_get_device_minor (LibHalVolume *volume); +const char *libhal_volume_get_fstype (LibHalVolume *volume); +const char *libhal_volume_get_fsversion (LibHalVolume *volume); +LibHalVolumeUsage libhal_volume_get_fsusage (LibHalVolume *volume); +dbus_bool_t libhal_volume_is_mounted (LibHalVolume *volume); +dbus_bool_t libhal_volume_is_mounted_read_only (LibHalVolume *volume); +dbus_bool_t libhal_volume_is_partition (LibHalVolume *volume); +dbus_bool_t libhal_volume_is_disc (LibHalVolume *volume); + +const char *libhal_volume_get_partition_scheme (LibHalVolume *volume); +const char *libhal_volume_get_partition_type (LibHalVolume *volume); +const char *libhal_volume_get_partition_label (LibHalVolume *volume); +const char *libhal_volume_get_partition_uuid (LibHalVolume *volume); +const char **libhal_volume_get_partition_flags (LibHalVolume *volume); +unsigned int libhal_volume_get_partition_number (LibHalVolume *volume); +dbus_uint64_t libhal_volume_get_partition_start_offset (LibHalVolume *volume); +dbus_uint64_t libhal_volume_get_partition_media_size (LibHalVolume *volume); + +const char *libhal_volume_get_label (LibHalVolume *volume); +const char *libhal_volume_get_mount_point (LibHalVolume *volume); +const char *libhal_volume_get_uuid (LibHalVolume *volume); +const char *libhal_volume_get_storage_device_udi (LibHalVolume *volume); + +const char *libhal_volume_crypto_get_backing_volume_udi (LibHalVolume *volume); +char *libhal_volume_crypto_get_clear_volume_udi (LibHalContext *hal_ctx, LibHalVolume *volume); + + +dbus_bool_t libhal_volume_disc_has_audio (LibHalVolume *volume); +dbus_bool_t libhal_volume_disc_has_data (LibHalVolume *volume); +dbus_bool_t libhal_volume_disc_is_blank (LibHalVolume *volume); +dbus_bool_t libhal_volume_disc_is_rewritable (LibHalVolume *volume); +dbus_bool_t libhal_volume_disc_is_appendable (LibHalVolume *volume); +LibHalVolumeDiscType libhal_volume_get_disc_type (LibHalVolume *volume); + +int libhal_volume_get_msdos_part_table_type (LibHalVolume *volume) LIBHAL_DEPRECATED; +dbus_uint64_t libhal_volume_get_msdos_part_table_start (LibHalVolume *volume) LIBHAL_DEPRECATED; +dbus_uint64_t libhal_volume_get_msdos_part_table_size (LibHalVolume *volume) LIBHAL_DEPRECATED; + + +dbus_bool_t libhal_volume_should_ignore (LibHalVolume *volume); + +char *libhal_volume_policy_compute_size_as_string (LibHalVolume *volume) LIBHAL_DEPRECATED; + +char *libhal_volume_policy_compute_display_name (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +char *libhal_volume_policy_compute_icon_name (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; + +dbus_bool_t libhal_volume_policy_should_be_visible (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy, + const char *target_mount_point) LIBHAL_DEPRECATED; + +dbus_bool_t libhal_volume_policy_is_mountable (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_volume_policy_get_desired_mount_point (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_volume_policy_get_mount_options (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; +const char *libhal_volume_policy_get_mount_fs (LibHalDrive *drive, + LibHalVolume *volume, + LibHalStoragePolicy *policy) LIBHAL_DEPRECATED; + + +#if defined(__cplusplus) +} +#endif + +#endif /* LIBHAL_STORAGE_H */ diff --git a/deps/libhal.c b/deps/libhal.c new file mode 100644 index 0000000..c9d9f74 --- /dev/null +++ b/deps/libhal.c @@ -0,0 +1,5228 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * libhal.c : HAL daemon C convenience library + * + * Copyright (C) 2003 David Zeuthen, + * Copyright (C) 2006 Sjoerd Simons, + * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "uthash.h" +#include "libhal.h" + +#ifdef ENABLE_NLS +# include +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +/* Stubs that do something close enough. */ +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) +# define N_(String) (String) +#endif + +/** + * LIBHAL_CHECK_PARAM_VALID: + * @_param_: the prameter to check for + * @_name_: the name of the prameter (for debug output) + * @_ret_: what to use for return value if the prameter is NULL + * + * Handy macro for checking whether a parameter is valid and not NULL. + */ +#define LIBHAL_CHECK_PARAM_VALID(_param_,_name_,_ret_) \ + do { \ + if (_param_ == NULL) { \ + fprintf (stderr, \ + "%s %d : invalid paramater. %s is NULL.\n", \ + __FILE__, __LINE__, _name_); \ + return _ret_; \ + } \ + } while(0) + +/** + * LIBHAL_CHECK_UDI_VALID: + * @_udi_: the UID to check for + * @_ret_: what to use for return value if udi is invalid + * + * Handy macro for checking whether a UID is valid and not NULL. + */ +#define LIBHAL_CHECK_UDI_VALID(_udi_,_ret_) \ + do { \ + if (_udi_ == NULL) { \ + fprintf (stderr, \ + "%s %d : invalid udi %s. udi is NULL.\n", \ + __FILE__, __LINE__, _udi_); \ + return _ret_; \ + } else { \ + if(strncmp(_udi_, "/org/freedesktop/Hal/devices/", 29) != 0) { \ + fprintf (stderr, \ + "%s %d : invalid udi: %s doesn't start" \ + "with '/org/freedesktop/Hal/devices/'. \n", \ + __FILE__, __LINE__, _udi_); \ + return _ret_; \ + } \ + } \ + } while(0) + +static char **libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements); + +static dbus_bool_t libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter); + + +/** + * libhal_free_string_array: + * @str_array: the array to be freed + * + * Frees a NULL-terminated array of strings. If passed NULL, does nothing. + */ +void +libhal_free_string_array (char **str_array) +{ + if (str_array != NULL) { + int i; + + for (i = 0; str_array[i] != NULL; i++) { + free (str_array[i]); + str_array[i] = NULL; + } + free (str_array); + str_array = NULL; + } +} + + +/** + * libhal_get_string_array_from_iter: + * @iter: the message iterator to extract the strings from + * @num_elements: pointer to an integer where to store number of elements (can be NULL) + * + * Creates a NULL terminated array of strings from a dbus message iterator. + * + * Returns: pointer to the string array + */ +static char ** +libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements) +{ + int count; + char **buffer; + char **t; + + count = 0; + buffer = (char **)malloc (sizeof (char *) * 8); + + if (buffer == NULL) + goto oom; + + buffer[0] = NULL; + while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING) { + const char *value; + char *str; + + if ((count % 8) == 0 && count != 0) { + t = realloc (buffer, sizeof (char *) * (count + 8)); + if (t == NULL) + goto oom; + else + buffer = t; + } + + dbus_message_iter_get_basic (iter, &value); + str = strdup (value); + if (str == NULL) + goto oom; + + buffer[count] = str; + + dbus_message_iter_next(iter); + count++; + } + + if ((count % 8) == 0) { + t = realloc (buffer, sizeof (char *) * (count + 1)); + if (t == NULL) + goto oom; + else + buffer = t; + } + + buffer[count] = NULL; + if (num_elements != NULL) + *num_elements = count; + return buffer; + +oom: + if (buffer != NULL) + free (buffer); + fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__); + return NULL; + +} + +/** + * libhal_free_string: + * @str: the nul-terminated sting to free + * + * Used to free strings returned by libhal. + */ +void +libhal_free_string (char *str) +{ + if (str != NULL) { + free (str); + str = NULL; + } +} + + +/** + * LibHalPropertySet: + * + * Represents a set of properties. Opaque; use the + * libhal_property_set_*() family of functions to access it. + */ +struct LibHalPropertySet_s { + LibHalProperty *properties; +}; + +/** + * LibHalProperty: + * + * Represents a property. Opaque. + */ +struct LibHalProperty_s { + LibHalPropertyType type; /**< Type of property */ + char *key; /**< ASCII string */ + + /** Possible values of the property */ + union { + char *str_value; /**< UTF-8 zero-terminated string */ + dbus_int32_t int_value; /**< 32-bit signed integer */ + dbus_uint64_t uint64_value; /**< 64-bit unsigned integer */ + double double_value; /**< IEEE754 double precision float */ + dbus_bool_t bool_value; /**< Truth value */ + char **strlist_value; /**< List of UTF-8 zero-terminated strings */ + } v; + + UT_hash_handle hh; /*makes this hashable*/ +}; + +/** + * LibHalContext: + * + * Context for connection to the HAL daemon. Opaque, use the + * libhal_ctx_*() family of functions to access it. + */ +struct LibHalContext_s { + DBusConnection *connection; /**< D-BUS connection */ + dbus_bool_t is_initialized; /**< Are we initialised */ + dbus_bool_t is_shutdown; /**< Have we been shutdown */ + dbus_bool_t cache_enabled; /**< Is the cache enabled */ + dbus_bool_t is_direct; /**< Whether the connection to hald is direct */ + + /** Device added */ + LibHalDeviceAdded device_added; + + /** Device removed */ + LibHalDeviceRemoved device_removed; + + /** Device got a new capability */ + LibHalDeviceNewCapability device_new_capability; + + /** Device got a new capability */ + LibHalDeviceLostCapability device_lost_capability; + + /** A property of a device changed */ + LibHalDevicePropertyModified device_property_modified; + + /** A non-continous event on the device occured */ + LibHalDeviceCondition device_condition; + + /** A global interface lock is acquired */ + LibHalGlobalInterfaceLockAcquired global_interface_lock_acquired; + + /** A global interface lock is released */ + LibHalGlobalInterfaceLockReleased global_interface_lock_released; + + /** An interface lock is acquired */ + LibHalInterfaceLockAcquired interface_lock_acquired; + + /** An interface lock is released */ + LibHalInterfaceLockReleased interface_lock_released; + + /** Singleton device added */ + LibHalSingletonDeviceAdded singleton_device_added; + + /** Singleton device removed*/ + LibHalSingletonDeviceRemoved singleton_device_removed; + + void *user_data; /**< User data */ +}; + +/** + * libhal_ctx_set_user_data: + * @ctx: the context for the connection to hald + * @user_data: user data + * + * Set user data for the context. + * + * Returns: TRUE if user data was successfully set, FALSE if otherwise + */ +dbus_bool_t +libhal_ctx_set_user_data(LibHalContext *ctx, void *user_data) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + ctx->user_data = user_data; + return TRUE; +} + +/** + * libhal_ctx_get_user_data: + * @ctx: the context for the connection to hald + * + * Get user data for the context. + * + * Returns: opaque pointer stored through libhal_ctx_set_user_data() or NULL if not set. + */ +void* +libhal_ctx_get_user_data(LibHalContext *ctx) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + return ctx->user_data; +} + + +/** + * libhal_property_fill_value_from_variant: + * @p: the property to fill in + * @var_iter: variant iterator to extract the value from + * + * Fills in the value for the LibHalProperty given a variant iterator. + * + * Returns: Whether the value was put in. + */ +static dbus_bool_t +libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter) +{ + DBusMessageIter iter_array; + + LIBHAL_CHECK_PARAM_VALID(p, "LibHalProperty *p", FALSE); + LIBHAL_CHECK_PARAM_VALID(var_iter, "DBusMessageIter *var_iter", FALSE); + + switch (p->type) { + case DBUS_TYPE_ARRAY: + if (dbus_message_iter_get_element_type (var_iter) != DBUS_TYPE_STRING) + return FALSE; + + dbus_message_iter_recurse (var_iter, &iter_array); + p->v.strlist_value = libhal_get_string_array_from_iter (&iter_array, NULL); + + p->type = LIBHAL_PROPERTY_TYPE_STRLIST; + + break; + case DBUS_TYPE_STRING: + { + const char *v; + + dbus_message_iter_get_basic (var_iter, &v); + + p->v.str_value = strdup (v); + if (p->v.str_value == NULL) + return FALSE; + p->type = LIBHAL_PROPERTY_TYPE_STRING; + + break; + } + case DBUS_TYPE_INT32: + { + dbus_int32_t v; + + dbus_message_iter_get_basic (var_iter, &v); + + p->v.int_value = v; + p->type = LIBHAL_PROPERTY_TYPE_INT32; + + break; + } + case DBUS_TYPE_UINT64: + { + dbus_uint64_t v; + + dbus_message_iter_get_basic (var_iter, &v); + + p->v.uint64_value = v; + p->type = LIBHAL_PROPERTY_TYPE_UINT64; + + break; + } + case DBUS_TYPE_DOUBLE: + { + double v; + + dbus_message_iter_get_basic (var_iter, &v); + + p->v.double_value = v; + p->type = LIBHAL_PROPERTY_TYPE_DOUBLE; + + break; + } + case DBUS_TYPE_BOOLEAN: + { + double v; + + dbus_message_iter_get_basic (var_iter, &v); + + p->v.double_value = v; + p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN; + + break; + } + default: + /** @todo report error */ + break; + } + + return TRUE; +} + +static LibHalPropertySet * +get_property_set (DBusMessageIter *iter) +{ + LibHalPropertySet *result; + DBusMessageIter dict_iter; + + result = malloc (sizeof (LibHalPropertySet)); + if (result == NULL) + goto oom; + +/* + result->properties = malloc(sizeof(LibHalProperty)*result->num_properties); + if( result->properties==NULL ) + { + /// @todo cleanup + return NULL; + } +*/ + + result->properties = NULL; + + if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_ARRAY && + dbus_message_iter_get_element_type (iter) != DBUS_TYPE_DICT_ENTRY) { + fprintf (stderr, "%s %d : error, expecting an array of dict entries\n", + __FILE__, __LINE__); + free (result); + return NULL; + } + + dbus_message_iter_recurse (iter, &dict_iter); + + while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY) + { + DBusMessageIter dict_entry_iter, var_iter; + const char *key; + LibHalProperty *p; + + dbus_message_iter_recurse (&dict_iter, &dict_entry_iter); + + dbus_message_iter_get_basic (&dict_entry_iter, &key); + + p = malloc (sizeof (LibHalProperty)); + if (p == NULL) + goto oom; + + p->key = strdup (key); + if (p->key == NULL) { + free (p); + goto oom; + } + + dbus_message_iter_next (&dict_entry_iter); + + dbus_message_iter_recurse (&dict_entry_iter, &var_iter); + + p->type = (LibHalPropertyType) dbus_message_iter_get_arg_type (&var_iter); + + if (!libhal_property_fill_value_from_variant (p, &var_iter)) { + free (p); + goto oom; + } + + HASH_ADD_KEYPTR (hh, result->properties, p->key, strlen (p->key), p); + + dbus_message_iter_next (&dict_iter); + } + + return result; + +oom: + if (result != NULL) + libhal_free_property_set (result); + + fprintf (stderr, + "%s %d : error allocating memory\n", + __FILE__, __LINE__); + + return NULL; +} + +/** + * libhal_device_get_all_properties: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Retrieve all the properties on a device. + * + * Returns: An object represent all properties. Must be freed with libhal_free_property_set(). + */ +LibHalPropertySet * +libhal_device_get_all_properties (LibHalContext *ctx, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter reply_iter; + LibHalPropertySet *result; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_UDI_VALID(udi, NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetAllProperties"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + fprintf (stderr, + "%s %d : %s\n", + __FILE__, __LINE__, error->message); + return NULL; + } + + if (reply == NULL) { + return NULL; + } + + dbus_message_iter_init (reply, &reply_iter); + + result = get_property_set (&reply_iter); + + dbus_message_unref (reply); + + return result; +} + +static int +key_sort (LibHalProperty *a, LibHalProperty *b) +{ + return strcmp (a->key, b->key); +} + +/** + * libhal_property_set_sort: + * @set: property-set to sort + * + * Sort all properties according to property name. + */ +void +libhal_property_set_sort (LibHalPropertySet *set) +{ + if (set == NULL) + return; + + HASH_SORT (set->properties, key_sort); +} + +/** + * libhal_free_property_set: + * @set: property-set to free + * + * Free a property set earlier obtained with libhal_device_get_all_properties(). + */ +void +libhal_free_property_set (LibHalPropertySet * set) +{ + LibHalProperty *p, *p_old; + + if (set == NULL) + return; + + for (p = set->properties; p != NULL;) { + HASH_DELETE (hh, set->properties, p); + free (p->key); + if (p->type == DBUS_TYPE_STRING) + free (p->v.str_value); + if (p->type == LIBHAL_PROPERTY_TYPE_STRLIST) + libhal_free_string_array (p->v.strlist_value); + p_old = p; + p = p->hh.next; + free (p_old); + } + free (set); +} + +/** + * libhal_property_set_get_num_elems: + * @set: property set to consider + * + * Get the number of properties in a property set. + * + * Returns: number of properties in given property set + */ +unsigned int +libhal_property_set_get_num_elems (LibHalPropertySet *set) +{ + unsigned int num_elems; + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", 0); + + num_elems = 0; + for (p = set->properties; p != NULL; p = p->hh.next) + num_elems++; + + return num_elems; +} + +static LibHalProperty * +property_set_lookup (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + + HASH_FIND_STR (set->properties, key, p); + return p; +} + +/** + * libhal_ps_get_type: + * @set: property set + * @key: name of property to inspect + * + * Get the type of a given property. + * + * Returns: the #LibHalPropertyType of the given property, + * LIBHAL_PROPERTY_TYPE_INVALID if property is not in the set + */ +LibHalPropertyType +libhal_ps_get_type (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", LIBHAL_PROPERTY_TYPE_INVALID); + LIBHAL_CHECK_PARAM_VALID(key, "*key", LIBHAL_PROPERTY_TYPE_INVALID); + + p = property_set_lookup (set, key); + if (p) return p->type; + else return LIBHAL_PROPERTY_TYPE_INVALID; +} + +/** + * libhal_ps_get_string: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type string. + * + * Returns: UTF8 nul-terminated string. This pointer is only valid + * until libhal_free_property_set() is invoked on the property set + * this property belongs to. NULL if property is not in the set or not a string + */ +const char * +libhal_ps_get_string (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_STRING) + return p->v.str_value; + else return NULL; +} + +/** + * libhal_ps_get_int: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type signed integer. + * + * Returns: property value (32-bit signed integer) + */ +dbus_int32_t +libhal_ps_get_int32 (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", 0); + LIBHAL_CHECK_PARAM_VALID(key, "*key", 0); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_INT32) + return p->v.int_value; + else return 0; +} + +/** + * libhal_ps_get_uint64: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type unsigned integer. + * + * Returns: property value (64-bit unsigned integer) + */ +dbus_uint64_t +libhal_ps_get_uint64 (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", 0); + LIBHAL_CHECK_PARAM_VALID(key, "*key", 0); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_UINT64) + return p->v.uint64_value; + else return 0; +} + +/** + * libhal_ps_get_double: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type double. + * + * Returns: property value (IEEE754 double precision float) + */ +double +libhal_ps_get_double (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", 0.0); + LIBHAL_CHECK_PARAM_VALID(key, "*key", 0.0); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_DOUBLE) + return p->v.double_value; + else return 0.0; +} + +/** + * libhal_ps_get_bool: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type bool. + * + * Returns: property value (bool) + */ +dbus_bool_t +libhal_ps_get_bool (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_BOOLEAN) + return p->v.bool_value; + else return FALSE; +} + +/** + * libhal_ps_get_strlist: + * @set: property set + * @key: name of property to inspect + * + * Get the value of a property of type string list. + * + * Returns: pointer to array of strings, this is owned by the property set + */ +const char *const * +libhal_ps_get_strlist (const LibHalPropertySet *set, const char *key) +{ + LibHalProperty *p; + + LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + + p = property_set_lookup (set, key); + if (p && p->type == LIBHAL_PROPERTY_TYPE_STRLIST) + return (const char *const *) p->v.strlist_value; + else return NULL; +} + + +/** + * libhal_psi_init: + * @iter: iterator object + * @set: property set to iterate over + * + * Initialize a property set iterator. + * + */ +void +libhal_psi_init (LibHalPropertySetIterator * iter, LibHalPropertySet * set) +{ + if (set == NULL) + return; + + iter->set = set; + iter->idx = -1; //deprecated + iter->cur_prop = set->properties; +} + + +/** + * libhal_psi_has_more: + * @iter: iterator object + * + * Determine whether there are more properties to iterate over. + * + * Returns: TRUE if there are more properties, FALSE otherwise. + */ +dbus_bool_t +libhal_psi_has_more (LibHalPropertySetIterator * iter) +{ + return (iter->cur_prop != NULL); +} + +/** + * libhal_psi_next: + * @iter: iterator object + * + * Advance iterator to next property. + */ +void +libhal_psi_next (LibHalPropertySetIterator * iter) +{ + iter->cur_prop = iter->cur_prop->hh.next; +} + +/** + * libhal_psi_get_type: + * @iter: iterator object + * + * Get type of property. + * + * Returns: the property type at the iterator's position + */ +LibHalPropertyType +libhal_psi_get_type (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->type; +} + +/** + * libhal_psi_get_key: + * @iter: iterator object + * + * Get the key of a property. + * + * Returns: ASCII nul-terminated string. This pointer is only valid + * until libhal_free_property_set() is invoked on the property set + * this property belongs to. + */ +char * +libhal_psi_get_key (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->key; +} + +/** + * libhal_psi_get_string: + * @iter: iterator object + * + * Get the value of a property of type string. + * + * Returns: UTF8 nul-terminated string. This pointer is only valid + * until libhal_free_property_set() is invoked on the property set + * this property belongs to. + */ +char * +libhal_psi_get_string (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.str_value; +} + +/** + * libhal_psi_get_int: + * @iter: iterator object + * + * Get the value of a property of type signed integer. + * + * Returns: property value (32-bit signed integer) + */ +dbus_int32_t +libhal_psi_get_int (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.int_value; +} + +/** + * libhal_psi_get_uint64: + * @iter: iterator object + * + * Get the value of a property of type unsigned integer. + * + * Returns: property value (64-bit unsigned integer) + */ +dbus_uint64_t +libhal_psi_get_uint64 (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.uint64_value; +} + +/** + * libhal_psi_get_double: + * @iter: iterator object + * + * Get the value of a property of type double. + * + * Returns: property value (IEEE754 double precision float) + */ +double +libhal_psi_get_double (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.double_value; +} + +/** + * libhal_psi_get_bool: + * @iter: iterator object + * + * Get the value of a property of type bool. + * + * Returns: property value (bool) + */ +dbus_bool_t +libhal_psi_get_bool (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.bool_value; +} + +/** + * libhal_psi_get_strlist: + * @iter: iterator object + * + * Get the value of a property of type string list. + * + * Returns: pointer to array of strings + */ +char ** +libhal_psi_get_strlist (LibHalPropertySetIterator * iter) +{ + return iter->cur_prop->v.strlist_value; +} + +static DBusHandlerResult +singleton_device_changed (LibHalContext *ctx, DBusConnection *connection, DBusMessage *msg, dbus_bool_t added) +{ + DBusMessage *reply; + DBusMessageIter iter; + LibHalPropertySet *set; + const char *udi; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + dbus_message_iter_init (msg, &iter); + + /* First should be the device UDI */ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + goto malformed; + + dbus_message_iter_get_basic (&iter, &udi); + + dbus_message_iter_next (&iter); + + /* then the property set*/ + set = get_property_set (&iter); + + if (!set) + goto malformed; + if (added) + (ctx->singleton_device_added)(ctx, udi, set); + else + (ctx->singleton_device_removed)(ctx, udi, set); + + libhal_free_property_set (set); + + reply = dbus_message_new_method_return (msg); + if (reply == NULL) + goto oom; + + if (!dbus_connection_send (connection, reply, NULL)) { + dbus_message_unref (reply); + goto oom; + } + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; + +malformed: + fprintf (stderr, "%s %d : singlton device changed message malformed\n", __FILE__, __LINE__); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +oom: + fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult +filter_func (DBusConnection * connection, + DBusMessage * message, void *user_data) +{ + const char *object_path; + DBusError error; + LibHalContext *ctx = (LibHalContext *) user_data; + + if (ctx->is_shutdown) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_error_init (&error); + + object_path = dbus_message_get_path (message); + + /*fprintf (stderr, "*** libhal filer_func: connection=%p obj_path=%s interface=%s method=%s\n", + connection, + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message)); + */ + + if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", + "DeviceAdded")) { + char *udi; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &udi, + DBUS_TYPE_INVALID)) { + if (ctx->device_added != NULL) { + ctx->device_added (ctx, udi); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", "DeviceRemoved")) { + char *udi; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &udi, + DBUS_TYPE_INVALID)) { + if (ctx->device_removed != NULL) { + ctx->device_removed (ctx, udi); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","NewCapability")) { + char *udi; + char *capability; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &udi, + DBUS_TYPE_STRING, &capability, + DBUS_TYPE_INVALID)) { + if (ctx->device_new_capability != NULL) { + ctx->device_new_capability (ctx, udi, capability); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","GlobalInterfaceLockAcquired")) { + char *lock_name; + char *lock_owner; + int num_locks; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &lock_name, + DBUS_TYPE_STRING, &lock_owner, + DBUS_TYPE_INT32, &num_locks, + DBUS_TYPE_INVALID)) { + if (ctx->global_interface_lock_acquired != NULL) { + ctx->global_interface_lock_acquired (ctx, lock_name, lock_owner, num_locks); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","GlobalInterfaceLockReleased")) { + char *lock_name; + char *lock_owner; + int num_locks; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &lock_name, + DBUS_TYPE_STRING, &lock_owner, + DBUS_TYPE_INT32, &num_locks, + DBUS_TYPE_INVALID)) { + if (ctx->global_interface_lock_released != NULL) { + ctx->global_interface_lock_released (ctx, lock_name, lock_owner, num_locks); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "Condition")) { + char *condition_name; + char *condition_detail; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &condition_name, + DBUS_TYPE_STRING, &condition_detail, + DBUS_TYPE_INVALID)) { + if (ctx->device_condition != NULL) { + ctx->device_condition (ctx, object_path, condition_name, condition_detail); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device","InterfaceLockAcquired")) { + char *lock_name; + char *lock_owner; + int num_locks; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &lock_name, + DBUS_TYPE_STRING, &lock_owner, + DBUS_TYPE_INT32, &num_locks, + DBUS_TYPE_INVALID)) { + if (ctx->interface_lock_acquired != NULL) { + ctx->interface_lock_acquired (ctx, object_path, lock_name, lock_owner, num_locks); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device","InterfaceLockReleased")) { + char *lock_name; + char *lock_owner; + int num_locks; + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &lock_name, + DBUS_TYPE_STRING, &lock_owner, + DBUS_TYPE_INT32, &num_locks, + DBUS_TYPE_INVALID)) { + if (ctx->interface_lock_released != NULL) { + ctx->interface_lock_released (ctx, object_path, lock_name, lock_owner, num_locks); + } + } else { + LIBHAL_FREE_DBUS_ERROR(&error); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "PropertyModified")) { + if (ctx->device_property_modified != NULL) { + int i; + char *key; + dbus_bool_t removed; + dbus_bool_t added; + int num_modifications; + DBusMessageIter iter; + DBusMessageIter iter_array; + + dbus_message_iter_init (message, &iter); + dbus_message_iter_get_basic (&iter, &num_modifications); + dbus_message_iter_next (&iter); + + dbus_message_iter_recurse (&iter, &iter_array); + + for (i = 0; i < num_modifications; i++) { + DBusMessageIter iter_struct; + + dbus_message_iter_recurse (&iter_array, &iter_struct); + + dbus_message_iter_get_basic (&iter_struct, &key); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &removed); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &added); + + ctx->device_property_modified (ctx, + object_path, + key, removed, + added); + + dbus_message_iter_next (&iter_array); + } + + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_method_call (message, + "org.freedesktop.Hal.SingletonAddon", + "DeviceAdded") && + strcmp (dbus_message_get_path (message), + "/org/freedesktop/Hal/SingletonAddon") == 0) { + return singleton_device_changed (ctx, connection, message, TRUE); + } else if (dbus_message_is_method_call (message, + "org.freedesktop.Hal.SingletonAddon", + "DeviceRemoved") && + strcmp (dbus_message_get_path (message), + "/org/freedesktop/Hal/SingletonAddon") == 0) { + return singleton_device_changed (ctx, connection, message, FALSE); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/** + * libhal_get_all_devices: + * @ctx: the context for the connection to hald + * @num_devices: the number of devices will be stored here + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get all devices in the Global Device List (GDL). + * + * Returns: An array of device identifiers terminated with NULL. It is + * the responsibility of the caller to free with + * libhal_free_string_array(). If an error occurs NULL is returned. + */ +char ** +libhal_get_all_devices (LibHalContext *ctx, int *num_devices, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter_array, reply_iter; + char **hal_device_names; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + + *num_devices = 0; + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "GetAllDevices"); + if (message == NULL) { + fprintf (stderr, "%s %d : Could not allocate D-BUS message\n", __FILE__, __LINE__); + return NULL; + } + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + + /* now analyze reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { + fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_recurse (&reply_iter, &iter_array); + + hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); + + dbus_message_unref (reply); + return hal_device_names; +} + +/** + * libhal_device_get_property_type: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Query a property type of a device. + * + * Returns: A LibHalPropertyType. LIBHAL_PROPERTY_TYPE_INVALID is + * return if the property doesn't exist. + */ +LibHalPropertyType +libhal_device_get_property_type (LibHalContext *ctx, const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + LibHalPropertyType type; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, LIBHAL_PROPERTY_TYPE_INVALID); /* or return NULL? */ + LIBHAL_CHECK_UDI_VALID(udi, LIBHAL_PROPERTY_TYPE_INVALID); + LIBHAL_CHECK_PARAM_VALID(key, "*key", LIBHAL_PROPERTY_TYPE_INVALID); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyType"); + if (message == NULL) { + fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__); + return LIBHAL_PROPERTY_TYPE_INVALID; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return LIBHAL_PROPERTY_TYPE_INVALID; + } + if (reply == NULL) { + return LIBHAL_PROPERTY_TYPE_INVALID; + } + + dbus_message_iter_init (reply, &reply_iter); + dbus_message_iter_get_basic (&reply_iter, &type); + + dbus_message_unref (reply); + return type; +} + +/** + * libhal_device_get_property_strlist: + * @ctx: the context for the connection to hald + * @udi: unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type string list. + * + * Returns: Array of pointers to UTF8 nul-terminated strings + * terminated by NULL. The caller is responsible for freeing this + * string array with the function libhal_free_string_array(). Returns + * NULL if the property didn't exist or we are OOM + */ +char ** +libhal_device_get_property_strlist (LibHalContext *ctx, const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, iter_array, reply_iter; + char **our_strings; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_UDI_VALID(udi, NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyStringList"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + /* now analyse reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { + fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_recurse (&reply_iter, &iter_array); + + our_strings = libhal_get_string_array_from_iter (&iter_array, NULL); + + dbus_message_unref (reply); + return our_strings; +} + +/** + * libhal_device_get_property_string: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: the name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type string. + * + * Returns: UTF8 nul-terminated string. The caller is responsible for + * freeing this string with the function libhal_free_string(). Returns + * NULL if the property didn't exist or we are OOM. + */ +char * +libhal_device_get_property_string (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + char *value; + char *dbus_str; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_UDI_VALID(udi, NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyString"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_STRING) { + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_get_basic (&reply_iter, &dbus_str); + value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL); + if (value == NULL) { + fprintf (stderr, "%s %d : error allocating memory\n", + __FILE__, __LINE__); + } + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_get_property_int: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type integer. + * + * Returns: Property value (32-bit signed integer) + */ +dbus_int32_t +libhal_device_get_property_int (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_int32_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1); + LIBHAL_CHECK_UDI_VALID(udi, -1); + LIBHAL_CHECK_PARAM_VALID(key, "*key", -1); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyInteger"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return -1; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return -1; + } + if (reply == NULL) { + return -1; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_INT32) { + fprintf (stderr, + "%s %d : property '%s' for device '%s' is not " + "of type integer\n", __FILE__, __LINE__, key, + udi); + dbus_message_unref (reply); + return -1; + } + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_get_property_uint64: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type signed integer. + * + * Returns: Property value (64-bit unsigned integer) + */ +dbus_uint64_t +libhal_device_get_property_uint64 (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_uint64_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1); + LIBHAL_CHECK_UDI_VALID(udi, -1); + LIBHAL_CHECK_PARAM_VALID(key, "*key", -1); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyInteger"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return -1; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return -1; + } + if (reply == NULL) { + return -1; + } + + dbus_message_iter_init (reply, &reply_iter); + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_UINT64) { + fprintf (stderr, + "%s %d : property '%s' for device '%s' is not " + "of type integer\n", __FILE__, __LINE__, key, + udi); + dbus_message_unref (reply); + return -1; + } + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_get_property_double: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type double. + * + * Returns: Property value (IEEE754 double precision float) + */ +double +libhal_device_get_property_double (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + double value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1.0); + LIBHAL_CHECK_UDI_VALID(udi, -1.0); + LIBHAL_CHECK_PARAM_VALID(key, "*key", -1.0); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyDouble"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return -1.0f; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return -1.0f; + } + if (reply == NULL) { + return -1.0f; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_DOUBLE) { + fprintf (stderr, + "%s %d : property '%s' for device '%s' is not " + "of type double\n", __FILE__, __LINE__, key, udi); + dbus_message_unref (reply); + return -1.0f; + } + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return (double) value; +} + +/** + * libhal_device_get_property_bool: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Get the value of a property of type bool. + * + * Returns: Property value (boolean) + */ +dbus_bool_t +libhal_device_get_property_bool (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_bool_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "GetPropertyBoolean"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_BOOLEAN) { + fprintf (stderr, + "%s %d : property '%s' for device '%s' is not " + "of type bool\n", __FILE__, __LINE__, key, udi); + dbus_message_unref (reply); + return FALSE; + } + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + + +/* generic helper */ +static dbus_bool_t +libhal_device_set_property_helper (LibHalContext *ctx, + const char *udi, + const char *key, + int type, + const char *str_value, + dbus_int32_t int_value, + dbus_uint64_t uint64_value, + double double_value, + dbus_bool_t bool_value, + DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + char *method_name = NULL; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + /** @todo sanity check incoming params */ + switch (type) { + case DBUS_TYPE_INVALID: + method_name = "RemoveProperty"; + break; + case DBUS_TYPE_STRING: + method_name = "SetPropertyString"; + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT64: + method_name = "SetPropertyInteger"; + break; + case DBUS_TYPE_DOUBLE: + method_name = "SetPropertyDouble"; + break; + case DBUS_TYPE_BOOLEAN: + method_name = "SetPropertyBoolean"; + break; + + default: + /* cannot happen; is not callable from outside this file */ + break; + } + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + method_name); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + switch (type) { + case DBUS_TYPE_STRING: + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str_value); + break; + case DBUS_TYPE_INT32: + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &int_value); + break; + case DBUS_TYPE_UINT64: + dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &uint64_value); + break; + case DBUS_TYPE_DOUBLE: + dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &double_value); + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bool_value); + break; + } + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + + return TRUE; +} + +/** + * libhal_device_set_property_string: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value of the property; a UTF8 string + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Set a property of type string. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_set_property_string (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + LIBHAL_CHECK_PARAM_VALID(value, "*value", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, + DBUS_TYPE_STRING, + value, 0, 0, 0.0f, FALSE, error); +} + +/** + * libhal_device_set_property_int: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Set a property of type signed integer. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_set_property_int (LibHalContext *ctx, const char *udi, + const char *key, dbus_int32_t value, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, + DBUS_TYPE_INT32, + NULL, value, 0, 0.0f, FALSE, error); +} + +/** + * libhal_device_set_property_uint64: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Set a property of type unsigned integer. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_set_property_uint64 (LibHalContext *ctx, const char *udi, + const char *key, dbus_uint64_t value, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, + DBUS_TYPE_UINT64, + NULL, 0, value, 0.0f, FALSE, error); +} + +/** + * libhal_device_set_property_double: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Set a property of type double. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_set_property_double (LibHalContext *ctx, const char *udi, + const char *key, double value, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, + DBUS_TYPE_DOUBLE, + NULL, 0, 0, value, FALSE, error); +} + +/** + * libhal_device_set_property_bool: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Set a property of type bool. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_set_property_bool (LibHalContext *ctx, const char *udi, + const char *key, dbus_bool_t value, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, + DBUS_TYPE_BOOLEAN, + NULL, 0, 0, 0.0f, value, error); +} + + +/** + * libhal_device_remove_property: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Remove a property. + * + * Returns: TRUE if the property was set, FALSE if the device didn't + * exist + */ +dbus_bool_t +libhal_device_remove_property (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + return libhal_device_set_property_helper (ctx, udi, key, DBUS_TYPE_INVALID, + /* DBUS_TYPE_INVALID means remove */ + NULL, 0, 0, 0.0f, FALSE, error); +} + +/** + * libhal_device_property_strlist_append: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value to append to property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Append to a property of type strlist. + * + * Returns: TRUE if the value was appended, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_property_strlist_append (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + LIBHAL_CHECK_PARAM_VALID(value, "*value", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "StringListAppend"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_property_strlist_prepend: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: value to prepend to property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Prepend to a property of type strlist. + * + * Returns: TRUE if the value was prepended, FALSE if the device + * didn't exist or the property had a different type. + */ +dbus_bool_t +libhal_device_property_strlist_prepend (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + LIBHAL_CHECK_PARAM_VALID(value, "*value", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "StringListPrepend"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_property_strlist_remove_index: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @idx: index of string to remove in the strlist + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Remove a specified string from a property of type strlist. + * + * Returns: TRUE if the string was removed, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_property_strlist_remove_index (LibHalContext *ctx, + const char *udi, + const char *key, + unsigned int idx, + DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "StringListRemoveIndex"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &idx); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_property_strlist_remove: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @key: name of the property + * @value: the string to remove + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Remove a specified string from a property of type strlist. + * + * Returns: TRUE if the string was removed, FALSE if the device didn't + * exist or the property had a different type. + */ +dbus_bool_t +libhal_device_property_strlist_remove (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + LIBHAL_CHECK_PARAM_VALID(value, "*value", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "StringListRemove"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + + +/** + * libhal_device_lock: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @reason_to_lock: a user-presentable reason why the device is locked. + * @reason_why_locked: a pointer to store the reason why the device cannot be locked on failure, or NULL + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Take an advisory lock on the device. + * + * Returns: TRUE if the lock was obtained, FALSE otherwise + */ +dbus_bool_t +libhal_device_lock (LibHalContext *ctx, + const char *udi, + const char *reason_to_lock, + char **reason_why_locked, DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + if (reason_why_locked != NULL) + *reason_why_locked = NULL; + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "Lock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reason_to_lock); + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + if (strcmp (error->name, + "org.freedesktop.Hal.DeviceAlreadyLocked") == 0) { + if (reason_why_locked != NULL) { + *reason_why_locked = + dbus_malloc0 (strlen (error->message) + 1); + if (*reason_why_locked == NULL) + return FALSE; + strcpy (*reason_why_locked, error->message); + } + } + + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + + return TRUE; +} + +/** + * libhal_device_unlock: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Release an advisory lock on the device. + * + * Returns: TRUE if the device was successfully unlocked, + * FALSE otherwise + */ +dbus_bool_t +libhal_device_unlock (LibHalContext *ctx, + const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "Unlock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + + return TRUE; +} + + +/** + * libhal_new_device: + * @ctx: the context for the connection to hald + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Create a new device object which will be hidden from applications + * until the CommitToGdl(), ie. libhal_device_commit_to_gdl(), method + * is called. Note that the program invoking this method needs to run + * with super user privileges. + * + * Returns: Temporary device unique id or NULL if there was a + * problem. This string must be freed by the caller. + */ +char * +libhal_new_device (LibHalContext *ctx, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter reply_iter; + char *value; + char *dbus_str; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "NewDevice"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_STRING) { + fprintf (stderr, + "%s %d : expected a string in reply to NewDevice\n", + __FILE__, __LINE__); + dbus_message_unref (reply); + return NULL; + } + + dbus_message_iter_get_basic (&reply_iter, &dbus_str); + value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL); + if (value == NULL) { + fprintf (stderr, "%s %d : error allocating memory\n", + __FILE__, __LINE__); + } + + dbus_message_unref (reply); + return value; +} + + +/** + * libhal_device_commit_to_gdl: + * @ctx: the context for the connection to hald + * @temp_udi: the temporary unique device id as returned by libhal_new_device() + * @udi: the new unique device id. + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * When a hidden device has been built using the NewDevice method, + * ie. libhal_new_device(), and the org.freedesktop.Hal.Device + * interface this function will commit it to the global device list. + * + * This means that the device object will be visible to applications + * and the HAL daemon will possibly attempt to boot the device + * (depending on the property RequireEnable). + * + * Note that the program invoking this method needs to run with super + * user privileges. + * + * Returns: FALSE if the given unique device id is already in use. + */ +dbus_bool_t +libhal_device_commit_to_gdl (LibHalContext *ctx, + const char *temp_udi, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(temp_udi, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "CommitToGdl"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &temp_udi); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_remove_device: + * @ctx: the context for the connection to hald + * @udi: the Unique device id. + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * This method can be invoked when a device is removed. The HAL daemon + * will shut down the device. Note that the device may still be in the + * device list if the Persistent property is set to true. + * + * Note that the program invoking this method needs to run with super + * user privileges. + * + * Returns: TRUE if the device was removed, FALSE otherwise + */ +dbus_bool_t +libhal_remove_device (LibHalContext *ctx, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "Remove"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_exists: + * @ctx: the context for the connection to hald + * @udi: the Unique device id. + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Determine if a device exists. + * + * Returns: TRUE if the device exists + */ +dbus_bool_t +libhal_device_exists (LibHalContext *ctx, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_bool_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "DeviceExists"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyze reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { + fprintf (stderr, + "%s %d : expected a bool in reply to DeviceExists\n", + __FILE__, __LINE__); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_property_exists: + * @ctx: the context for the connection to hald + * @udi: the Unique device id. + * @key: name of the property + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Determine if a property on a device exists. + * + * Returns: TRUE if the device exists, FALSE otherwise + */ +dbus_bool_t +libhal_device_property_exists (LibHalContext *ctx, + const char *udi, const char *key, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_bool_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "PropertyExists"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_iter_init (reply, &reply_iter); + + /* now analyse reply */ + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { + fprintf (stderr, "%s %d : expected a bool in reply to " + "PropertyExists\n", __FILE__, __LINE__); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_merge_properties: + * @ctx: the context for the connection to hald + * @target_udi: the Unique device id of target device to merge to + * @source_udi: the Unique device id of device to merge from + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Merge properties from one device to another. + * + * Returns: TRUE if the properties were merged, FALSE otherwise + */ +dbus_bool_t +libhal_merge_properties (LibHalContext *ctx, + const char *target_udi, const char *source_udi, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(target_udi, FALSE); + LIBHAL_CHECK_UDI_VALID(source_udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "MergeProperties"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &target_udi); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &source_udi); + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_matches: + * @ctx: the context for the connection to hald + * @udi1: the Unique Device Id for device 1 + * @udi2: the Unique Device Id for device 2 + * @property_namespace: the namespace for set of devices, e.g. "usb" + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Check a set of properties for two devices matches. + * + * Checks that all properties where keys, starting with a given value + * (namespace), of the first device is in the second device and that + * they got the same value and type. + * + * Note that the other inclusion isn't tested, so there could be + * properties (from the given namespace) in the second device not + * present in the first device. + * + * Returns: TRUE if all properties starting with the given namespace + * parameter from one device is in the other and have the same value. + */ +dbus_bool_t +libhal_device_matches (LibHalContext *ctx, + const char *udi1, const char *udi2, + const char *property_namespace, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, reply_iter; + dbus_bool_t value; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi1, FALSE); + LIBHAL_CHECK_UDI_VALID(udi2, FALSE); + LIBHAL_CHECK_PARAM_VALID(property_namespace, "*property_namespace", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "DeviceMatches"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi1); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi2); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, property_namespace); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + /* now analyse reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { + fprintf (stderr, + "%s %d : expected a bool in reply to DeviceMatches\n", + __FILE__, __LINE__); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_iter_get_basic (&reply_iter, &value); + + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_print: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Print a device to stdout; useful for debugging. + * + * Returns: TRUE if device's information could be obtained, FALSE otherwise + */ +dbus_bool_t +libhal_device_print (LibHalContext *ctx, const char *udi, DBusError *error) +{ + int type; + char *key; + LibHalPropertySet *pset; + LibHalPropertySetIterator i; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + printf ("device_id = %s\n", udi); + + if ((pset = libhal_device_get_all_properties (ctx, udi, error)) == NULL) + return FALSE; + + for (libhal_psi_init (&i, pset); libhal_psi_has_more (&i); + libhal_psi_next (&i)) { + type = libhal_psi_get_type (&i); + key = libhal_psi_get_key (&i); + + switch (type) { + case LIBHAL_PROPERTY_TYPE_STRING: + printf (" %s = '%s' (string)\n", key, + libhal_psi_get_string (&i)); + break; + case LIBHAL_PROPERTY_TYPE_INT32: + printf (" %s = %d = 0x%x (int)\n", key, + libhal_psi_get_int (&i), + libhal_psi_get_int (&i)); + break; + case LIBHAL_PROPERTY_TYPE_UINT64: + printf (" %s = %llu = 0x%llx (uint64)\n", key, + (long long unsigned int) libhal_psi_get_uint64 (&i), + (long long unsigned int) libhal_psi_get_uint64 (&i)); + break; + case LIBHAL_PROPERTY_TYPE_BOOLEAN: + printf (" %s = %s (bool)\n", key, + (libhal_psi_get_bool (&i) ? "true" : + "false")); + break; + case LIBHAL_PROPERTY_TYPE_DOUBLE: + printf (" %s = %g (double)\n", key, + libhal_psi_get_double (&i)); + break; + case LIBHAL_PROPERTY_TYPE_STRLIST: + { + unsigned int j; + char **str_list; + + str_list = libhal_psi_get_strlist (&i); + printf (" %s = [", key); + for (j = 0; str_list[j] != NULL; j++) { + printf ("'%s'", str_list[j]); + if (str_list[j+1] != NULL) + printf (", "); + } + printf ("] (string list)\n"); + + break; + } + default: + printf (" *** unknown type for key %s\n", key); + break; + } + } + + libhal_free_property_set (pset); + + return TRUE; +} + +/** + * libhal_manager_find_device_string_match: + * @ctx: the context for the connection to hald + * @key: name of the property + * @value: the value to match + * @num_devices: pointer to store number of devices + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Find a device in the GDL where a single string property matches a + * given value. + * + * Returns: UDI of devices; free with libhal_free_string_array() + */ +char ** +libhal_manager_find_device_string_match (LibHalContext *ctx, + const char *key, + const char *value, int *num_devices, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, iter_array, reply_iter; + char **hal_device_names; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL); + LIBHAL_CHECK_PARAM_VALID(value, "*value", NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "FindDeviceStringMatch"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + /* now analyse reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { + fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_recurse (&reply_iter, &iter_array); + + hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); + + dbus_message_unref (reply); + return hal_device_names; +} + + +/** + * libhal_device_add_capability: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @capability: the capability name to add + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Assign a capability to a device. + * + * Returns: TRUE if the capability was added, FALSE if the device didn't exist + */ +dbus_bool_t +libhal_device_add_capability (LibHalContext *ctx, + const char *udi, const char *capability, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(capability, "*capability", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "AddCapability"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability); + + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_query_capability: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @capability: the capability name + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Check if a device has a capability. The result is undefined if the + * device doesn't exist. + * + * Returns: TRUE if the device has the capability, otherwise FALSE + */ +dbus_bool_t +libhal_device_query_capability (LibHalContext *ctx, const char *udi, const char *capability, DBusError *error) +{ + char **caps; + unsigned int i; + dbus_bool_t ret; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(capability, "*capability", FALSE); + + ret = FALSE; + + caps = libhal_device_get_property_strlist (ctx, udi, "info.capabilities", error); + if (caps != NULL) { + for (i = 0; caps[i] != NULL; i++) { + if (strcmp (caps[i], capability) == 0) { + ret = TRUE; + break; + } + } + libhal_free_string_array (caps); + } + + return ret; +} + +/** + * libhal_find_device_by_capability: + * @ctx: the context for the connection to hald + * @capability: the capability name + * @num_devices: pointer to store number of devices + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Find devices with a given capability. + * + * Returns: UDI of devices; free with libhal_free_string_array() + */ +char ** +libhal_find_device_by_capability (LibHalContext *ctx, + const char *capability, int *num_devices, DBusError *error) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, iter_array, reply_iter; + char **hal_device_names; + DBusError _error; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_PARAM_VALID(capability, "*capability", NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "FindDeviceByCapability"); + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability); + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) { + return NULL; + } + /* now analyse reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { + fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_recurse (&reply_iter, &iter_array); + + hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices); + + dbus_message_unref (reply); + return hal_device_names; +} + +/** + * libhal_device_property_watch_all: + * @ctx: the context for the connection to hald + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Watch all devices, ie. the device_property_changed callback is + * invoked when the properties on any device changes. + * + * Returns: TRUE only if the operation succeeded + */ +dbus_bool_t +libhal_device_property_watch_all (LibHalContext *ctx, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + dbus_bus_add_match (ctx->connection, + "type='signal'," + "interface='org.freedesktop.Hal.Device'," + "sender='org.freedesktop.Hal'", error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + return TRUE; +} + + +dbus_bool_t +libhal_device_property_remove_watch_all (LibHalContext *ctx, DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + dbus_bus_remove_match (ctx->connection, + "type='signal'," + "interface='org.freedesktop.Hal.Device'," + "sender='org.freedesktop.Hal'", error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + return TRUE; +} + + +/** + * libhal_device_add_property_watch: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Add a watch on a device, so the device_property_changed callback is + * invoked when the properties on the given device changes. + * + * The application itself is responsible for deleting the watch, using + * libhal_device_remove_property_watch, if the device is removed. + * + * Returns: TRUE only if the operation succeeded + */ +dbus_bool_t +libhal_device_add_property_watch (LibHalContext *ctx, const char *udi, DBusError *error) +{ + char buf[512]; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + snprintf (buf, 512, + "type='signal'," + "interface='org.freedesktop.Hal.Device'," + "sender='org.freedesktop.Hal'," "path=%s", udi); + + dbus_bus_add_match (ctx->connection, buf, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + return TRUE; +} + + +/** + * libhal_device_remove_property_watch: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Remove a watch on a device. + * + * Returns: TRUE only if the operation succeeded + */ +dbus_bool_t +libhal_device_remove_property_watch (LibHalContext *ctx, const char *udi, DBusError *error) +{ + char buf[512]; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + snprintf (buf, 512, + "type='signal'," + "interface='org.freedesktop.Hal.Device'," + "sender='org.freedesktop.Hal'," "path=%s", udi); + + dbus_bus_remove_match (ctx->connection, buf, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + return TRUE; +} + + +/** + * libhal_ctx_new: + * + * Create a new LibHalContext + * + * Returns: a new uninitialized LibHalContext object + */ +LibHalContext * +libhal_ctx_new (void) +{ + LibHalContext *ctx; + + ctx = calloc (1, sizeof (LibHalContext)); + if (ctx == NULL) { + fprintf (stderr, + "%s %d : Failed to allocate %lu bytes\n", + __FILE__, __LINE__, (unsigned long) sizeof (LibHalContext)); + return NULL; + } + + ctx->is_initialized = FALSE; + ctx->is_shutdown = FALSE; + ctx->connection = NULL; + ctx->is_direct = FALSE; + + return ctx; +} + +/** + * libhal_ctx_set_cache: + * @ctx: context to enable/disable cache for + * @use_cache: whether or not to use cache + * + * Enable or disable caching. Note: Caching is not actually + * implemented yet. + * + * Returns: TRUE if cache was successfully enabled/disabled, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_cache (LibHalContext *ctx, dbus_bool_t use_cache) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->cache_enabled = use_cache; + return TRUE; +} + +/** + * libhal_ctx_set_dbus_connection: + * @ctx: context to set connection for + * @conn: DBus connection to use + * + * Set DBus connection to use to talk to hald. + * + * Returns: TRUE if connection was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_dbus_connection (LibHalContext *ctx, DBusConnection *conn) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + if (conn == NULL) + return FALSE; + + ctx->connection = conn; + return TRUE; +} + +/** + * libhal_ctx_get_dbus_connection: + * @ctx: context to get connection for + * + * Get DBus connection used for talking to hald. + * + * Returns: DBus connection to use or NULL + */ +DBusConnection * +libhal_ctx_get_dbus_connection (LibHalContext *ctx) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + + return ctx->connection; +} + + +/** + * libhal_ctx_init: + * @ctx: Context for connection to hald (D-BUS connection should be set with libhal_ctx_set_dbus_connection) + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Initialize the connection to hald. + * + * Returns: TRUE if initialization succeeds, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_init (LibHalContext *ctx, DBusError *error) +{ + DBusError _error; + dbus_bool_t hald_exists; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + if (ctx->connection == NULL) + return FALSE; + + dbus_error_init (&_error); + hald_exists = dbus_bus_name_has_owner (ctx->connection, "org.freedesktop.Hal", &_error); + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + + if (!hald_exists) { + return FALSE; + } + + + if (!dbus_connection_add_filter (ctx->connection, filter_func, ctx, NULL)) { + return FALSE; + } + + dbus_bus_add_match (ctx->connection, + "type='signal'," + "interface='org.freedesktop.Hal.Manager'," + "sender='org.freedesktop.Hal'," + "path='/org/freedesktop/Hal/Manager'", &_error); + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + ctx->is_initialized = TRUE; + ctx->is_direct = FALSE; + + return TRUE; +} + +/** + * libhal_ctx_init_direct: + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Create an already initialized connection to hald. This function should only be used by HAL helpers. + * + * Returns: A pointer to an already initialized LibHalContext + */ +LibHalContext * +libhal_ctx_init_direct (DBusError *error) +{ + char *hald_addr; + LibHalContext *ctx; + DBusError _error; + + ctx = libhal_ctx_new (); + if (ctx == NULL) + goto out; + + if (((hald_addr = getenv ("HALD_DIRECT_ADDR"))) == NULL) { + libhal_ctx_free (ctx); + ctx = NULL; + goto out; + } + + dbus_error_init (&_error); + ctx->connection = dbus_connection_open (hald_addr, &_error); + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + libhal_ctx_free (ctx); + ctx = NULL; + goto out; + } + + if (!dbus_connection_add_filter (ctx->connection, filter_func, ctx, NULL)) { + libhal_ctx_free (ctx); + ctx = NULL; + goto out; + } + + + ctx->is_initialized = TRUE; + ctx->is_direct = TRUE; + +out: + return ctx; +} + +/** + * libhal_ctx_shutdown: + * @ctx: the context for the connection to hald + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Shut down a connection to hald. + * + * Returns: TRUE if connection successfully shut down, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_shutdown (LibHalContext *ctx, DBusError *error) +{ + DBusError myerror; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + if (ctx->is_direct) { + /* for some reason dbus_connection_set_exit_on_disconnect doesn't work yet so don't unref */ + /*dbus_connection_unref (ctx->connection);*/ + } else { + dbus_error_init (&myerror); + dbus_bus_remove_match (ctx->connection, + "type='signal'," + "interface='org.freedesktop.Hal.Manager'," + "sender='org.freedesktop.Hal'," + "path='/org/freedesktop/Hal/Manager'", &myerror); + dbus_move_error (&myerror, error); + if (error != NULL && dbus_error_is_set (error)) { + fprintf (stderr, "%s %d : Error unsubscribing to signals, error=%s\n", + __FILE__, __LINE__, error->message); + /** @todo clean up */ + } + + /* TODO: remove other matches */ + + dbus_connection_remove_filter (ctx->connection, filter_func, ctx); + } + + ctx->is_initialized = FALSE; + + return TRUE; +} + +/** + * libhal_ctx_free: + * @ctx: pointer to a LibHalContext + * + * Free a LibHalContext resource. + * + * Returns: TRUE + */ +dbus_bool_t +libhal_ctx_free (LibHalContext *ctx) +{ + free (ctx); + return TRUE; +} + +/** + * libhal_ctx_set_device_added: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device is added + * + * Set the callback for when a device is added + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_added (LibHalContext *ctx, LibHalDeviceAdded callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_added = callback; + return TRUE; +} + +/** + * libhal_ctx_set_device_removed: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device is removed + * + * Set the callback for when a device is removed. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_removed (LibHalContext *ctx, LibHalDeviceRemoved callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_removed = callback; + return TRUE; +} + +/** + * libhal_ctx_set_device_new_capability: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device gains a new capability + * + * Set the callback for when a device gains a new capability. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_new_capability (LibHalContext *ctx, LibHalDeviceNewCapability callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_new_capability = callback; + return TRUE; +} + +/** + * libhal_ctx_set_device_lost_capability: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device loses a capability + * + * Set the callback for when a device loses a capability + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_lost_capability (LibHalContext *ctx, LibHalDeviceLostCapability callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_lost_capability = callback; + return TRUE; +} + +/** + * libhal_ctx_set_device_property_modified: + * @ctx: the context for the connection to hald + * @callback: the function to call when a property is modified on a device + * + * Set the callback for when a property is modified on a device. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibHalDevicePropertyModified callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_property_modified = callback; + return TRUE; +} + +/** + * libhal_ctx_set_device_condition: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device emits a condition + * + * Set the callback for when a device emits a condition + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->device_condition = callback; + return TRUE; +} + +/** + * libhal_ctx_set_singleton_device_added: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device emits a condition + * + * Set the callback for when a singleton should handle a new device + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_singleton_device_added (LibHalContext *ctx, LibHalSingletonDeviceAdded callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->singleton_device_added = callback; + return TRUE; +} + +/** + * libhal_ctx_set_singleton_device_removed: + * @ctx: the context for the connection to hald + * @callback: the function to call when a device emits a condition + * + * Set the callback for when a singleton should discard a device + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_singleton_device_removed (LibHalContext *ctx, LibHalSingletonDeviceRemoved callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + + ctx->singleton_device_removed = callback; + return TRUE; +} + +/** + * libhal_string_array_length: + * @str_array: array of strings to consider + * + * Get the length of an array of strings. + * + * Returns: Number of strings in array + */ +unsigned int +libhal_string_array_length (char **str_array) +{ + unsigned int i; + + if (str_array == NULL) + return 0; + + for (i = 0; str_array[i] != NULL; i++) + ; + + return i; +} + + +/** + * libhal_device_rescan: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * TODO document me. + * + * Returns: Whether the operation succeeded + */ +dbus_bool_t +libhal_device_rescan (LibHalContext *ctx, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessageIter reply_iter; + DBusMessage *reply; + dbus_bool_t result; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device", + "Rescan"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + return FALSE; + } + dbus_message_iter_get_basic (&reply_iter, &result); + + dbus_message_unref (reply); + + return result; +} + +/** + * libhal_device_reprobe: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * TODO document me. + * + * Returns: Whether the operation succeeded + */ +dbus_bool_t +libhal_device_reprobe (LibHalContext *ctx, const char *udi, DBusError *error) +{ + DBusMessage *message; + DBusMessageIter reply_iter; + DBusMessage *reply; + dbus_bool_t result; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "Reprobe"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + return FALSE; + } + dbus_message_iter_get_basic (&reply_iter, &result); + + dbus_message_unref (reply); + + return result; +} + +/** + * libhal_device_emit_condition: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @condition_name: user-readable name of condition + * @condition_details: user-readable details of condition + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Emit a condition from a device. Can only be used from hald helpers. + * + * Returns: TRUE if condition successfully emitted, + * FALSE otherwise + */ +dbus_bool_t libhal_device_emit_condition (LibHalContext *ctx, + const char *udi, + const char *condition_name, + const char *condition_details, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessageIter reply_iter; + DBusMessage *reply; + dbus_bool_t result; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(condition_name, "*condition_name", FALSE); + LIBHAL_CHECK_PARAM_VALID(condition_details, "*condition_details", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "EmitCondition"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_details); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + fprintf (stderr, + "%s %d : Failure sending D-BUS message: %s: %s\n", + __FILE__, __LINE__, error->name, error->message); + return FALSE; + } + + if (reply == NULL) { + fprintf (stderr, + "%s %d : Got no reply\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + fprintf (stderr, + "%s %d : Malformed reply\n", + __FILE__, __LINE__); + return FALSE; + } + dbus_message_iter_get_basic (&reply_iter, &result); + + dbus_message_unref (reply); + + return result; +} + +static dbus_bool_t +addon_is_ready(LibHalContext *ctx, const char *identifier, + dbus_bool_t singleton, DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_PARAM_VALID(identifier, "*identifier", FALSE); + + if (singleton) { + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "SingletonAddonIsReady"); + } else { + message = dbus_message_new_method_call ("org.freedesktop.Hal", + identifier, + "org.freedesktop.Hal.Device", + "AddonIsReady"); + } + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &identifier); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + return TRUE; +} + + +/** + * libhal_device_addon_is_ready: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id this addon is handling + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * HAL addon's must call this method when they are done initializing the device object. The HAL + * daemon will wait for all addon's to call this. + * + * Can only be used from hald helpers. + * + * Returns: TRUE if the HAL daemon received the message, FALSE otherwise + */ +dbus_bool_t +libhal_device_addon_is_ready (LibHalContext *ctx, + const char *udi, + DBusError *error) +{ + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + + return addon_is_ready (ctx, udi, FALSE, error); +} + +/** + * libhal_device_singleton_addon_is_ready: + * @ctx: the context for the connection to hald + * @command_line: commandline singleton was started with + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * HAL singleton addon's must call this method when they are done initializing the device object. The HAL + * daemon will wait for all addon's to call this. + * + * Can only be used from hald helpers. + * + * Returns: TRUE if the HAL daemon received the message, FALSE otherwise + */ +dbus_bool_t +libhal_device_singleton_addon_is_ready (LibHalContext *ctx, + const char *command_line, + DBusError *error) +{ + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_PARAM_VALID(command_line, "*command_line", FALSE); + + return addon_is_ready (ctx, command_line, TRUE, error); +} + + +/** + * libhal_device_claim_interface: + * @ctx: the context for the connection to hald + * @udi: the Unique Device Id + * @interface_name: Name of interface to claim, e.g. org.freedesktop.Hal.Device.FoobarKindOfThing + * @introspection_xml: Introspection XML containing what would be inside the interface XML tag + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Claim an interface for a device. All messages to this interface + * will be forwarded to the helper. Can only be used from hald + * helpers. + * + * Returns: TRUE if interface was claimed, FALSE otherwise + */ +dbus_bool_t +libhal_device_claim_interface (LibHalContext *ctx, + const char *udi, + const char *interface_name, + const char *introspection_xml, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessageIter reply_iter; + DBusMessage *reply; + dbus_bool_t result; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(interface_name, "*interface_name", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "ClaimInterface"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &introspection_xml); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != + DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + return FALSE; + } + dbus_message_iter_get_basic (&reply_iter, &result); + + dbus_message_unref (reply); + + return result; +} + + + +struct LibHalChangeSetElement_s; + +typedef struct LibHalChangeSetElement_s LibHalChangeSetElement; + +struct LibHalChangeSetElement_s { + char *key; + int change_type; + union { + char *val_str; + dbus_int32_t val_int; + dbus_uint64_t val_uint64; + double val_double; + dbus_bool_t val_bool; + char **val_strlist; + } value; + LibHalChangeSetElement *next; + LibHalChangeSetElement *prev; +}; + +struct LibHalChangeSet_s { + char *udi; + LibHalChangeSetElement *head; + LibHalChangeSetElement *tail; +}; + +/** + * libhal_device_new_changeset: + * @udi: unique device identifier + * + * Request a new changeset object. Used for changing multiple properties at once. Useful when + * performance is critical and also for atomically updating several properties. + * + * Returns: A new changeset object or NULL on error + */ +LibHalChangeSet * +libhal_device_new_changeset (const char *udi) +{ + LibHalChangeSet *changeset; + + LIBHAL_CHECK_UDI_VALID(udi, NULL); + + changeset = calloc (1, sizeof (LibHalChangeSet)); + if (changeset == NULL) + goto out; + + changeset->udi = strdup (udi); + if (changeset->udi == NULL) { + free (changeset); + changeset = NULL; + goto out; + } + + changeset->head = NULL; + changeset->tail = NULL; + +out: + return changeset; +} + +static void +libhal_changeset_append (LibHalChangeSet *changeset, LibHalChangeSetElement *elem) +{ + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", (void) NULL ); + LIBHAL_CHECK_PARAM_VALID(elem, "*elem", (void) NULL); + + if (changeset->head == NULL) { + changeset->head = elem; + changeset->tail = elem; + elem->next = NULL; + elem->prev = NULL; + } else { + elem->prev = changeset->tail; + elem->next = NULL; + elem->prev->next = elem; + changeset->tail = elem; + } +} + + +/** + * libhal_changeset_set_property_string: + * @changeset: the changeset + * @key: key of property + * @value: the value to set + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_string (LibHalChangeSet *changeset, const char *key, const char *value) +{ + LibHalChangeSetElement *elem; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + LIBHAL_CHECK_PARAM_VALID(value, "*value", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + elem->change_type = LIBHAL_PROPERTY_TYPE_STRING; + elem->value.val_str = strdup (value); + if (elem->value.val_str == NULL) { + free (elem->key); + free (elem); + elem = NULL; + goto out; + } + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_changeset_set_property_int: + * @changeset: the changeset + * @key: key of property + * @value: the value to set + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_int (LibHalChangeSet *changeset, const char *key, dbus_int32_t value) +{ + LibHalChangeSetElement *elem; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + elem->change_type = LIBHAL_PROPERTY_TYPE_INT32; + elem->value.val_int = value; + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_changeset_set_property_uint64: + * @changeset: the changeset + * @key: key of property + * @value: the value to set + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_uint64 (LibHalChangeSet *changeset, const char *key, dbus_uint64_t value) +{ + LibHalChangeSetElement *elem; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + elem->change_type = LIBHAL_PROPERTY_TYPE_UINT64; + elem->value.val_uint64 = value; + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_changeset_set_property_double: + * @changeset: the changeset + * @key: key of property + * @value: the value to set + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_double (LibHalChangeSet *changeset, const char *key, double value) +{ + LibHalChangeSetElement *elem; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + elem->change_type = LIBHAL_PROPERTY_TYPE_DOUBLE; + elem->value.val_double = value; + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_changeset_set_property_bool: + * @changeset: the changeset + * @key: key of property + * @value: the value to set + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_bool (LibHalChangeSet *changeset, const char *key, dbus_bool_t value) +{ + LibHalChangeSetElement *elem; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + elem->change_type = LIBHAL_PROPERTY_TYPE_BOOLEAN; + elem->value.val_bool = value; + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_changeset_set_property_strlist: + * @changeset: the changeset + * @key: key of property + * @value: the value to set - NULL terminated array of strings + * + * Set a property. + * + * Returns: FALSE on OOM + */ +dbus_bool_t +libhal_changeset_set_property_strlist (LibHalChangeSet *changeset, const char *key, const char **value) +{ + LibHalChangeSetElement *elem; + char **value_copy; + int len; + int i, j; + + LIBHAL_CHECK_PARAM_VALID(changeset, "*changeset", FALSE); + LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE); + + elem = calloc (1, sizeof (LibHalChangeSetElement)); + if (elem == NULL) + goto out; + elem->key = strdup (key); + if (elem->key == NULL) { + free (elem); + elem = NULL; + goto out; + } + + for (i = 0; value[i] != NULL; i++) + ; + len = i; + + value_copy = calloc (len + 1, sizeof (char *)); + if (value_copy == NULL) { + free (elem->key); + free (elem); + elem = NULL; + goto out; + } + + for (i = 0; i < len; i++) { + value_copy[i] = strdup (value[i]); + if (value_copy[i] == NULL) { + for (j = 0; j < i; j++) { + free (value_copy[j]); + } + free (value_copy); + free (elem->key); + free (elem); + elem = NULL; + goto out; + } + } + value_copy[i] = NULL; + + elem->change_type = LIBHAL_PROPERTY_TYPE_STRLIST; + elem->value.val_strlist = value_copy; + + libhal_changeset_append (changeset, elem); +out: + return elem != NULL; +} + +/** + * libhal_device_commit_changeset: + * @ctx: the context for the connection to hald + * @changeset: the changeset to commit + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Commit a changeset to the daemon. + * + * Returns: True if the changeset was committed on the daemon side + */ +dbus_bool_t +libhal_device_commit_changeset (LibHalContext *ctx, LibHalChangeSet *changeset, DBusError *error) +{ + LibHalChangeSetElement *elem; + DBusMessage *message; + DBusMessage *reply; + DBusError _error; + DBusMessageIter iter; + DBusMessageIter sub; + DBusMessageIter sub2; + DBusMessageIter sub3; + DBusMessageIter sub4; + int i; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(changeset->udi, FALSE); + + if (changeset->head == NULL) { + return TRUE; + } + + message = dbus_message_new_method_call ("org.freedesktop.Hal", changeset->udi, + "org.freedesktop.Hal.Device", + "SetMultipleProperties"); + + if (message == NULL) { + fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_open_container (&iter, + DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &sub); + + for (elem = changeset->head; elem != NULL; elem = elem->next) { + dbus_message_iter_open_container (&sub, + DBUS_TYPE_DICT_ENTRY, + NULL, + &sub2); + dbus_message_iter_append_basic (&sub2, DBUS_TYPE_STRING, &(elem->key)); + + switch (elem->change_type) { + case LIBHAL_PROPERTY_TYPE_STRING: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub3); + dbus_message_iter_append_basic (&sub3, DBUS_TYPE_STRING, &(elem->value.val_str)); + dbus_message_iter_close_container (&sub2, &sub3); + break; + case LIBHAL_PROPERTY_TYPE_STRLIST: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, &sub3); + dbus_message_iter_open_container (&sub3, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &sub4); + for (i = 0; elem->value.val_strlist[i] != NULL; i++) { + dbus_message_iter_append_basic (&sub4, DBUS_TYPE_STRING, + &(elem->value.val_strlist[i])); + } + dbus_message_iter_close_container (&sub3, &sub4); + dbus_message_iter_close_container (&sub2, &sub3); + break; + case LIBHAL_PROPERTY_TYPE_INT32: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub3); + dbus_message_iter_append_basic (&sub3, DBUS_TYPE_INT32, &(elem->value.val_int)); + dbus_message_iter_close_container (&sub2, &sub3); + break; + case LIBHAL_PROPERTY_TYPE_UINT64: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT64_AS_STRING, &sub3); + dbus_message_iter_append_basic (&sub3, DBUS_TYPE_UINT64, &(elem->value.val_uint64)); + dbus_message_iter_close_container (&sub2, &sub3); + break; + case LIBHAL_PROPERTY_TYPE_DOUBLE: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub3); + dbus_message_iter_append_basic (&sub3, DBUS_TYPE_DOUBLE, &(elem->value.val_double)); + dbus_message_iter_close_container (&sub2, &sub3); + break; + case LIBHAL_PROPERTY_TYPE_BOOLEAN: + dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING,&sub3); + dbus_message_iter_append_basic (&sub3, DBUS_TYPE_BOOLEAN, &(elem->value.val_bool)); + dbus_message_iter_close_container (&sub2, &sub3); + break; + default: + fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type); + break; + } + dbus_message_iter_close_container (&sub, &sub2); + } + + dbus_message_iter_close_container (&iter, &sub); + + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + &_error); + + dbus_message_unref (message); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + fprintf (stderr, + "%s %d : %s\n", + __FILE__, __LINE__, error->message); + + return FALSE; + } + if (reply == NULL) { + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_free_changeset: + * @changeset: the changeset to free + * + * Free a changeset. + */ +void +libhal_device_free_changeset (LibHalChangeSet *changeset) +{ + LibHalChangeSetElement *elem; + LibHalChangeSetElement *elem2; + + for (elem = changeset->head; elem != NULL; elem = elem2) { + elem2 = elem->next; + + switch (elem->change_type) { + case LIBHAL_PROPERTY_TYPE_STRING: + free (elem->value.val_str); + break; + case LIBHAL_PROPERTY_TYPE_STRLIST: + libhal_free_string_array (elem->value.val_strlist); + break; + /* explicit fallthrough */ + case LIBHAL_PROPERTY_TYPE_INT32: + case LIBHAL_PROPERTY_TYPE_UINT64: + case LIBHAL_PROPERTY_TYPE_DOUBLE: + case LIBHAL_PROPERTY_TYPE_BOOLEAN: + break; + default: + fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type); + break; + } + free (elem->key); + free (elem); + } + + free (changeset->udi); + free (changeset); +} + + +/** + * libhal_device_acquire_interface_lock: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @interface: the intername name to lock + * @exclusive: whether the lock should be exclusive + * @error: pointer to an initialized dbus error object for returning errors + * + * Releases a lock on an interface for a specific device. + * + * Returns: TRUE iff the lock was acquired + **/ +dbus_bool_t +libhal_device_acquire_interface_lock (LibHalContext *ctx, + const char *udi, + const char *interface, + dbus_bool_t exclusive, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "AcquireInterfaceLock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &exclusive); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_release_interface_lock: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @interface: the intername name to unlock + * @error: pointer to an initialized dbus error object for returning errors + * + * Acquires a lock on an interface for a specific device. + * + * Returns: TRUE iff the lock was released. + **/ +dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx, + const char *udi, + const char *interface, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_UDI_VALID(udi, FALSE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "ReleaseInterfaceLock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_acquire_global_interface_lock: + * @ctx: the context for the connection to hald + * @interface: the intername name to lock + * @exclusive: whether the lock should be exclusive + * @error: pointer to an initialized dbus error object for returning errors + * + * Acquires a global lock on an interface. + * + * Returns: TRUE iff the lock was acquired + **/ +dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx, + const char *interface, + dbus_bool_t exclusive, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "AcquireGlobalInterfaceLock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &exclusive); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_release_global_interface_lock: + * @ctx: the context for the connection to hald + * @interface: the intername name to unlock + * @error: pointer to an initialized dbus error object for returning errors + * + * Releases a global lock on an interface. + * + * Returns: TRUE iff the lock was released + **/ +dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx, + const char *interface, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", FALSE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "ReleaseGlobalInterfaceLock"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return FALSE; + } + if (reply == NULL) + return FALSE; + + dbus_message_unref (reply); + return TRUE; +} + +/** + * libhal_device_is_caller_locked_out: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @interface: the intername name to check + * @caller: the caller to check for + * @error: pointer to an initialized dbus error object for returning errors + * + * Determines whether a given process on the system message bus is + * locked out from an interface on a specific device. Only HAL helpers + * are privileged to use this method. + * + * Returns: Whether the given caller is locked out + **/ +dbus_bool_t +libhal_device_is_caller_locked_out (LibHalContext *ctx, + const char *udi, + const char *interface, + const char *caller, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + DBusMessageIter reply_iter; + dbus_bool_t value; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, TRUE); + LIBHAL_CHECK_UDI_VALID(udi, TRUE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", TRUE); + LIBHAL_CHECK_PARAM_VALID(caller, "*caller", TRUE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "IsCallerLockedOut"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return TRUE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &caller); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return TRUE; + } + if (reply == NULL) + return TRUE; + + /* now analyze reply */ + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + return TRUE; + } + dbus_message_iter_get_basic (&reply_iter, &value); + dbus_message_unref (reply); + return value; +} + + +/** + * libhal_ctx_set_global_interface_lock_acquired: + * @ctx: the context for the connection to hald + * @callback: the callback + * + * Set the callback for when a global interface lock is acquired. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_global_interface_lock_acquired (LibHalContext *ctx, LibHalGlobalInterfaceLockAcquired callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE); + + ctx->global_interface_lock_acquired = callback; + return TRUE; +} + +/** + * libhal_ctx_set_global_interface_lock_released: + * @ctx: the context for the connection to hald + * @callback: the callback + * + * Set the callback for when a global interface lock is released. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_global_interface_lock_released (LibHalContext *ctx, LibHalGlobalInterfaceLockReleased callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE); + + ctx->global_interface_lock_released = callback; + return TRUE; +} + + +/** + * libhal_ctx_set_interface_lock_acquired: + * @ctx: the context for the connection to hald + * @callback: the callback + * + * Set the callback for when an interface lock is acquired. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_interface_lock_acquired (LibHalContext *ctx, LibHalInterfaceLockAcquired callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE); + + ctx->interface_lock_acquired = callback; + return TRUE; +} + +/** + * libhal_ctx_set_interface_lock_released: + * @ctx: the context for the connection to hald + * @callback: the callback + * + * Set the callback for when an interface lock is released. + * + * Returns: TRUE if callback was successfully set, FALSE otherwise + */ +dbus_bool_t +libhal_ctx_set_interface_lock_released (LibHalContext *ctx, LibHalInterfaceLockReleased callback) +{ + LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE); + + ctx->interface_lock_released = callback; + return TRUE; +} + + + +/** + * libhal_device_is_locked_by_others: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @interface: the intername name to check + * @error: pointer to an initialized dbus error object for returning errors or NULL + * + * Determines whether a determines other processes than the caller holds a lock on the given device. + * + * Returns: If another process is holding a lock on the device + **/ +dbus_bool_t +libhal_device_is_locked_by_others (LibHalContext *ctx, + const char *udi, + const char *interface, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + DBusMessageIter reply_iter; + dbus_bool_t value; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, TRUE); + LIBHAL_CHECK_UDI_VALID(udi, TRUE); + LIBHAL_CHECK_PARAM_VALID(interface, "*interface", TRUE); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "IsLockedByOthers"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return TRUE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return TRUE; + } + if (reply == NULL) + return TRUE; + + /* now analyze reply */ + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) { + dbus_message_unref (reply); + return TRUE; + } + dbus_message_iter_get_basic (&reply_iter, &value); + dbus_message_unref (reply); + return value; +} + +/** + * libhal_device_is_caller_privileged: + * @ctx: the context for the connection to hald + * @udi: the Unique id of device + * @action: the action to check for + * @caller: the caller to check for + * @error: pointer to an initialized dbus error object for returning errors + * + * Determines if a given caller have a given privilege on a given + * device. Will always error out if HAL is not built with PolicyKit + * support. + * + * Returns: The textual reply from PolicyKit. See the #PolicyKitResult + * enumeration in the PolicyKit documentation for details. The caller + * is responsible for freeing this string with the function + * libhal_free_string(). + **/ +char* +libhal_device_is_caller_privileged (LibHalContext *ctx, + const char *udi, + const char *action, + const char *caller, + DBusError *error) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusMessage *reply; + DBusMessageIter reply_iter; + char *dbus_str; + char *value; + + LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL); + LIBHAL_CHECK_UDI_VALID(udi, NULL); + LIBHAL_CHECK_PARAM_VALID(action, "*action", NULL); + LIBHAL_CHECK_PARAM_VALID(caller, "*caller", NULL); + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device", + "IsCallerPrivileged"); + + if (message == NULL) { + fprintf (stderr, + "%s %d : Couldn't allocate D-BUS message\n", + __FILE__, __LINE__); + return NULL; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &action); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &caller); + + reply = dbus_connection_send_with_reply_and_block (ctx->connection, + message, -1, + error); + + dbus_message_unref (message); + + if (error != NULL && dbus_error_is_set (error)) { + return NULL; + } + if (reply == NULL) + return NULL; + + /* now analyze reply */ + dbus_message_iter_init (reply, &reply_iter); + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_STRING) { + dbus_message_unref (reply); + return NULL; + } + dbus_message_iter_get_basic (&reply_iter, &dbus_str); + value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL); + if (value == NULL) { + fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__); + } + dbus_message_unref (reply); + return value; +} + +/** + * libhal_get_all_devices_with_properties: + * @out_num_devices: Return location for number of devices + * @out_udi: Return location for array of of udi's. Caller should free this with libhal_free_string_array() when done with it. + * @out_properties: Return location for array of #LibHalPropertySet objects. Caller should free each one of them with libhal_free_property_set() when done with it + * @error: Return location for error + * + * Get all devices in the hal database as well as all properties for each device. + * + * Return: %TRUE if success; %FALSE and @error will be set. + **/ +dbus_bool_t libhal_get_all_devices_with_properties (LibHalContext *ctx, + int *out_num_devices, + char ***out_udi, + LibHalPropertySet ***out_properties, + DBusError *error) +{ + + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter_array, reply_iter; + DBusError _error; + char **udi_array; + char **_udi_array; + LibHalPropertySet **prop_array; + LibHalPropertySet **_prop_array; + size_t count; + unsigned int n; + + LIBHAL_CHECK_LIBHALCONTEXT (ctx, FALSE); + LIBHAL_CHECK_PARAM_VALID (out_num_devices, "*out_num_devices",FALSE); + LIBHAL_CHECK_PARAM_VALID (out_udi, "***out_udi", FALSE); + LIBHAL_CHECK_PARAM_VALID (out_properties, "***out_properties", FALSE); + + *out_num_devices = 0; + *out_udi = NULL; + *out_properties = NULL; + + count = 0; + udi_array = NULL; + prop_array = NULL; + + message = dbus_message_new_method_call ("org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager", + "GetAllDevicesWithProperties"); + if (message == NULL) { + fprintf (stderr, "%s %d : Could not allocate D-BUS message\n", __FILE__, __LINE__); + goto fail; + } + + dbus_error_init (&_error); + reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &_error); + + dbus_move_error (&_error, error); + if (error != NULL && dbus_error_is_set (error)) { + dbus_message_unref (message); + goto fail; + } + if (reply == NULL) { + dbus_message_unref (message); + goto fail; + } + + /* now analyze reply */ + dbus_message_iter_init (reply, &reply_iter); + + if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) { + fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__); + goto fail; + } + + dbus_message_iter_recurse (&reply_iter, &iter_array); + + #define _BLOCK_SIZE 32 + + udi_array = (char **) malloc (sizeof (char*) * _BLOCK_SIZE); + if (udi_array == NULL) + goto fail; + + prop_array = (LibHalPropertySet **) malloc (sizeof (void*) * _BLOCK_SIZE); + if (prop_array == NULL) + goto fail; + + while (dbus_message_iter_get_arg_type (&iter_array) == DBUS_TYPE_STRUCT) { + DBusMessageIter iter_struct; + const char *value; + LibHalPropertySet *pset; + char *udi; + + if ((count % _BLOCK_SIZE) == 0 && count > 0) { + _udi_array = (char **) realloc (udi_array, sizeof (char*) * (count + _BLOCK_SIZE)); + _prop_array = (LibHalPropertySet **) realloc (prop_array, sizeof (void*) * (count+_BLOCK_SIZE)); + if (_udi_array == NULL || _prop_array == NULL) + goto fail; + udi_array = _udi_array; + prop_array = _prop_array; + } + + dbus_message_iter_recurse (&iter_array, &iter_struct); + + dbus_message_iter_get_basic (&iter_struct, &value); + udi = strdup (value); + if (udi == NULL) + goto fail; + + dbus_message_iter_next(&iter_struct); + + pset = get_property_set (&iter_struct); + + udi_array[count] = udi; + prop_array[count] = pset; + count++; + + dbus_message_iter_next (&iter_array); + } + + if ((count % _BLOCK_SIZE) == 0 && count > 0) { + _udi_array = (char **) realloc (udi_array, sizeof (char*) * (count + _BLOCK_SIZE)); + _prop_array = (LibHalPropertySet **) realloc (prop_array, sizeof (void*) * (count + _BLOCK_SIZE)); + if (_udi_array == NULL || _prop_array == NULL) + goto fail; + udi_array = _udi_array; + prop_array = _prop_array; + } + udi_array[count] = NULL; + prop_array[count] = NULL; + + *out_num_devices = count; + *out_udi = udi_array; + *out_properties = prop_array; + + dbus_message_unref (reply); + dbus_message_unref (message); + + return TRUE; + +fail: + if (udi_array != NULL) { + for (n = 0; n < count; n++) { + free (udi_array[n]); + } + free (udi_array); + } + + if (prop_array != NULL) { + for (n = 0; n < count; n++) { + free (prop_array[n]); + } + free (prop_array); + } + + return FALSE; +} diff --git a/deps/libhal.h b/deps/libhal.h new file mode 100644 index 0000000..23c7d13 --- /dev/null +++ b/deps/libhal.h @@ -0,0 +1,793 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * libhal.h : HAL daemon C convenience library headers + * + * Copyright (C) 2003 David Zeuthen, + * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifndef LIBHAL_H +#define LIBHAL_H + +#ifndef DBUS_API_SUBJECT_TO_CHANGE +#define DBUS_API_SUBJECT_TO_CHANGE +#endif + +#include + +#if defined(__cplusplus) +extern "C" { +#if 0 +} /* shut up emacs indenting */ +#endif +#endif + +#if defined(__GNUC__) +#define LIBHAL_DEPRECATED __attribute__ ((deprecated)) +#else +#define LIBHAL_DEPRECATED +#endif + + +/** + * LIBHAL_LIBHAL_FREE_DBUS_ERROR: + * @_dbus_error_: the DBusError + * + * Handy macro for checking whether a DBusError is set and free the error if + * the error is set. + */ +#define LIBHAL_FREE_DBUS_ERROR(_dbus_error_) \ + do { \ + if (dbus_error_is_set(_dbus_error_)) \ + dbus_error_free (_dbus_error_); \ + } while (0) + + +/** + * LIBHAL_CHECK_LIBHALCONTEXT: + * @_ctx_: the context + * @_ret_: what to use for return value if context is invalid + * + * Handy macro for checking whether a context is valid. + */ +#define LIBHAL_CHECK_LIBHALCONTEXT(_ctx_, _ret_) \ + do { \ + if (_ctx_ == NULL) { \ + fprintf (stderr, \ + "%s %d : LibHalContext *ctx is NULL\n", \ + __FILE__, __LINE__); \ + return _ret_; \ + } \ + } while(0) + +/** + * LibHalPropertyType: + * + * Possible types for properties on hal device objects + */ +typedef enum { + /** Used to report error condition */ + LIBHAL_PROPERTY_TYPE_INVALID = DBUS_TYPE_INVALID, + + /** Type for 32-bit signed integer property */ + LIBHAL_PROPERTY_TYPE_INT32 = DBUS_TYPE_INT32, + + /** Type for 64-bit unsigned integer property */ + LIBHAL_PROPERTY_TYPE_UINT64 = DBUS_TYPE_UINT64, + + /** Type for double precision floating point property */ + LIBHAL_PROPERTY_TYPE_DOUBLE = DBUS_TYPE_DOUBLE, + + /** Type for boolean property */ + LIBHAL_PROPERTY_TYPE_BOOLEAN = DBUS_TYPE_BOOLEAN, + + /** Type for UTF-8 string property */ + LIBHAL_PROPERTY_TYPE_STRING = DBUS_TYPE_STRING, + + /** Type for list of UTF-8 strings property */ + LIBHAL_PROPERTY_TYPE_STRLIST = ((int) (DBUS_TYPE_STRING<<8)+('l')) +} LibHalPropertyType; + + +typedef struct LibHalContext_s LibHalContext; +typedef struct LibHalProperty_s LibHalProperty; +typedef struct LibHalPropertySet_s LibHalPropertySet; + + +/** + * LibHalIntegrateDBusIntoMainLoop: + * @ctx: context for connection to hald + * @dbus_connection: DBus connection to use in ctx + * + * Type for function in application code that integrates a + * DBusConnection object into its own mainloop. + */ +typedef void (*LibHalIntegrateDBusIntoMainLoop) (LibHalContext *ctx, + DBusConnection *dbus_connection); + +/** + * LibHalDeviceAdded: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * + * Type for callback when a device is added. + */ +typedef void (*LibHalDeviceAdded) (LibHalContext *ctx, + const char *udi); + +/** + * LibHalDeviceRemoved: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * + * Type for callback when a device is removed. + */ +typedef void (*LibHalDeviceRemoved) (LibHalContext *ctx, + const char *udi); + +/** + * LibHalDeviceNewCapability: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @capability: capability of the device + * + * Type for callback when a device gains a new capability. + * + */ +typedef void (*LibHalDeviceNewCapability) (LibHalContext *ctx, + const char *udi, + const char *capability); + +/** + * LibHalDeviceLostCapability: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @capability: capability of the device + * + * Type for callback when a device loses a capability. + * + */ +typedef void (*LibHalDeviceLostCapability) (LibHalContext *ctx, + const char *udi, + const char *capability); + +/** + * LibHalDevicePropertyModified: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @key: name of the property that has changed + * @is_removed: whether or not property was removed + * @is_added: whether or not property was added + * + * Type for callback when a property of a device changes. + */ +typedef void (*LibHalDevicePropertyModified) (LibHalContext *ctx, + const char *udi, + const char *key, + dbus_bool_t is_removed, + dbus_bool_t is_added); + +/** + * LibHalDeviceCondition: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @condition_name: name of the condition, e.g. ProcessorOverheating. Consult the HAL spec for details + * @condition_detail: detail of condition + * + * Type for callback when a non-continuous condition occurs on a device. + */ +typedef void (*LibHalDeviceCondition) (LibHalContext *ctx, + const char *udi, + const char *condition_name, + const char *condition_detail); + +/** + * LibHalGlobalInterfaceLockAcquired: + * @ctx: context for connection to hald + * @interface_name: the name of the interface + * @lock_owner: what service acquired the lock + * @num_locks: number of locks on the interface + * + * Type for callback when someone acquires a global lock. + */ +typedef void (*LibHalGlobalInterfaceLockAcquired) (LibHalContext *ctx, + const char *interface_name, + const char *lock_owner, + int num_locks); + +/** + * LibHalGlobalInterfaceLockReleased: + * @ctx: context for connection to hald + * @interface_name: the name of the interface + * @lock_owner: what service released the lock + * @num_locks: number of locks on the interface + * + * Type for callback when someone releases a global lock. + */ +typedef void (*LibHalGlobalInterfaceLockReleased) (LibHalContext *ctx, + const char *interface_name, + const char *lock_owner, + int num_locks); + +/** + * LibHalInterfaceLockAcquired: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @interface_name: the name of the interface + * @lock_owner: what service acquired the lock + * @num_locks: number of locks on the interface + * + * Type for callback when someone acquires a lock on a device. + */ +typedef void (*LibHalInterfaceLockAcquired) (LibHalContext *ctx, + const char *udi, + const char *interface_name, + const char *lock_owner, + int num_locks); + +/** + * LibHalInterfaceLockReleased: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @interface_name: the name of the interface + * @lock_owner: what service released the lock + * @num_locks: number of locks on the interface + * + * Type for callback when someone acquires a lock on a device. + */ +typedef void (*LibHalInterfaceLockReleased) (LibHalContext *ctx, + const char *udi, + const char *interface_name, + const char *lock_owner, + int num_locks); + +/** + * LibHalSingletonDeviceAdded: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @properties: the device's properties + * + * Type for callback for addon singletons when a device is added + */ +typedef void (*LibHalSingletonDeviceAdded) (LibHalContext *ctx, + const char *udi, + const LibHalPropertySet *properties); + +/** + * LibHalSingletonDeviceRemoved: + * @ctx: context for connection to hald + * @udi: the Unique Device Id + * @properties: the device's properties + * + * Type for callback for addon singletons when a device is added + */ +typedef void (*LibHalSingletonDeviceRemoved) (LibHalContext *ctx, + const char *udi, + const LibHalPropertySet *properties); + + + +/* Create a new context for a connection with hald */ +LibHalContext *libhal_ctx_new (void); + +/* Enable or disable caching */ +dbus_bool_t libhal_ctx_set_cache (LibHalContext *ctx, dbus_bool_t use_cache); + +/* Set DBus connection to use to talk to hald. */ +dbus_bool_t libhal_ctx_set_dbus_connection (LibHalContext *ctx, DBusConnection *conn); + +/* Get DBus connection to use to talk to hald. */ +DBusConnection *libhal_ctx_get_dbus_connection (LibHalContext *ctx); + +/* Set user data for the context */ +dbus_bool_t libhal_ctx_set_user_data (LibHalContext *ctx, void *user_data); + +/* Get user data for the context */ +void* libhal_ctx_get_user_data (LibHalContext *ctx); + +/* Set the callback for when a device is added */ +dbus_bool_t libhal_ctx_set_device_added (LibHalContext *ctx, LibHalDeviceAdded callback); + +/* Set the callback for when a device is removed */ +dbus_bool_t libhal_ctx_set_device_removed (LibHalContext *ctx, LibHalDeviceRemoved callback); + +/* Set the callback for when a device gains a new capability */ +dbus_bool_t libhal_ctx_set_device_new_capability (LibHalContext *ctx, LibHalDeviceNewCapability callback); + +/* Set the callback for when a device loses a capability */ +dbus_bool_t libhal_ctx_set_device_lost_capability (LibHalContext *ctx, LibHalDeviceLostCapability callback); + +/* Set the callback for when a property is modified on a device */ +dbus_bool_t libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibHalDevicePropertyModified callback); + +/* Set the callback for when a device emits a condition */ +dbus_bool_t libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback); + +/* Set the callback for when a global interface lock is acquired */ +dbus_bool_t libhal_ctx_set_global_interface_lock_acquired (LibHalContext *ctx, LibHalGlobalInterfaceLockAcquired callback); + +/* Set the callback for when a global interface lock is released */ +dbus_bool_t libhal_ctx_set_global_interface_lock_released (LibHalContext *ctx, LibHalGlobalInterfaceLockReleased callback); + +/* Set the callback for when an interface lock is acquired */ +dbus_bool_t libhal_ctx_set_interface_lock_acquired (LibHalContext *ctx, LibHalInterfaceLockAcquired callback); + +/* Set the callback for when an interface lock is released */ +dbus_bool_t libhal_ctx_set_interface_lock_released (LibHalContext *ctx, LibHalInterfaceLockReleased callback); + +/* Set the callback for addon singleton device added */ +dbus_bool_t libhal_ctx_set_singleton_device_added (LibHalContext *ctx, LibHalSingletonDeviceAdded callback); + +/* Set the callback for addon singleton device removed*/ +dbus_bool_t libhal_ctx_set_singleton_device_removed (LibHalContext *ctx, LibHalSingletonDeviceRemoved callback); + +/* Initialize the connection to hald */ +dbus_bool_t libhal_ctx_init (LibHalContext *ctx, DBusError *error); + +/* Shut down a connection to hald */ +dbus_bool_t libhal_ctx_shutdown (LibHalContext *ctx, DBusError *error); + +/* Free a LibHalContext resource */ +dbus_bool_t libhal_ctx_free (LibHalContext *ctx); + +/* Create an already initialized connection to hald */ +LibHalContext *libhal_ctx_init_direct (DBusError *error); + +/* Get all devices in the Global Device List (GDL). */ +char **libhal_get_all_devices (LibHalContext *ctx, int *num_devices, DBusError *error); + +/* Determine if a device exists. */ +dbus_bool_t libhal_device_exists (LibHalContext *ctx, const char *udi, DBusError *error); + +/* Print a device to stdout; useful for debugging. */ +dbus_bool_t libhal_device_print (LibHalContext *ctx, const char *udi, DBusError *error); + +/* Determine if a property on a device exists. */ +dbus_bool_t libhal_device_property_exists (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type string. */ +char *libhal_device_get_property_string (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type signed integer. */ +dbus_int32_t libhal_device_get_property_int (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type unsigned integer. */ +dbus_uint64_t libhal_device_get_property_uint64 (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type double. */ +double libhal_device_get_property_double (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type bool. */ +dbus_bool_t libhal_device_get_property_bool (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Get the value of a property of type string list. */ +char **libhal_device_get_property_strlist (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Set a property of type string. */ +dbus_bool_t libhal_device_set_property_string (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error); + +/* Set a property of type signed integer. */ +dbus_bool_t libhal_device_set_property_int (LibHalContext *ctx, + const char *udi, + const char *key, + dbus_int32_t value, + DBusError *error); + +/* Set a property of type unsigned integer. */ +dbus_bool_t libhal_device_set_property_uint64 (LibHalContext *ctx, + const char *udi, + const char *key, + dbus_uint64_t value, + DBusError *error); + +/* Set a property of type double. */ +dbus_bool_t libhal_device_set_property_double (LibHalContext *ctx, + const char *udi, + const char *key, + double value, + DBusError *error); + +/* Set a property of type bool. */ +dbus_bool_t libhal_device_set_property_bool (LibHalContext *ctx, + const char *udi, + const char *key, + dbus_bool_t value, + DBusError *error); + +/* Append to a property of type strlist. */ +dbus_bool_t libhal_device_property_strlist_append (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error); + +/* Prepend to a property of type strlist. */ +dbus_bool_t libhal_device_property_strlist_prepend (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error); + +/* Remove a specified string from a property of type strlist. */ +dbus_bool_t libhal_device_property_strlist_remove_index (LibHalContext *ctx, + const char *udi, + const char *key, + unsigned int idx, + DBusError *error); + +/* Remove a specified string from a property of type strlist. */ +dbus_bool_t libhal_device_property_strlist_remove (LibHalContext *ctx, + const char *udi, + const char *key, + const char *value, + DBusError *error); + +/* Remove a property. */ +dbus_bool_t libhal_device_remove_property (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +/* Query a property type of a device. */ +LibHalPropertyType libhal_device_get_property_type (LibHalContext *ctx, + const char *udi, + const char *key, + DBusError *error); + +struct LibHalChangeSet_s; +typedef struct LibHalChangeSet_s LibHalChangeSet; + +LibHalChangeSet *libhal_device_new_changeset (const char *udi); + +dbus_bool_t libhal_changeset_set_property_string (LibHalChangeSet *changeset, + const char *key, + const char *value); + +dbus_bool_t libhal_changeset_set_property_int (LibHalChangeSet *changeset, + const char *key, + dbus_int32_t value); + +dbus_bool_t libhal_changeset_set_property_uint64 (LibHalChangeSet *changeset, + const char *key, + dbus_uint64_t value); + +dbus_bool_t libhal_changeset_set_property_double (LibHalChangeSet *changeset, + const char *key, + double value); + +dbus_bool_t libhal_changeset_set_property_bool (LibHalChangeSet *changeset, + const char *key, + dbus_bool_t value); + +dbus_bool_t libhal_changeset_set_property_strlist (LibHalChangeSet *changeset, + const char *key, + const char **value); + +dbus_bool_t libhal_device_commit_changeset (LibHalContext *ctx, + LibHalChangeSet *changeset, + DBusError *error); + +void libhal_device_free_changeset (LibHalChangeSet *changeset); + + +/* Retrieve all the properties on a device. */ +LibHalPropertySet *libhal_device_get_all_properties (LibHalContext *ctx, + const char *udi, + DBusError *error); + +/* Get all devices and their properties */ +dbus_bool_t libhal_get_all_devices_with_properties (LibHalContext *ctx, + int *out_num_devices, + char ***out_udi, + LibHalPropertySet ***out_properties, + DBusError *error); + +/* sort all properties according to property name */ +void libhal_property_set_sort (LibHalPropertySet *set); + +/* Free a property set earlier obtained with libhal_device_get_all_properties(). */ +void libhal_free_property_set (LibHalPropertySet *set); + +/* Get the number of properties in a property set. */ +unsigned int libhal_property_set_get_num_elems (LibHalPropertySet *set); + +/* Get type of property. */ +LibHalPropertyType libhal_ps_get_type (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type string. */ +const char *libhal_ps_get_string (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type signed integer. */ +dbus_int32_t libhal_ps_get_int32 (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type unsigned integer. */ +dbus_uint64_t libhal_ps_get_uint64 (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type double. */ +double libhal_ps_get_double (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type bool. */ +dbus_bool_t libhal_ps_get_bool (const LibHalPropertySet *set, const char *key); + +/* Get the value of a property of type string list. */ +const char * const *libhal_ps_get_strlist (const LibHalPropertySet *set, const char *key); + + +/** + * LibHalPropertySetIterator: + * + * Iterator for inspecting all properties. Do not access any members; + * use the libhal_psi_* family of functions instead. + */ +struct LibHalPropertySetIterator_s { + LibHalPropertySet *set; /**< Property set we are iterating over */ + unsigned int idx; /**< Index into current element */ + LibHalProperty *cur_prop; /**< Current property being visited */ + void *reservered0; /**< Reserved for future use */ + void *reservered1; /**< Reserved for future use */ +}; + + +typedef struct LibHalPropertySetIterator_s LibHalPropertySetIterator; + +/* Initialize a property set iterator. */ +void libhal_psi_init (LibHalPropertySetIterator *iter, LibHalPropertySet *set); + +/* Determine whether there are more properties to iterate over */ +dbus_bool_t libhal_psi_has_more (LibHalPropertySetIterator *iter); + +/* Advance iterator to next property. */ +void libhal_psi_next (LibHalPropertySetIterator *iter); + +/* Get type of property. */ +LibHalPropertyType libhal_psi_get_type (LibHalPropertySetIterator *iter); + +/* Get the key of a property. */ +char *libhal_psi_get_key (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type string. */ +char *libhal_psi_get_string (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type signed integer. */ +dbus_int32_t libhal_psi_get_int (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type unsigned integer. */ +dbus_uint64_t libhal_psi_get_uint64 (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type double. */ +double libhal_psi_get_double (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type bool. */ +dbus_bool_t libhal_psi_get_bool (LibHalPropertySetIterator *iter); + +/* Get the value of a property of type string list. */ +char **libhal_psi_get_strlist (LibHalPropertySetIterator *iter); + +/* Get the length of an array of strings */ +unsigned int libhal_string_array_length (char **str_array); + +/* Frees a NULL-terminated array of strings. If passed NULL, does nothing. */ +void libhal_free_string_array (char **str_array); + +/* Frees a nul-terminated string */ +void libhal_free_string (char *str); + +/* Create a new device object which will be hidden from applications + * until the CommitToGdl(), ie. libhal_device_commit_to_gdl(), method is called. + */ +char *libhal_new_device (LibHalContext *ctx, DBusError *error); + +/* When a hidden device has been built using the NewDevice method, ie. + * libhal_new_device(), and the org.freedesktop.Hal.Device interface + * this function will commit it to the global device list. + */ +dbus_bool_t libhal_device_commit_to_gdl (LibHalContext *ctx, + const char *temp_udi, + const char *udi, + DBusError *error); + +/* This method can be invoked when a device is removed. The HAL daemon + * will shut down the device. Note that the device may still be in the device + * list if the Persistent property is set to true. + */ +dbus_bool_t libhal_remove_device (LibHalContext *ctx, + const char *udi, + DBusError *error); + +/* Merge properties from one device to another. */ +dbus_bool_t libhal_merge_properties (LibHalContext *ctx, + const char *target_udi, + const char *source_udi, + DBusError *error); + +/* Check a set of properties for two devices matches. */ +dbus_bool_t libhal_device_matches (LibHalContext *ctx, + const char *udi1, + const char *udi2, + const char *property_namespace, + DBusError *error); + +/* Find a device in the GDL where a single string property matches a + * given value. + */ +char **libhal_manager_find_device_string_match (LibHalContext *ctx, + const char *key, + const char *value, + int *num_devices, + DBusError *error); + +/* Assign a capability to a device. */ +dbus_bool_t libhal_device_add_capability (LibHalContext *ctx, + const char *udi, + const char *capability, + DBusError *error); + +/* Check if a device has a capability. The result is undefined if the + * device doesn't exist. + */ +dbus_bool_t libhal_device_query_capability (LibHalContext *ctx, + const char *udi, + const char *capability, + DBusError *error); + +/* Find devices with a given capability. */ +char **libhal_find_device_by_capability (LibHalContext *ctx, + const char *capability, + int *num_devices, + DBusError *error); + +/* Watch all devices, ie. the device_property_changed callback is + * invoked when the properties on any device changes. + */ +dbus_bool_t libhal_device_property_watch_all (LibHalContext *ctx, + DBusError *error); + +/* Remove a watch of all devices. + */ +dbus_bool_t libhal_device_property_remove_watch_all (LibHalContext *ctx, + DBusError *error); + +/* Add a watch on a device, so the device_property_changed callback is + * invoked when the properties on the given device changes. + */ +dbus_bool_t libhal_device_add_property_watch (LibHalContext *ctx, + const char *udi, + DBusError *error); + +/* Remove a watch on a device */ +dbus_bool_t libhal_device_remove_property_watch (LibHalContext *ctx, + const char *udi, + DBusError *error); + +/* Take an advisory lock on the device. */ +dbus_bool_t libhal_device_lock (LibHalContext *ctx, + const char *udi, + const char *reason_to_lock, + char **reason_why_locked, + DBusError *error); + +/* Release an advisory lock on the device. */ +dbus_bool_t libhal_device_unlock (LibHalContext *ctx, + const char *udi, + DBusError *error); + +dbus_bool_t libhal_device_rescan (LibHalContext *ctx, + const char *udi, + DBusError *error); + +dbus_bool_t libhal_device_reprobe (LibHalContext *ctx, + const char *udi, + DBusError *error); + +/* Emit a condition from a device (for hald helpers only) */ +dbus_bool_t libhal_device_emit_condition (LibHalContext *ctx, + const char *udi, + const char *condition_name, + const char *condition_details, + DBusError *error); + +/* Claim an interface for a device (for hald helpers only) */ +dbus_bool_t libhal_device_claim_interface (LibHalContext *ctx, + const char *udi, + const char *interface_name, + const char *introspection_xml, + DBusError *error); + +/* hald waits for all addons to call this function before announcing the addon (for hald helpers only) */ +dbus_bool_t libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error); + +dbus_bool_t libhal_device_singleton_addon_is_ready (LibHalContext *ctx, const char *command_line, DBusError *error); + +/* Take a mandatory lock on an interface on a device. */ +dbus_bool_t libhal_device_acquire_interface_lock (LibHalContext *ctx, + const char *udi, + const char *interface, + dbus_bool_t exclusive, + DBusError *error); + +/* Release a mandatory lock on an interface on a device. */ +dbus_bool_t libhal_device_release_interface_lock (LibHalContext *ctx, + const char *udi, + const char *interface, + DBusError *error); + +/* Take a mandatory lock on an interface (the lock affects all devices the caller have access to). */ +dbus_bool_t libhal_acquire_global_interface_lock (LibHalContext *ctx, + const char *interface, + dbus_bool_t exclusive, + DBusError *error); + +/* Release a mandatory lock on an interface (affects all devices the caller have access to). */ +dbus_bool_t libhal_release_global_interface_lock (LibHalContext *ctx, + const char *interface, + DBusError *error); + +/* Determine if a given caller is locked out of a given interface on a given device */ +dbus_bool_t libhal_device_is_caller_locked_out (LibHalContext *ctx, + const char *udi, + const char *interface, + const char *caller, + DBusError *error); + +/* Determines whether a determines other processes than the caller holds a lock on the given device. */ +dbus_bool_t libhal_device_is_locked_by_others (LibHalContext *ctx, + const char *udi, + const char *interface, + DBusError *error); + +/* Determine if a given caller is privileged (requires HAL to be built with PolicyKit support) */ +char* libhal_device_is_caller_privileged (LibHalContext *ctx, + const char *udi, + const char *action, + const char *caller, + DBusError *error); + + +#if defined(__cplusplus) +} +#endif + +#endif /* LIBHAL_H */ diff --git a/deps/uthash.h b/deps/uthash.h new file mode 100644 index 0000000..fb79ca2 --- /dev/null +++ b/deps/uthash.h @@ -0,0 +1,605 @@ +/* +Copyright (c) 2003-2006, Troy Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include /* memcmp,strlen */ + +#ifndef UTHASH_H +#define UTHASH_H + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_bkt_malloc(sz) malloc(sz) /* malloc fcn for UT_hash_bucket's */ +#define uthash_bkt_free(ptr) free(ptr) /* free fcn for UT_hash_bucket's */ +#define uthash_tbl_malloc(sz) malloc(sz) /* malloc fcn for UT_hash_table */ +#define uthash_tbl_free(ptr) free(ptr) /* free fcn for UT_hash_table */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +#define HASH_FIND(hh,head,keyptr,keylen_in,out) \ +do { \ + out=head; \ + if (head) { \ + (head)->hh.tbl->key = (char*)(keyptr); \ + (head)->hh.tbl->keylen = keylen_in; \ + HASH_FCN((head)->hh.tbl->key,(head)->hh.tbl->keylen, \ + (head)->hh.tbl->num_buckets,(head)->hh.tbl->bkt, \ + (head)->hh.tbl->i, (head)->hh.tbl->j,(head)->hh.tbl->k); \ + HASH_FIND_IN_BKT(hh, (head)->hh.tbl->buckets[ (head)->hh.tbl->bkt], \ + keyptr,keylen_in,out); \ + } \ +} while (0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + add->hh.next = NULL; \ + add->hh.key = (char*)keyptr; \ + add->hh.keylen = keylen_in; \ + add->hh.elmt = add; \ + if (!(head)) { \ + head = add; \ + (head)->hh.prev = NULL; \ + (head)->hh.tbl = (UT_hash_table*)uthash_tbl_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + (head)->hh.tbl->name = #head; \ + (head)->hh.tbl->tail = &(add->hh); \ + (head)->hh.tbl->noexpand = 0; \ + (head)->hh.tbl->hash_q = 1<<16; \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->num_items = 0; \ + (head)->hh.tbl->hho = ((long)(&add->hh) - (long)(add)); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_bkt_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + } else { \ + (head)->hh.tbl->tail->next = add; \ + add->hh.prev = (head)->hh.tbl->tail->elmt; \ + (head)->hh.tbl->tail = &(add->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + add->hh.tbl = (head)->hh.tbl; \ + (head)->hh.tbl->key = (char*)keyptr; \ + (head)->hh.tbl->keylen = keylen_in; \ + HASH_FCN((head)->hh.tbl->key,(head)->hh.tbl->keylen, \ + (head)->hh.tbl->num_buckets, \ + (head)->hh.tbl->bkt, \ + (head)->hh.tbl->i, (head)->hh.tbl->j, (head)->hh.tbl->k ); \ + HASH_ADD_TO_BKT(hh,(head)->hh.tbl->buckets[(head)->hh.tbl->bkt],add); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(head); \ +} while(0) + +#define HASH_DELETE(hh,head,delptr) \ +do { \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_bkt_free((head)->hh.tbl->buckets ); \ + uthash_tbl_free((head)->hh.tbl); \ + head = NULL; \ + } else { \ + if ((delptr) == (head)->hh.tbl->tail->elmt) { \ + (head)->hh.tbl->tail = (void*)(((long)((delptr)->hh.prev)) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)(((long)((delptr)->hh.prev)) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + head = (delptr)->hh.next; \ + } \ + if ((delptr)->hh.next) { \ + ((UT_hash_handle*)(((long)((delptr)->hh.next)) + \ + (head)->hh.tbl->hho))->prev = (delptr)->hh.prev; \ + } \ + (head)->hh.tbl->key = (char*)((delptr)->hh.key); \ + (head)->hh.tbl->keylen = (delptr)->hh.keylen; \ + HASH_FCN((head)->hh.tbl->key,(head)->hh.tbl->keylen, \ + (head)->hh.tbl->num_buckets,(head)->hh.tbl->bkt, \ + (head)->hh.tbl->i,(head)->hh.tbl->j,(head)->hh.tbl->k ); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[(head)->hh.tbl->bkt], \ + delptr); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + * This function misuses fields in UT_hash_table for its bookkeeping variables. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(head) \ +do { \ + if (head) { \ + (head)->hh.tbl->keylen = 0; /* item counter */ \ + for( (head)->hh.tbl->bkt_i = 0; \ + (head)->hh.tbl->bkt_i < (head)->hh.tbl->num_buckets; \ + (head)->hh.tbl->bkt_i++) \ + { \ + (head)->hh.tbl->bkt_ideal = 0; /* bkt item counter */ \ + (head)->hh.tbl->hh = \ + (head)->hh.tbl->buckets[(head)->hh.tbl->bkt_i].hh_head; \ + (head)->hh.tbl->key = NULL; /* hh_prev */ \ + while ((head)->hh.tbl->hh) { \ + if ((head)->hh.tbl->key != \ + (char*)((head)->hh.tbl->hh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %x, actual %x\n", \ + (head)->hh.tbl->hh->hh_prev, \ + (head)->hh.tbl->key ); \ + } \ + (head)->hh.tbl->bkt_ideal++; \ + (head)->hh.tbl->key = (char*)((head)->hh.tbl->hh); \ + (head)->hh.tbl->hh = (head)->hh.tbl->hh->hh_next; \ + } \ + (head)->hh.tbl->keylen += (head)->hh.tbl->bkt_ideal; \ + if ((head)->hh.tbl->buckets[(head)->hh.tbl->bkt_i].count \ + != (head)->hh.tbl->bkt_ideal) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[(head)->hh.tbl->bkt_i].count, \ + (head)->hh.tbl->bkt_ideal); \ + } \ + } \ + if ((head)->hh.tbl->keylen != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, (head)->hh.tbl->keylen ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + (head)->hh.tbl->keylen = 0; /* item counter */ \ + (head)->hh.tbl->key = NULL; /* app prev */ \ + (head)->hh.tbl->hh = &(head)->hh; \ + while ((head)->hh.tbl->hh) { \ + (head)->hh.tbl->keylen++; \ + if ((head)->hh.tbl->key !=(char*)((head)->hh.tbl->hh->prev)) {\ + HASH_OOPS("invalid prev %x, actual %x\n", \ + (head)->hh.tbl->hh->prev, \ + (head)->hh.tbl->key ); \ + } \ + (head)->hh.tbl->key = (head)->hh.tbl->hh->elmt; \ + (head)->hh.tbl->hh = ( (head)->hh.tbl->hh->next ? \ + (UT_hash_handle*)((long)((head)->hh.tbl->hh->next) + \ + (head)->hh.tbl->hho) \ + : NULL ); \ + } \ + if ((head)->hh.tbl->keylen != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, (head)->hh.tbl->keylen ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ + (head)->hh.tbl->keylen = fieldlen; \ + write(HASH_EMIT_KEYS, &((head)->hh.tbl->keylen), sizeof(int)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkins unless specified e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 0; \ + while (keylen--) bkt = (bkt * 33) + *key++; \ + bkt &= (num_bkts-1); + + +/* SAX/FNV/OAT/JEN/JSW hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/hashing.html (thanks Julienne Walker) */ +#define HASH_SAX(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 0; \ + for(i=0; i < keylen; i++) \ + bkt ^= (bkt << 5) + (bkt >> 2) + key[i]; \ + bkt &= (num_bkts-1); + +#define HASH_FNV(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 2166136261UL; \ + for(i=0; i < keylen; i++) \ + bkt = (bkt * 16777619) ^ key[i]; \ + bkt &= (num_bkts-1); + +#define HASH_OAT(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 0; \ + for(i=0; i < keylen; i++) { \ + bkt += key[i]; \ + bkt += (bkt << 10); \ + bkt ^= (bkt >> 6); \ + } \ + bkt += (bkt << 3); \ + bkt ^= (bkt >> 11); \ + bkt += (bkt << 15); \ + bkt &= (num_bkts-1); + +#define HASH_JEN_MIX(a,b,c) \ +{ \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} + +#define HASH_JEN(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 0xfeedbeef; \ + i = j = 0x9e3779b9; \ + k = keylen; \ + while (k >= 12) { \ + i += (key[0] + ( (unsigned)key[1] << 8 ) \ + + ( (unsigned)key[2] << 16 ) \ + + ( (unsigned)key[3] << 24 ) ); \ + j += (key[4] + ( (unsigned)key[5] << 8 ) \ + + ( (unsigned)key[6] << 16 ) \ + + ( (unsigned)key[7] << 24 ) ); \ + bkt += (key[8] + ( (unsigned)key[9] << 8 ) \ + + ( (unsigned)key[10] << 16 ) \ + + ( (unsigned)key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(i, j, bkt); \ + \ + key += 12; \ + k -= 12; \ + } \ + bkt += keylen; \ + switch ( k ) { \ + case 11: bkt += ( (unsigned)key[10] << 24 ); \ + case 10: bkt += ( (unsigned)key[9] << 16 ); \ + case 9: bkt += ( (unsigned)key[8] << 8 ); \ + case 8: j += ( (unsigned)key[7] << 24 ); \ + case 7: j += ( (unsigned)key[6] << 16 ); \ + case 6: j += ( (unsigned)key[5] << 8 ); \ + case 5: j += key[4]; \ + case 4: i += ( (unsigned)key[3] << 24 ); \ + case 3: i += ( (unsigned)key[2] << 16 ); \ + case 2: i += ( (unsigned)key[1] << 8 ); \ + case 1: i += key[0]; \ + } \ + HASH_JEN_MIX(i, j, bkt); \ + bkt &= (num_bkts-1); + +#define HASH_JSW(key,keylen,num_bkts,bkt,i,j,k) \ + bkt = 16777551; \ + for(i=0; i < keylen; i++) { \ + bkt = (bkt << 1 | bkt >> 31) ^ \ + *(int*)((long)( \ + "\xe9\x81\x51\xe4\x84\x9d\x32\xd9\x2d\xda\xca\x94\xa7\x85\x1e" \ + "\x28\xfe\xa3\x18\x60\x28\x45\xa6\x48\x67\xdb\xd5\xa2\x91\x4d" \ + "\x1a\x2f\x97\x37\x82\xd8\xe9\x1c\xb7\x7b\x3c\xa5\x4c\x23\x2" \ + "\x42\x85\x20\x78\x6c\x6\x67\x6f\xa5\xcb\x53\x8c\xe1\x1f\x12" \ + "\x66\xcb\xa0\xbe\x47\x59\x8\x20\xd5\x31\xd9\xdc\xcc\x27\xc3" \ + "\x4d\x8\x9f\xb3\x50\x8\x90\x4f\x1f\x20\x60\xb8\xe2\x7b\x63" \ + "\x49\xc0\x64\xc7\xaf\xc9\x81\x9c\x5f\x7d\x45\xc5\xe4\xe4\x86" \ + "\xaf\x1a\x15\x6c\x9b\xc3\x7c\xc5\x88\x2b\xf3\xd9\x72\x76\x47" \ + "\x56\xe6\x8c\xd1\x6c\x94\x41\x59\x4d\xe2\xd7\x44\x9a\x55\x5e" \ + "\xee\x9d\x7c\x8f\x21\x57\x10\x77\xf7\x4b\xd8\x7e\xc0\x4d\xba" \ + "\x1f\x96\x2a\x60\x13\xae\xab\x58\x70\xe5\x23\x62\x2b\x63\xb6" \ + "\x42\x8e\x8f\x57\xf2\xfa\x47\x37\x91\xac\x11\x3d\x9a\x85\x73" \ + "\x9e\x39\x65\xc8\xd4\x5b\xaa\x35\x72\x5f\x40\x31\x9a\xb0\xdd" \ + "\xa9\x2c\x16\xa3\x32\xef\xcb\x8c\x80\x33\x60\xd\x85\xce\x22" \ + "\x8c\x28\x6\x7f\xff\xf6\x8a\x5f\x21\x8e\xf2\xd0\xd9\x63\x66" \ + "\x22\xe8\xe6\x3\x39\xfd\x10\x69\xce\x6c\xc4\xde\xf3\x87\x56" \ + "\xc8\x4a\x31\x51\x58\xc5\x62\x30\x8e\xd\xd5\x2f\x7c\x24\xca" \ + "\xd1\x12\x1b\x3a\x3e\x95\x99\xa\x7\xc1\x83\xd0\x4f\x97\x8c" \ + "\xf1\xb0\x9c\xd8\xb9\x72\xd7\x3e\x6b\x66\x83\x8e\xe9\x86\xad" \ + "\xfa\xc2\xe\x4\xb5\x7b\x5d\x0\xbc\x47\xbe\x4\x69\xfa\xd1" \ + "\x29\x5c\x77\x38\xfc\x88\xeb\xd5\xe1\x17\x54\xf6\xe5\xb3\xae" \ + "\xc7\x14\xb6\x4b\xa6\x42\x4b\xa3\xdf\xa5\xcf\xdb\xad\xcd\x2c" \ + "\xa3\x3\x13\xc0\x42\x5d\x6e\x3c\xfe\xd8\xeb\xa7\x96\x47\x2b" \ + "\x61\xb3\x70\xc9\x6d\xff\x1a\x82\x65\xdc\x92\x4b\x1a\x52\x75" \ + "\xa5\x61\x55\x2b\xe\x7\xde\x1e\x71\xc5\x12\x34\x59\x4f\x19" \ + "\x2\x9\xb6\x5\xe6\x7b\xad\xb6\x92\xfb\x84\x32\xf1\x45\x6c" \ + "\xec\x1a\xcb\x39\x32\x2\x47\x51\xd6\xc8\x9d\xd0\xb1\xdb\xa8" \ + "\x90\x4c\x65\x5a\x77\x1f\xca\x74\x8e\x3b\xce\x76\x55\x8b\x78" \ + "\x3c\xf3\x19\x8f\xe1\xc3\xa9\x8a\xc8\xf3\x14\x30\x4e\x77\xe9" \ + "\xd5\x6a\xcb\x96\x2f\x31\x35\xff\x6b\x10\x92\xf7\xc4\x33\xb8" \ + "\x76\x35\x6\xf\x82\x1c\xfa\x1f\x92\x47\xa1\xf9\x7e\xe5\x51" \ + "\xee\x63\xaa\x9a\x38\xa3\xa1\x86\xbf\xf0\xe8\x29\xe1\x19\x83" \ + "\xff\x36\x3c\x26\x15\x89\x36\x22\x93\x41\x3e\x63\x36\x34\x4c" \ + "\xda\x18\xd4\x18\xd8\xc8\x8a\x10\x1f\x14\x4c\x7f\x79\xfc\x46" \ + "\xbb\xc8\x24\x51\xc7\xe4\xfb\xc0\x78\xb1\xe9\xac\xf1\x3d\x55" \ + "\x51\x9c\x8\xf0\xa6\x3\xcb\x91\xc6\xf4\xe2\xd4\xe5\x18\x61" \ + "\xfc\x8f\x8a\xce\x89\x33\xcd\xf\x7d\x50\xa0\x7d\x3f\xac\x49" \ + "\xe1\x71\x92\xc7\x8d\xc0\xd0\x6e\xe4\xf7\xcd\xc1\x47\x9f\x99" \ + "\xd5\x7\x20\xad\x64\xdb\xab\x44\xd4\x8\xc6\x9a\xa4\xa7\x7c" \ + "\x9b\x13\xe4\x9c\x88\xec\xc4\xcb\xe1\x3f\x5\x5\xf\xd\x3a" \ + "\x75\xed\xfa\xc0\x23\x34\x74\xfd\xca\x1c\x74\x77\x29\xc8\xb6" \ + "\xe2\xbb\xa1\xa\x2e\xae\x65\x3e\xcb\xf5\x5e\xe0\x29\x4c\xfa" \ + "\xab\x35\xea\x7\x9f\xb3\x3b\x9c\x4e\x86\xe8\x5b\x76\x11\xf1" \ + "\xbf\x7f\x73\x34\x71\x9\x2d\x2a\x60\x8f\x14\x12\xba\x26\x84" \ + "\xb9\x94\xa9\x59\x38\x25\xfd\x77\xc3\xe5\x86\xc4\x3\xda\x32" \ + "\x30\xd8\x84\x81\x83\x14\x8c\x24\xee\x51\xa9\x92\x61\xb2\xeb" \ + "\xce\xac\x34\xc1\xad\x24\x74\xce\xf9\xce\x5c\xfd\x45\x69\x1d" \ + "\xc6\xc2\xaf\x7c\x8d\x5\x52\xb5\x88\x2f\x9f\xee\x6b\x5f\xbd" \ + "\xfe\x22\x6\x47\xa2\xc8\x25\x37\x67\x44\x4c\xe\xfe\x7e\x5a" \ + "\x36\x7f\x18\x83\x8f\x82\x87\x3b\xbf\xb8\xd2\x37\xff\x52\x60" \ + "\xb5\xf3\xd\x20\x80\xcc\xb2\x7a\xdd\xc2\x94\xbc\xe3\xb1\x87" \ + "\x3e\x49\x57\xcc\xe9\x5a\xea\xb4\xe\xdf\xa6\x8f\x70\x60\x32" \ + "\xb\x7d\x74\xf5\x46\xb6\x93\xc2\x5\x92\x72\xfc\xd9\xd2\xe5" \ + "\x90\x36\x2a\xd4\xf9\x50\x33\x52\xa5\xcc\xcf\x14\x9e\xdc\x4f" \ + "\xb7\x7d\xcf\x25\xdb\xc0\x46\xdb\xea\xe\x27\xc8\x18\x40\x39" \ + "\xbd\xec\x48\xa3\xfa\x87\xa3\x18\x68\xfc\x7a\x44\xa8\xc5\x8c" \ + "\x45\x81\x70\x72\x14\x70\xf9\x40\xc8\xe7\x41\xcb\xde\xd\x4e" \ + "\x35\x4d\xcd\xe2\x40\xa3\x2e\xbb\xb7\x50\x6c\x26\xb8\xbe\x2a" \ + "\x36\x8e\x23\xb\xa\xfe\xed\xa\xe7\xa0\x16\x73\xad\x24\x51" \ + "\x7f\xda\x9d\xd7\x9f\x18\xe6\xa8\xe4\x98\xbc\x62\x77\x55\x60" \ + "\x88\x16\x25\xbf\x95\xad\xea\xe1\x87\x18\x35\x9e\x7c\x51\xee" \ + "\xc0\x80\x8b\xb8\x37\xfd\x95\xfe\x87\x15\xf4\x97\xd5\x61\x4f" \ + "\x97\xfa\xaf\x48\xd\x5b\x84\x2d\xdb\x15\xf2\xb4\x17\x4f\x41" \ + "\x31\x58\x32\x93\xc1\x52\x34\xa6\x17\xd\x56\x5\xee\xfb\xfb" \ + "\x2d\x69\x14\xbe\x24\x94\x8\xb0\xfc\x9f\x2\x95\x88\x7d\xd6" \ + "\xe7\xa4\x5b\xbb\xf2\x7d\xd8\xa5\xd2\x7c\x9\x62\x22\x5\x53" \ + "\xd0\x67\xeb\x68\xfc\x82\x80\xf\xc9\x73\x76\x36\xb8\x13\x9f" \ + "\xb1\xf1\xee\x61\x12\xe7\x5d\x75\x65\xb8\x84\x17\xb\x7b\x28" \ + "\x4c\xb7\xda\xbb" ) \ + + ( (unsigned char)key[i] * sizeof(int) )); \ + } \ + bkt &= (num_bkts-1); + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(hh,head,keyptr,keylen_in,out) \ +out = (head.hh_head) ? (head.hh_head->elmt) : NULL; \ +while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + out= (out->hh.hh_next) ? (out->hh.hh_next->elmt) : NULL; \ +} + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(hh,head,add) \ + head.count++; \ + add->hh.hh_next = head.hh_head; \ + add->hh.hh_prev = NULL; \ + if (head.hh_head) head.hh_head->hh_prev = &add->hh; \ + head.hh_head=&add->hh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && add->hh.tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS(add->hh.tbl) \ + } + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,delptr) \ + (head).count--; \ + if ((head).hh_head->elmt == delptr) { \ + (head).hh_head = delptr->hh.hh_next; \ + } \ + if (delptr->hh.hh_prev) { \ + delptr->hh.hh_prev->hh_next = delptr->hh.hh_next; \ + } \ + if (delptr->hh.hh_next) { \ + delptr->hh.hh_next->hh_prev = delptr->hh.hh_prev; \ + } + +#define HASH_EXPAND_BUCKETS(tbl) \ + tbl->new_buckets = (UT_hash_bucket*)uthash_bkt_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!tbl->new_buckets) { uthash_fatal( "out of memory"); } \ + memset(tbl->new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->bkt_ideal= (tbl->num_items / tbl->num_buckets*2) + \ + ((tbl->num_items % (tbl->num_buckets*2)) ? 1 : 0);\ + tbl->sum_of_deltas = 0; \ + for(tbl->bkt_i = 0; tbl->bkt_i < tbl->num_buckets; tbl->bkt_i++) \ + { \ + tbl->hh = tbl->buckets[ tbl->bkt_i ].hh_head; \ + while (tbl->hh) { \ + tbl->hh_nxt = tbl->hh->hh_next; \ + tbl->key = tbl->hh->key; \ + tbl->keylen = tbl->hh->keylen; \ + HASH_FCN(tbl->key,tbl->keylen,tbl->num_buckets*2,tbl->bkt,\ + tbl->i,tbl->j,tbl->k); \ + tbl->newbkt = &(tbl->new_buckets[ tbl->bkt ]); \ + if (++(tbl->newbkt->count) > tbl->bkt_ideal) { \ + tbl->sum_of_deltas++; \ + tbl->newbkt->expand_mult = tbl->newbkt->count / \ + tbl->bkt_ideal; \ + } \ + tbl->hh->hh_prev = NULL; \ + tbl->hh->hh_next = tbl->newbkt->hh_head; \ + if (tbl->newbkt->hh_head) tbl->newbkt->hh_head->hh_prev = \ + tbl->hh; \ + tbl->newbkt->hh_head = tbl->hh; \ + tbl->hh = tbl->hh_nxt; \ + } \ + } \ + tbl->num_buckets *= 2; \ + uthash_bkt_free( tbl->buckets ); \ + tbl->buckets = tbl->new_buckets; \ + tbl->new_hash_q = (1<<16) - ((tbl->sum_of_deltas << 16) / tbl->num_items); \ + if (tbl->hash_q < (1<<15) && tbl->new_hash_q < (1<<15)) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + tbl->hash_q = tbl->new_hash_q; \ + uthash_expand_fyi(tbl); + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +#define HASH_SORT(head,cmpfcn) \ + if (head) { \ + (head)->hh.tbl->insize = 1; \ + (head)->hh.tbl->looping = 1; \ + (head)->hh.tbl->list = &((head)->hh); \ + while ((head)->hh.tbl->looping) { \ + (head)->hh.tbl->p = (head)->hh.tbl->list; \ + (head)->hh.tbl->list = NULL; \ + (head)->hh.tbl->tale = NULL; \ + (head)->hh.tbl->nmerges = 0; \ + while ((head)->hh.tbl->p) { \ + (head)->hh.tbl->nmerges++; \ + (head)->hh.tbl->q = (head)->hh.tbl->p; \ + (head)->hh.tbl->psize = 0; \ + for ( (head)->hh.tbl->i = 0; \ + (head)->hh.tbl->i < (head)->hh.tbl->insize; \ + (head)->hh.tbl->i++ ) { \ + (head)->hh.tbl->psize++; \ + (head)->hh.tbl->q = (((head)->hh.tbl->q->next) ? \ + ((void*)(((long)((head)->hh.tbl->q->next)) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! ((head)->hh.tbl->q) ) break; \ + } \ + (head)->hh.tbl->qsize = (head)->hh.tbl->insize; \ + while (((head)->hh.tbl->psize > 0) || \ + (((head)->hh.tbl->qsize > 0) && (head)->hh.tbl->q )) { \ + if ((head)->hh.tbl->psize == 0) { \ + (head)->hh.tbl->e = (head)->hh.tbl->q; \ + (head)->hh.tbl->q = (((head)->hh.tbl->q->next) ? \ + ((void*)(((long)((head)->hh.tbl->q->next)) + \ + (head)->hh.tbl->hho)) : NULL); \ + (head)->hh.tbl->qsize--; \ + } else if ( ((head)->hh.tbl->qsize == 0) || \ + !((head)->hh.tbl->q) ) { \ + (head)->hh.tbl->e = (head)->hh.tbl->p; \ + (head)->hh.tbl->p = (((head)->hh.tbl->p->next) ? \ + ((void*)(((long)((head)->hh.tbl->p->next)) + \ + (head)->hh.tbl->hho)) : NULL); \ + (head)->hh.tbl->psize--; \ + } else if (( \ + cmpfcn((head)->hh.tbl->p->elmt,(head)->hh.tbl->q->elmt)) \ + <= 0) { \ + (head)->hh.tbl->e = (head)->hh.tbl->p; \ + (head)->hh.tbl->p = (((head)->hh.tbl->p->next) ? \ + ((void*)(((long)((head)->hh.tbl->p->next)) + \ + (head)->hh.tbl->hho)) : NULL); \ + (head)->hh.tbl->psize--; \ + } else { \ + (head)->hh.tbl->e = (head)->hh.tbl->q; \ + (head)->hh.tbl->q = (((head)->hh.tbl->q->next) ? \ + ((void*)(((long)((head)->hh.tbl->q->next)) + \ + (head)->hh.tbl->hho)) : NULL); \ + (head)->hh.tbl->qsize--; \ + } \ + if ( (head)->hh.tbl->tale ) { \ + (head)->hh.tbl->tale->next = (((head)->hh.tbl->e) ? \ + ((head)->hh.tbl->e->elmt) : NULL); \ + } else { \ + (head)->hh.tbl->list = (head)->hh.tbl->e; \ + } \ + (head)->hh.tbl->e->prev = (((head)->hh.tbl->tale) ? \ + ((head)->hh.tbl->tale->elmt) : NULL); \ + (head)->hh.tbl->tale = (head)->hh.tbl->e; \ + } \ + (head)->hh.tbl->p = (head)->hh.tbl->q; \ + } \ + (head)->hh.tbl->tale->next = NULL; \ + if ( (head)->hh.tbl->nmerges <= 1 ) { \ + (head)->hh.tbl->looping=0; \ + (head)->hh.tbl->tail = (head)->hh.tbl->tale; \ + (head) = (head)->hh.tbl->list->elmt; \ + } \ + (head)->hh.tbl->insize *= 2; \ + } \ + HASH_FSCK(head); \ + } + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + unsigned expand_mult; +} UT_hash_bucket; + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets; + unsigned num_items; + int noexpand; /* when set, inhibits expansion of buckets for this hash */ + int hash_q; /* measures the evenness of the items among buckets (0-1) */ + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + char *name; /* macro-stringified name of list head, used by libut */ + int hho; + /* scratch */ + unsigned bkt; + char *key; + size_t keylen; + int i,j,k; + /* scratch for bucket expansion */ + UT_hash_bucket *new_buckets, *newbkt; + struct UT_hash_handle *hh, *hh_nxt; + unsigned bkt_i, bkt_ideal, sum_of_deltas; + int new_hash_q; + /* scratch for sort */ + int looping,nmerges,insize,psize,qsize; + struct UT_hash_handle *p, *q, *e, *list, *tale; + +} UT_hash_table; + + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *elmt; /* ptr to enclosing element */ + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + size_t keylen; /* enclosing struct's key len */ +} UT_hash_handle; + +#endif /* UTHASH_H */